From 32f4c5a36ef2aa3f53e2d29f53a0b011c5c73571 Mon Sep 17 00:00:00 2001
From: Andrea Gianarda <andrea.gianarda@belledonne-communications.com>
Date: Wed, 28 Jun 2023 17:21:16 +0200
Subject: [PATCH] Implement conference broadcast feature.

It allows the organizer to choose whether participant are speakers or
listener in a conference.
For scheduled conferences, if a participant is not in the list of
allowed participants, he/she will have its role set to listener (i.e
audio stream will be sendonly from the server side and recvonly on the
client side).

Non scheduled conferences will have the organizer and participants to be
speakers.

The dynamic change of a participant role is not supported yet once the
conference is started but it may be done prior to it by updating the
conference informations
---
 coreapi/bellesip_sal/sal_sdp.c                |     1 -
 coreapi/callbacks.c                           |    13 +-
 coreapi/conference.cpp                        |    83 +-
 coreapi/conference.h                          |    23 +-
 coreapi/linphoneconference.c                  |     1 +
 coreapi/local_conference.cpp                  |   131 +-
 coreapi/local_conference.h                    |     9 +-
 coreapi/remote_conference.cpp                 |    39 +-
 coreapi/remote_conference.h                   |     2 +-
 coreapi/tester_utils.cpp                      |     2 +-
 coreapi/tester_utils.h                        |     3 +-
 include/CMakeLists.txt                        |     2 +
 include/linphone/api/c-api.h                  |     1 +
 include/linphone/api/c-conference-info.h      |    58 +-
 include/linphone/api/c-factory.h              |     9 +
 include/linphone/api/c-participant-info.h     |   129 +
 include/linphone/api/c-participant.h          |     7 +
 include/linphone/api/c-types.h                |     8 +
 include/linphone/enums/participant-enums.h    |    35 +
 include/linphone/misc.h                       |     2 +
 include/linphone/utils/utils.h                |     5 +-
 src/CMakeLists.txt                            |     4 +
 src/alert/alert.h                             |    11 +-
 src/c-wrapper/api/c-account-params.cpp        |     1 +
 src/c-wrapper/api/c-conference-info.cpp       |    63 +-
 src/c-wrapper/api/c-factory.cpp               |     7 +
 src/c-wrapper/api/c-participant-info.cpp      |    79 +
 src/c-wrapper/api/c-participant.cpp           |    16 +
 src/c-wrapper/c-wrapper.h                     |    79 -
 src/c-wrapper/list-holder.h                   |   105 +
 src/call/call.cpp                             |    12 +-
 src/chat/chat-room/client-group-chat-room.cpp |    17 +-
 src/chat/chat-room/server-group-chat-room.cpp |    17 +-
 src/chat/ics/ics.cpp                          |    29 +-
 src/chat/ics/ics.h                            |     3 +
 src/conference/conference-info.cpp            |   183 +-
 src/conference/conference-info.h              |    49 +-
 src/conference/conference-interface.h         |     8 +-
 src/conference/conference-scheduler.cpp       |   105 +-
 src/conference/conference-scheduler.h         |     1 +
 src/conference/conference.cpp                 |    27 +-
 src/conference/conference.h                   |     4 +-
 .../local-conference-event-handler.cpp        |     4 +
 .../remote-conference-event-handler.cpp       |    28 +-
 src/conference/participant-device.cpp         |   143 +-
 src/conference/participant-device.h           |    13 +-
 src/conference/participant-info.cpp           |   152 +
 src/conference/participant-info.h             |    77 +
 src/conference/participant.cpp                |    43 +-
 src/conference/participant.h                  |    25 +-
 src/conference/session/media-session-p.h      |     7 +
 src/conference/session/media-session.cpp      |   178 +-
 src/core/core-chat-room.cpp                   |     1 -
 src/core/core.cpp                             |     4 +-
 src/db/main-db-p.h                            |     5 +-
 src/db/main-db.cpp                            |    68 +-
 src/factory/factory.cpp                       |     5 +
 src/factory/factory.h                         |     3 +-
 src/sal/sal_media_description.cpp             |   164 +-
 src/utils/utils.cpp                           |    32 +-
 tester/audio_video_conference_tester.c        |   825 +-
 tester/group_chat_tester.c                    |     7 +-
 tester/ics-tester.cpp                         |    27 +-
 tester/local_conference_edition_tester.cpp    |   430 +-
 tester/local_conference_tester.cpp            | 17485 ++++++++++++++++
 tester/local_conference_tester_functions.cpp  |   395 +-
 tester/local_conference_tester_functions.h    |    36 +-
 tester/local_ice_conference_tester.cpp        |    10 +-
 tester/local_inpromptu_conference_tester.cpp  |   103 +-
 tester/local_scheduled_conference_tester.cpp  |   122 +-
 tester/shared_tester_functions.cpp            |    41 +-
 tester/utils-tester.cpp                       |     1 +
 72 files changed, 20474 insertions(+), 1343 deletions(-)
 create mode 100644 include/linphone/api/c-participant-info.h
 create mode 100644 include/linphone/enums/participant-enums.h
 create mode 100644 src/c-wrapper/api/c-participant-info.cpp
 create mode 100644 src/c-wrapper/list-holder.h
 create mode 100644 src/conference/participant-info.cpp
 create mode 100644 src/conference/participant-info.h
 create mode 100644 tester/local_conference_tester.cpp

diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c
index 0fef5bcbb9..97f59a3e47 100644
--- a/coreapi/bellesip_sal/sal_sdp.c
+++ b/coreapi/bellesip_sal/sal_sdp.c
@@ -17,7 +17,6 @@
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
-#include "c-wrapper/internal/c-tools.h"
 #include "sal_impl.h"
 
 inline OrtpRtcpXrStatSummaryFlag operator|=(OrtpRtcpXrStatSummaryFlag a, OrtpRtcpXrStatSummaryFlag b) {
diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c
index 94994bf714..c2518aa389 100644
--- a/coreapi/callbacks.c
+++ b/coreapi/callbacks.c
@@ -49,6 +49,7 @@
 #include "chat/chat-room/client-group-chat-room-p.h"
 #include "chat/chat-room/server-group-chat-room-p.h"
 #endif
+#include "conference/participant-info.h"
 #include "conference/participant.h"
 #include "conference/session/call-session-p.h"
 #include "conference/session/call-session.h"
@@ -125,8 +126,8 @@ static void call_received(SalCallOp *h) {
 						return;
 					}
 					std::shared_ptr<Address> fromOp = Address::create(h->getFrom());
-					list<std::shared_ptr<Address>> identAddresses = Utils::parseResourceLists(h->getRemoteBody());
-					if (identAddresses.size() != 1) {
+					const auto participantList = Utils::parseResourceLists(h->getRemoteBody());
+					if (participantList.size() != 1) {
 						h->decline(SalReasonNotAcceptable);
 						h->release();
 						return;
@@ -134,10 +135,10 @@ static void call_received(SalCallOp *h) {
 					const char *endToEndEncryptedStr =
 					    sal_custom_header_find(h->getRecvCustomHeaders(), "End-To-End-Encrypted");
 					bool encrypted = endToEndEncryptedStr && strcmp(endToEndEncryptedStr, "true") == 0;
-
+					const auto &participant = (*participantList.begin())->getAddress();
 					std::shared_ptr<Address> confAddr =
 					    L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb->findOneToOneConferenceChatRoomAddress(
-					        fromOp, identAddresses.front(), encrypted);
+					        fromOp, participant, encrypted);
 					if (confAddr && confAddr->isValid()) {
 						shared_ptr<AbstractChatRoom> chatRoom =
 						    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ConferenceId(confAddr, confAddr));
@@ -164,9 +165,9 @@ static void call_received(SalCallOp *h) {
 
 			const char *oneToOneChatRoomStr = sal_custom_header_find(h->getRecvCustomHeaders(), "One-To-One-Chat-Room");
 			if (oneToOneChatRoomStr && (strcmp(oneToOneChatRoomStr, "true") == 0)) {
-				list<std::shared_ptr<Address>> participantList = Utils::parseResourceLists(h->getRemoteBody());
+				const auto participantList = Utils::parseResourceLists(h->getRemoteBody());
 				if (participantList.size() == 1) {
-					std::shared_ptr<Address> participant = participantList.front();
+					const auto &participant = (*participantList.begin())->getAddress();
 					shared_ptr<AbstractChatRoom> chatRoom =
 					    L_GET_PRIVATE_FROM_C_OBJECT(lc)->findExhumableOneToOneChatRoom(to, participant,
 					                                                                   endToEndEncrypted == "true");
diff --git a/coreapi/conference.cpp b/coreapi/conference.cpp
index 39d38a2d0f..947a6b9a75 100644
--- a/coreapi/conference.cpp
+++ b/coreapi/conference.cpp
@@ -21,9 +21,11 @@
 #include "conference.h"
 #include "call/call.h"
 #include "conference/notify-conference-listener.h"
+#include "conference/participant-info.h"
 #include "conference/participant.h"
 #include "conference/session/media-session-p.h"
 #include "core/core.h"
+#include "factory/factory.h"
 #include "linphone/api/c-call.h"
 #include "linphone/core.h"
 
@@ -212,6 +214,40 @@ bool Conference::isConferenceStarted() const {
 	return conferenceStarted;
 }
 
+void Conference::fillParticipantAttributes(std::shared_ptr<Participant> &p) {
+	const auto &pAddress = p->getAddress();
+	const auto participantInfo =
+	    std::find_if(mInvitedParticipants.cbegin(), mInvitedParticipants.cend(),
+	                 [&pAddress](const auto &info) { return pAddress->weakEqual(*info->getAddress()); });
+	const auto conferenceAddressStr =
+	    (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<address-not-defined>"));
+
+	if (participantInfo == mInvitedParticipants.cend()) {
+		if (mInvitedParticipants.empty()) {
+			// It is a conference created on the fly, therefore all participants are speakers
+			p->setRole(Participant::Role::Speaker);
+			lInfo() << "Conference " << this << " (address " << conferenceAddressStr
+			        << ") has been created on the fly, either by inviting addresses or by merging existing calls "
+			           "therefoe participant "
+			        << *pAddress << " is given the role of " << p->getRole();
+		} else {
+			lInfo() << "Unable to find participant " << *pAddress
+			        << " in the list of invited participants. Assuming its role to be " << p->getRole()
+			        << " in conference " << this << " (address " << conferenceAddressStr << ")";
+		}
+	} else {
+		const auto &role = (*participantInfo)->getRole();
+		if (role == Participant::Role::Unknown) {
+			p->setRole(Participant::Role::Speaker);
+			lInfo() << "No role was given to participant " << *pAddress << " when the conference " << this
+			        << " (address " << conferenceAddressStr << ") was created. Assuming its role to be "
+			        << p->getRole();
+		} else {
+			p->setRole(role);
+		}
+	}
+}
+
 bool Conference::addParticipant(const std::shared_ptr<Address> &participantAddress) {
 	bool success = LinphonePrivate::Conference::addParticipant(participantAddress);
 
@@ -222,6 +258,7 @@ bool Conference::addParticipant(const std::shared_ptr<Address> &participantAddre
 		        << conferenceAddressStr;
 		time_t creationTime = time(nullptr);
 		std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(participantAddress);
+		fillParticipantAttributes(p);
 		notifyParticipantAdded(creationTime, false, p);
 	} else {
 		lError() << "Unable to add participant with address " << *participantAddress << " to conference "
@@ -239,6 +276,7 @@ bool Conference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call) {
 	if (p == nullptr) {
 		auto session = call->getActiveSession();
 		p = Participant::create(this, remoteAddress);
+		fillParticipantAttributes(p);
 		p->setFocus(false);
 		std::shared_ptr<Address> toAddr;
 		if (session) {
@@ -444,27 +482,6 @@ void Conference::setState(LinphonePrivate::ConferenceInterface::State state) {
 	}
 }
 
-std::shared_ptr<ConferenceInfo>
-Conference::createConferenceInfoWithOrganizer(const std::shared_ptr<Address> &organizer) const {
-
-	std::list<std::shared_ptr<Address>> participantAddresses;
-	if (!invitedAddresses.empty()) {
-		participantAddresses = invitedAddresses;
-	}
-
-	// Add participants that are not part of the invitees'list
-	for (const auto &p : getParticipants()) {
-		const auto &pAddress = p->getAddress();
-		auto pIt = std::find_if(participantAddresses.begin(), participantAddresses.end(),
-		                        [&pAddress](const auto &address) { return (pAddress->weakEqual(*address)); });
-		if (pIt == participantAddresses.end()) {
-			participantAddresses.push_back(pAddress);
-		}
-	}
-
-	return createConferenceInfoWithCustomParticipantList(organizer, participantAddresses);
-}
-
 void Conference::notifyStateChanged(LinphonePrivate::ConferenceInterface::State state) {
 	// Call listeners
 	LinphonePrivate::Conference::notifyStateChanged(state);
@@ -515,6 +532,30 @@ void Conference::transferStateChanged(LinphoneCore *lc, LinphoneCall *transfered
 	}
 }
 
+std::list<std::shared_ptr<Address>> Conference::getInvitedAddresses() const {
+	list<std::shared_ptr<Address>> addresses;
+	for (auto &participant : mInvitedParticipants) {
+		addresses.push_back(participant->getAddress());
+	}
+	return addresses;
+}
+
+ConferenceInfo::participant_list_t Conference::getFullParticipantList() const {
+	auto participantList = mInvitedParticipants;
+	// Add participants that are not part of the invitees'list
+	for (const auto &p : getParticipants()) {
+		const auto &pAddress = p->getAddress();
+		auto pIt = std::find_if(participantList.begin(), participantList.end(), [&pAddress](const auto &participant) {
+			return (pAddress->weakEqual(*participant->getAddress()));
+		});
+		if (pIt == participantList.end()) {
+			auto participantInfo = Factory::get()->createParticipantInfo(pAddress);
+			participantList.push_back(participantInfo);
+		}
+	}
+	return participantList;
+}
+
 } // end of namespace MediaConference
 
 LINPHONE_END_NAMESPACE
diff --git a/coreapi/conference.h b/coreapi/conference.h
index 78370947b3..c4cc8e6cfa 100644
--- a/coreapi/conference.h
+++ b/coreapi/conference.h
@@ -24,6 +24,8 @@
 #include "belle-sip/object++.hh"
 
 #include "conference-cbs.h"
+#include "conference/conference-interface.h"
+#include "conference/conference.h"
 #include "linphone/conference.h"
 #include "linphone/utils/general.h"
 
@@ -63,8 +65,19 @@ void linphone_conference_set_state_changed_callback(LinphoneConference *obj,
 
 LINPHONE_BEGIN_NAMESPACE
 
+class AudioControlInterface;
+class VideoControlInterface;
+class MixerSession;
+class ConferenceParams;
+class Call;
+class CallSession;
+class CallSessionListener;
+class ParticipantDevice;
+class AudioDevice;
+class ConferenceId;
+
 namespace MediaConference { // They are in a special namespace because of conflict of generic Conference classes in
-                            // src/conference/*
+	                        // src/conference/*
 
 /*
  * Base class for audio/video conference.
@@ -180,7 +193,7 @@ public:
 	virtual void notifyStateChanged(LinphonePrivate::ConferenceInterface::State state) override;
 
 protected:
-	std::list<std::shared_ptr<Address>> invitedAddresses;
+	ConferenceInfo::participant_list_t mInvitedParticipants;
 
 	// Legacy member
 	std::string mConferenceID;
@@ -196,9 +209,9 @@ protected:
 	callStateChangedCb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message) = 0;
 	virtual void
 	transferStateChangedCb(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) = 0;
-
-	virtual std::shared_ptr<ConferenceInfo>
-	createConferenceInfoWithOrganizer(const std::shared_ptr<Address> &organizer) const override;
+	std::list<std::shared_ptr<Address>> getInvitedAddresses() const;
+	ConferenceInfo::participant_list_t getFullParticipantList() const;
+	void fillParticipantAttributes(std::shared_ptr<Participant> &p);
 };
 
 } // end of namespace MediaConference
diff --git a/coreapi/linphoneconference.c b/coreapi/linphoneconference.c
index d0c93a4075..a62c037bc7 100644
--- a/coreapi/linphoneconference.c
+++ b/coreapi/linphoneconference.c
@@ -41,6 +41,7 @@
 #include "linphone/conference.h"
 #include "local_conference.h"
 #include "remote_conference.h"
+#include "linphone/utils/utils.h"
 
 using namespace std;
 
diff --git a/coreapi/local_conference.cpp b/coreapi/local_conference.cpp
index 82b9bf0dba..c85c66cbf6 100644
--- a/coreapi/local_conference.cpp
+++ b/coreapi/local_conference.cpp
@@ -18,14 +18,16 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "core/core-p.h"
-#include "call/call-log.h"
-#include "db/main-db.h"
 #include "local_conference.h"
+#include "call/call-log.h"
+#include "conference/params/media-session-params-p.h"
+#include "conference/participant-info.h"
 #include "conference/participant.h"
-#include "conference/session/mixers.h"
 #include "conference/session/media-session-p.h"
-#include "conference/params/media-session-params-p.h"
+#include "conference/session/mixers.h"
+#include "core/core-p.h"
+#include "db/main-db.h"
+#include "factory/factory.h"
 #ifdef HAVE_ADVANCED_IM
 #include "conference/handlers/local-audio-video-conference-event-handler.h"
 #endif // HAVE_ADVANCED_IM
@@ -140,9 +142,10 @@ void LocalConference::updateConferenceInformation(SalCallOp *op) {
 		if (salAddress) {
 			ms_free(salAddress);
 		}
-		auto invited = std::find_if(invitedAddresses.begin(), invitedAddresses.end(), [&address](const auto &invitee) {
-			               return address->weakEqual(*invitee);
-		               }) != invitedAddresses.end();
+		auto invited =
+		    std::find_if(mInvitedParticipants.begin(), mInvitedParticipants.end(), [&address](const auto &invitee) {
+			    return address->weakEqual(*invitee->getAddress());
+		    }) != mInvitedParticipants.end();
 
 		std::shared_ptr<Address> remoteAddress =
 		    Address::create((op->getDir() == SalOp::Dir::Incoming) ? op->getFrom() : op->getTo());
@@ -202,13 +205,10 @@ void LocalConference::updateConferenceInformation(SalCallOp *op) {
 			getMe()->setAdmin(true);
 			getMe()->setFocus(true);
 
-			invitedAddresses.clear();
 			const auto resourceList = op->getContentInRemote(ContentType::ResourceLists);
-			if (!resourceList.isEmpty()) {
-				auto invitees = Utils::parseResourceLists(resourceList);
-				invitedAddresses.insert(invitedAddresses.begin(), invitees.begin(), invitees.end());
-			}
-			const auto &conferenceInfo = createConferenceInfoWithCustomParticipantList(organizer, invitedAddresses);
+			fillInvitedParticipantList(op, resourceList.isEmpty());
+
+			const auto &conferenceInfo = createConferenceInfoWithCustomParticipantList(organizer, mInvitedParticipants);
 			auto infoState = ConferenceInfo::State::New;
 			if (resourceList.isEmpty()) {
 				infoState = ConferenceInfo::State::Cancelled;
@@ -242,6 +242,27 @@ void LocalConference::updateConferenceInformation(SalCallOp *op) {
 	}
 }
 
+void LocalConference::fillInvitedParticipantList(SalCallOp *op, bool cancelling) {
+	mInvitedParticipants.clear();
+	const auto resourceList = op->getContentInRemote(ContentType::ResourceLists);
+	if (!resourceList.isEmpty()) {
+		auto invitees = Utils::parseResourceLists(resourceList);
+		mInvitedParticipants = invitees;
+		if (!cancelling) {
+			auto organizerNotFound =
+			    std::find_if(mInvitedParticipants.begin(), mInvitedParticipants.end(), [this](const auto &invitee) {
+				    return organizer->weakEqual(*invitee->getAddress());
+			    }) == mInvitedParticipants.end();
+			if (organizerNotFound && organizer) {
+				Participant::Role role = Participant::Role::Speaker;
+				lInfo() << "Setting role of organizer " << *organizer << " to " << role;
+				auto organizerInfo = Factory::get()->createParticipantInfo(organizer);
+				organizerInfo->setRole(role);
+				mInvitedParticipants.push_back(organizerInfo);
+			}
+		}
+	}
+}
 void LocalConference::configure(SalCallOp *op) {
 	LinphoneCore *lc = getCore()->getCCore();
 	bool admin = ((sal_address_has_param(op->getRemoteContactAddress(), "admin") &&
@@ -310,12 +331,7 @@ void LocalConference::configure(SalCallOp *op) {
 		if (endTime <= 0) {
 			endTime = -1;
 		}
-
-		const auto resourceList = op->getContentInRemote(ContentType::ResourceLists);
-		if (!resourceList.isEmpty()) {
-			auto invitees = Utils::parseResourceLists(resourceList);
-			invitedAddresses.insert(invitedAddresses.begin(), invitees.begin(), invitees.end());
-		}
+		fillInvitedParticipantList(op, false);
 	} else if (info) {
 		subject = info->getSubject();
 		organizer = info->getOrganizerAddress();
@@ -327,11 +343,7 @@ void LocalConference::configure(SalCallOp *op) {
 		} else {
 			endTime = -1;
 		}
-
-		const auto &participants = info->getParticipants();
-		for (const auto &p : participants) {
-			invitedAddresses.push_back(p.first);
-		}
+		mInvitedParticipants = info->getParticipants();
 	}
 
 	auto videoEnabled = linphone_core_video_enabled(lc);
@@ -399,10 +411,12 @@ void LocalConference::configure(SalCallOp *op) {
 }
 
 std::list<std::shared_ptr<Address>> LocalConference::getAllowedAddresses() const {
-	auto allowedAddresses = invitedAddresses;
-	auto organizerIt = std::find_if(invitedAddresses.begin(), invitedAddresses.end(),
-	                                [this](const auto &address) { return address->weakEqual(*organizer); });
-	if (organizerIt == invitedAddresses.end()) {
+	auto allowedAddresses = getInvitedAddresses();
+	;
+	auto organizerIt =
+	    std::find_if(mInvitedParticipants.begin(), mInvitedParticipants.end(),
+	                 [this](const auto &participant) { return participant->getAddress()->weakEqual(*organizer); });
+	if (organizerIt == mInvitedParticipants.end()) {
 		allowedAddresses.push_back(organizer);
 	}
 	return allowedAddresses;
@@ -477,7 +491,7 @@ void LocalConference::confirmCreation() {
 }
 
 std::shared_ptr<ConferenceInfo> LocalConference::createConferenceInfo() const {
-	return createConferenceInfoWithOrganizer(organizer);
+	return createConferenceInfoWithCustomParticipantList(organizer, getFullParticipantList());
 }
 
 void LocalConference::finalizeCreation() {
@@ -772,10 +786,10 @@ int LocalConference::participantDeviceJoined(
     BCTBX_UNUSED(const std::shared_ptr<LinphonePrivate::Participant> &participant),
     const std::shared_ptr<LinphonePrivate::ParticipantDevice> &device) {
 	int success = -1;
-	if ((device->updateMediaCapabilities() || (device->getState() != ParticipantDevice::State::Present)) &&
+	const auto mediaCapabilitiesChanged = device->updateMediaCapabilities();
+	if ((!mediaCapabilitiesChanged.empty() || (device->getState() != ParticipantDevice::State::Present)) &&
 	    (getState() == ConferenceInterface::State::Created)) {
 		lInfo() << "Device " << *device->getAddress() << " joined conference " << *getConferenceAddress();
-		device->updateMediaCapabilities();
 		device->updateStreamAvailabilities();
 		device->setState(ParticipantDevice::State::Present);
 		return 0;
@@ -803,7 +817,8 @@ int LocalConference::participantDeviceLeft(
     BCTBX_UNUSED(const std::shared_ptr<LinphonePrivate::Participant> &participant),
     const std::shared_ptr<LinphonePrivate::ParticipantDevice> &device) {
 	int success = -1;
-	if ((device->updateMediaCapabilities() || (device->getState() != ParticipantDevice::State::OnHold)) &&
+	const auto mediaCapabilitiesChanged = device->updateMediaCapabilities();
+	if ((!mediaCapabilitiesChanged.empty() || (device->getState() != ParticipantDevice::State::OnHold)) &&
 	    (getState() == ConferenceInterface::State::Created)) {
 		lInfo() << "Device " << *device->getAddress() << " left conference " << *getConferenceAddress();
 		device->updateStreamAvailabilities();
@@ -843,7 +858,8 @@ int LocalConference::participantDeviceMediaCapabilityChanged(
     const std::shared_ptr<LinphonePrivate::Participant> &participant,
     const std::shared_ptr<LinphonePrivate::ParticipantDevice> &device) {
 	int success = -1;
-	if (device->updateMediaCapabilities() &&
+	const auto mediaCapabilitiesChanged = device->updateMediaCapabilities();
+	if (!mediaCapabilitiesChanged.empty() &&
 	    ((getState() == ConferenceInterface::State::CreationPending) ||
 	     (getState() == ConferenceInterface::State::Created)) &&
 	    (device->getState() == ParticipantDevice::State::Present)) {
@@ -935,11 +951,7 @@ bool LocalConference::dialOutAddresses(const std::list<std::shared_ptr<Address>>
 	const string &confId = conferenceAddress->getUriParamValue("conf-id");
 	linphone_call_params_set_conference_id(new_params, confId.c_str());
 
-	std::list<std::shared_ptr<Address>> addresses;
-	if (!invitedAddresses.empty()) {
-		addresses = invitedAddresses;
-	}
-
+	std::list<std::shared_ptr<Address>> addresses = getInvitedAddresses();
 	// Add participants already in the conference to the list of addresses if they are not part of the invitees
 	for (const auto &p : getParticipants()) {
 		const auto &pAddress = p->getAddress();
@@ -1179,6 +1191,7 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 		// therefore there is no way to know if the remote client already knew that the call was in a conference or not.
 		auto contactAddress = session->getContactAddress();
 		tryAddMeDevice();
+
 		// Add participant to the conference participant list
 		switch (state) {
 			case LinphoneCallOutgoingInit:
@@ -1188,7 +1201,7 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 			case LinphoneCallPausing:
 			case LinphoneCallPaused:
 			case LinphoneCallResuming:
-			case LinphoneCallStreamsRunning:
+			case LinphoneCallStreamsRunning: {
 				if (call->toC() == linphone_core_get_current_call(getCore()->getCCore()))
 					L_GET_PRIVATE_FROM_C_OBJECT(getCore()->getCCore())->setCurrentCall(nullptr);
 				mMixerSession->joinStreamsGroup(session->getStreamsGroup());
@@ -1218,7 +1231,27 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 
 				Conference::addParticipant(call);
 
-				break;
+				const auto &participant = findParticipant(session->getRemoteAddress());
+				LinphoneMediaDirection audioDirection = LinphoneMediaDirectionInactive;
+				if (participant) {
+					const auto &role = participant->getRole();
+					switch (role) {
+						case Participant::Role::Speaker:
+							audioDirection = LinphoneMediaDirectionSendRecv;
+							break;
+						case Participant::Role::Listener:
+							audioDirection = LinphoneMediaDirectionSendOnly;
+							break;
+						case Participant::Role::Unknown:
+							audioDirection = LinphoneMediaDirectionInactive;
+							break;
+					}
+				}
+
+				const_cast<LinphonePrivate::MediaSessionParams *>(call->getParams())->setAudioDirection(audioDirection);
+			}
+
+			break;
 			default:
 				lError() << "Call " << call << " (local address " << call->getLocalAddress()->toString()
 				         << " remote address " << (remoteAddress ? remoteAddress->toString() : "Unknown")
@@ -1260,9 +1293,9 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 				}
 			} break;
 			default:
-				lError() << "Call " << call << " (local address " << call->getLocalAddress()->toString()
-				         << " remote address " << (remoteAddress ? remoteAddress->toString() : "Unknown")
-				         << ") is in state " << Utils::toString(call->getState())
+				lError() << "Call " << call << " (local address " << *call->getLocalAddress() << " remote address "
+				         << (remoteAddress ? remoteAddress->toString() : "Unknown") << ") is in state "
+				         << Utils::toString(call->getState())
 				         << ", hence the call cannot be updated following it becoming part of the conference";
 				return false;
 				break;
@@ -1286,7 +1319,8 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 		// If no resource list is provided in the INVITE, there is not need to call participants
 		if ((initialState == ConferenceInterface::State::CreationPending) && dialout && !resourceList.isEmpty()) {
 			list<std::shared_ptr<Address>> addresses;
-			for (auto &addr : invitedAddresses) {
+			for (auto &participant : mInvitedParticipants) {
+				const auto &addr = participant->getAddress();
 				// Do not invite organizer as it is already dialing in
 				if (*addr != *organizer) {
 					addresses.push_back(addr);
@@ -1318,7 +1352,10 @@ bool LocalConference::addParticipant(const std::shared_ptr<Address> &participant
 			    return (participantAddress->weakEqual(*address));
 		    });
 		if (p == allowedAddresses.end()) {
-			invitedAddresses.push_back(participantAddress);
+			// Participants invited after the start of a conference can only listen to it
+			auto participantInfo = Factory::get()->createParticipantInfo(participantAddress);
+			participantInfo->setRole(Participant::Role::Listener);
+			mInvitedParticipants.push_back(participantInfo);
 		}
 
 		std::list<std::shared_ptr<Address>> addressesList{participantAddress};
@@ -2026,7 +2063,7 @@ void LocalConference::callStateChangedCb(LinphoneCore *lc,
 			} break;
 			case LinphoneCallStateEnd:
 			case LinphoneCallStateError:
-				lInfo() << "Removing terminated call (local address " << session->getLocalAddress()->toString()
+				lInfo() << "Removing terminated call (local address " << *session->getLocalAddress()
 				        << " remote address " << *remoteAddress << ") from conference " << this << " ("
 				        << *getConferenceAddress() << ")";
 				if (session->getErrorInfo() &&
diff --git a/coreapi/local_conference.h b/coreapi/local_conference.h
index b03285cc80..e004259f54 100644
--- a/coreapi/local_conference.h
+++ b/coreapi/local_conference.h
@@ -33,7 +33,7 @@ class EventSubscribe;
 class EventPublish;
 
 namespace MediaConference { // They are in a special namespace because of conflict of generic Conference classes in
-                            // src/conference/*
+	                        // src/conference/*
 
 /*
  * Class for an audio/video conference running locally.
@@ -172,6 +172,9 @@ private:
 	bool mIsIn = false;
 	std::shared_ptr<Address> organizer;
 	static constexpr int confIdLength = 10;
+#ifdef HAVE_ADVANCED_IM
+	std::shared_ptr<LocalAudioVideoConferenceEventHandler> eventHandler;
+#endif // HAVE_ADVANCED_IM
 
 	bool validateNewParameters(const LinphonePrivate::ConferenceParams &newConfParams) const;
 	bool updateAllParticipantSessionsExcept(const std::shared_ptr<CallSession> &session);
@@ -184,12 +187,10 @@ private:
 	void checkIfTerminated();
 	std::list<std::shared_ptr<Address>> getAllowedAddresses() const;
 	void configure(SalCallOp *op);
+	void fillInvitedParticipantList(SalCallOp *op, bool cancelling);
 
 	void addLocalEndpoint();
 	void removeLocalEndpoint();
-#ifdef HAVE_ADVANCED_IM
-	std::shared_ptr<LocalAudioVideoConferenceEventHandler> eventHandler;
-#endif // HAVE_ADVANCED_IM
 
 	virtual std::shared_ptr<ConferenceInfo> createConferenceInfo() const override;
 	bool tryAddMeDevice();
diff --git a/coreapi/remote_conference.cpp b/coreapi/remote_conference.cpp
index 59b3c6ef74..cda3328b24 100644
--- a/coreapi/remote_conference.cpp
+++ b/coreapi/remote_conference.cpp
@@ -45,7 +45,7 @@ RemoteConference::RemoteConference(const shared_ptr<Core> &core,
                                    const std::shared_ptr<LinphonePrivate::CallSession> &focusSession,
                                    const std::shared_ptr<Address> &confAddr,
                                    const ConferenceId &conferenceId,
-                                   const std::list<std::shared_ptr<Address>> &invitees,
+                                   const ConferenceInfo::participant_list_t &invitees,
                                    CallSessionListener *listener,
                                    const std::shared_ptr<LinphonePrivate::ConferenceParams> params)
     : Conference(core, conferenceId.getLocalAddress(), listener, params) {
@@ -68,7 +68,7 @@ RemoteConference::RemoteConference(const shared_ptr<Core> &core,
 #endif
 	getMe()->setAdmin((organizer == nullptr) || organizer->weakEqual(*(getMe()->getAddress())));
 
-	invitedAddresses = invitees;
+	mInvitedParticipants = invitees;
 
 	setState(ConferenceInterface::State::Instantiated);
 
@@ -168,8 +168,16 @@ void RemoteConference::finalizeCreation() {
 std::shared_ptr<ConferenceInfo> RemoteConference::createConferenceInfo() const {
 	auto session = static_pointer_cast<MediaSession>(getMainSession());
 	const auto referer = (session ? L_GET_PRIVATE(session->getMediaParams())->getReferer() : nullptr);
-	const auto organizer = (referer) ? referer->getRemoteAddress() : getMe()->getAddress();
-	return createConferenceInfoWithOrganizer(organizer);
+	const auto guessedOrganizer = getOrganizer();
+	std::shared_ptr<Address> organizer = nullptr;
+	if (guessedOrganizer) {
+		organizer = guessedOrganizer;
+	} else if (referer) {
+		organizer = referer->getRemoteAddress();
+	} else {
+		organizer = getMe()->getAddress();
+	}
+	return createConferenceInfoWithCustomParticipantList(organizer, getFullParticipantList());
 }
 
 void RemoteConference::setMainSession(const std::shared_ptr<LinphonePrivate::CallSession> &session) {
@@ -1335,7 +1343,14 @@ void RemoteConference::onParticipantDeviceRemoved(
 	auto session = static_pointer_cast<MediaSession>(getMainSession());
 	const MediaSessionParams *params = session->getMediaParams();
 
-	if (confParams->videoEnabled() && params->videoEnabled() && (getState() == ConferenceInterface::State::Created) &&
+	const auto &confSecurityLevel = confParams->getSecurityLevel();
+	const auto &audioAvailable = device->getStreamAvailability(LinphoneStreamTypeAudio);
+	const auto audioNeedsReInvite = ((confSecurityLevel == ConferenceParams::SecurityLevel::EndToEnd) &&
+	                                 confParams->audioEnabled() && params->audioEnabled() && audioAvailable);
+
+	const auto videoNeedsReInvite = (confParams->videoEnabled() && params->videoEnabled());
+
+	if ((audioNeedsReInvite || videoNeedsReInvite) && (getState() == ConferenceInterface::State::Created) &&
 	    !isMe(device->getAddress()) && (device->getTimeOfJoining() >= 0)) {
 		auto updateSession = [this, device]() -> LinphoneStatus {
 			lInfo() << "Sending re-INVITE in order to update streams because participant device "
@@ -1368,16 +1383,12 @@ void RemoteConference::onParticipantDeviceStateChanged(
 		return (*devAddr == contactAddress);
 	});
 
-	const auto &audioDir = device->getStreamCapability(LinphoneStreamTypeAudio);
+	const auto &audioAvailable = device->getStreamAvailability(LinphoneStreamTypeAudio);
 	const auto &confSecurityLevel = confParams->getSecurityLevel();
-	const auto audioNeedsReInvite =
-	    ((confSecurityLevel == ConferenceParams::SecurityLevel::EndToEnd) && confParams->audioEnabled() &&
-	     params->audioEnabled() &&
-	     ((audioDir == LinphoneMediaDirectionSendOnly) || (audioDir == LinphoneMediaDirectionSendRecv)));
-	const auto &videoDir = device->getStreamCapability(LinphoneStreamTypeVideo);
-	const auto videoNeedsReInvite =
-	    (confParams->videoEnabled() && params->videoEnabled() &&
-	     ((videoDir == LinphoneMediaDirectionSendOnly) || (videoDir == LinphoneMediaDirectionSendRecv)));
+	const auto audioNeedsReInvite = ((confSecurityLevel == ConferenceParams::SecurityLevel::EndToEnd) &&
+	                                 confParams->audioEnabled() && params->audioEnabled() && audioAvailable);
+	const auto &videoAvailable = device->getStreamAvailability(LinphoneStreamTypeVideo);
+	const auto videoNeedsReInvite = (confParams->videoEnabled() && params->videoEnabled() && videoAvailable);
 	if ((getState() == ConferenceInterface::State::Created) && (callIt == m_pendingCalls.cend()) && isIn() &&
 	    (device->getState() == ParticipantDevice::State::Present) && ((videoNeedsReInvite || audioNeedsReInvite))) {
 		auto updateSession = [this, device]() -> LinphoneStatus {
diff --git a/coreapi/remote_conference.h b/coreapi/remote_conference.h
index 6df2219373..35fc7deae7 100644
--- a/coreapi/remote_conference.h
+++ b/coreapi/remote_conference.h
@@ -53,7 +53,7 @@ public:
 	                 const std::shared_ptr<LinphonePrivate::CallSession> &focusSession,
 	                 const std::shared_ptr<Address> &confAddr,
 	                 const ConferenceId &conferenceId,
-	                 const std::list<std::shared_ptr<Address>> &invitees,
+	                 const ConferenceInfo::participant_list_t &invitees,
 	                 CallSessionListener *listener,
 	                 const std::shared_ptr<LinphonePrivate::ConferenceParams> params);
 	virtual ~RemoteConference();
diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp
index a12ef932f6..cb4e3b4462 100644
--- a/coreapi/tester_utils.cpp
+++ b/coreapi/tester_utils.cpp
@@ -236,7 +236,7 @@ void linphone_core_reset_tone_manager_stats(LinphoneCore *lc) {
 	L_GET_PRIVATE_FROM_C_OBJECT(lc)->getToneManager().resetStats();
 }
 
-const char *linphone_core_get_tone_file(LinphoneCore *lc, LinphoneToneID id){
+const char *linphone_core_get_tone_file(LinphoneCore *lc, LinphoneToneID id) {
 	LinphoneToneDescription *tone = L_GET_PRIVATE_FROM_C_OBJECT(lc)->getToneManager().getTone(id);
 	return tone ? tone->audiofile : NULL;
 }
diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h
index 07c4447482..7a73faf8dc 100644
--- a/coreapi/tester_utils.h
+++ b/coreapi/tester_utils.h
@@ -304,7 +304,8 @@ LINPHONE_PUBLIC const char *linphone_core_get_groupchat_version(const LinphoneCo
 LINPHONE_PUBLIC const char *linphone_core_get_ephemeral_version(const LinphoneCore *lc);
 
 LINPHONE_PUBLIC size_t linphone_chat_room_get_previouses_conference_ids_count(LinphoneChatRoom *cr);
-LINPHONE_PUBLIC void linphone_conference_info_set_uri(LinphoneConferenceInfo *conference_info, LinphoneAddress *uri);
+LINPHONE_PUBLIC void linphone_conference_info_set_uri(LinphoneConferenceInfo *conference_info,
+                                                      const LinphoneAddress *uri);
 LINPHONE_PUBLIC bool_t linphone_participant_preserve_session(const LinphoneParticipant *participant);
 LINPHONE_PUBLIC bool_t linphone_conference_params_is_static(const LinphoneConferenceParams *params);
 
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 372d6be358..575238b1ce 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -106,6 +106,7 @@ set(C_API_HEADER_FILES
 	c-magic-search.h
 	c-magic-search-cbs.h
 	c-participant.h
+	c-participant-info.h
 	c-participant-device.h
 	c-participant-device-cbs.h
 	c-participant-device-identity.h
@@ -128,6 +129,7 @@ set(ENUMS_HEADER_FILES
 	chat-message-enums.h
 	chat-room-enums.h
 	conference-enums.h
+	participant-enums.h
 	participant-device-enums.h
 	encryption-engine-enums.h
 	event-log-enums.h
diff --git a/include/linphone/api/c-api.h b/include/linphone/api/c-api.h
index 2f10cdb9b8..631c4b0e6f 100644
--- a/include/linphone/api/c-api.h
+++ b/include/linphone/api/c-api.h
@@ -60,6 +60,7 @@
 #include "linphone/api/c-participant-device-identity.h"
 #include "linphone/api/c-participant-device.h"
 #include "linphone/api/c-participant-imdn-state.h"
+#include "linphone/api/c-participant-info.h"
 #include "linphone/api/c-participant.h"
 #include "linphone/api/c-push-notification-config.h"
 #include "linphone/api/c-push-notification-message.h"
diff --git a/include/linphone/api/c-conference-info.h b/include/linphone/api/c-conference-info.h
index 21b284ca35..06d371ae00 100644
--- a/include/linphone/api/c-conference-info.h
+++ b/include/linphone/api/c-conference-info.h
@@ -72,14 +72,23 @@ linphone_conference_info_get_organizer(const LinphoneConferenceInfo *conference_
  * @param organizer The #LinphoneAddress of the conference's organizer. @maybenil
  */
 LINPHONE_PUBLIC void linphone_conference_info_set_organizer(LinphoneConferenceInfo *conference_info,
-                                                            LinphoneAddress *organizer);
+                                                            const LinphoneAddress *organizer);
 
 /**
- * Retrieve the list of participants.
+ * Retrieve the list of participants as list of addresses.
  * @param conference_info The #LinphoneConferenceInfo object. @notnil
  * @return The list of participants. \bctbx_list{LinphoneAddress} @maybenil
  */
-LINPHONE_PUBLIC bctbx_list_t *linphone_conference_info_get_participants(const LinphoneConferenceInfo *conference_info);
+LINPHONE_PUBLIC LINPHONE_DEPRECATED const bctbx_list_t *
+linphone_conference_info_get_participants(const LinphoneConferenceInfo *conference_info);
+
+/**
+ * Retrieve the list of participants as list of participant infos.
+ * @param conference_info The #LinphoneConferenceInfo object. @notnil
+ * @return The list of participants. \bctbx_list{LinphoneParticipantInfo} @maybenil
+ */
+LINPHONE_PUBLIC const bctbx_list_t *
+linphone_conference_info_get_participant_infos(const LinphoneConferenceInfo *conference_info);
 
 /**
  * Set the list of participants.
@@ -87,7 +96,15 @@ LINPHONE_PUBLIC bctbx_list_t *linphone_conference_info_get_participants(const Li
  * @param participants The list of participants to set. \bctbx_list{LinphoneAddress} @maybenil
  */
 LINPHONE_PUBLIC void linphone_conference_info_set_participants(LinphoneConferenceInfo *conference_info,
-                                                               bctbx_list_t *participants);
+                                                               const bctbx_list_t *participants);
+
+/**
+ * Set the list of participants.
+ * @param conference_info The #LinphoneConferenceInfo object. @notnil
+ * @param participant_infos The list of participant informations to set. \bctbx_list{LinphoneParticipantInfo} @maybenil
+ */
+LINPHONE_PUBLIC void linphone_conference_info_set_participants_2(LinphoneConferenceInfo *conference_info,
+                                                                 const bctbx_list_t *participant_infos);
 
 /**
  * Add a participant to the conference.
@@ -95,7 +112,25 @@ LINPHONE_PUBLIC void linphone_conference_info_set_participants(LinphoneConferenc
  * @param participant The participant (#LinphoneAddress) to add. @notnil
  */
 LINPHONE_PUBLIC void linphone_conference_info_add_participant(LinphoneConferenceInfo *conference_info,
-                                                              LinphoneAddress *participant);
+                                                              const LinphoneAddress *participant);
+
+/**
+ * Add a participant to the conference.
+ * @param conference_info The #LinphoneConferenceInfo object. @notnil
+ * @param participant_info The participant information (#LinphoneParticipantInfo) to add. This method can be called to
+ * set attributes such as the role to the organizer of the conference @notnil
+ */
+LINPHONE_PUBLIC void linphone_conference_info_add_participant_2(LinphoneConferenceInfo *conference_info,
+                                                                const LinphoneParticipantInfo *participant_info);
+
+/**
+ * Update the participant information in the conference informations
+ * @param conference_info The #LinphoneConferenceInfo object. @notnil
+ * @param participant_info The participant information (#LinphoneParticipantInfo) to update. This method can be called
+ * to change attributes such as the role to the organizer of the conference @notnil
+ */
+LINPHONE_PUBLIC void linphone_conference_info_update_participant(LinphoneConferenceInfo *conference_info,
+                                                                 const LinphoneParticipantInfo *participant_info);
 
 /**
  * Remove a participant from the conference.
@@ -103,7 +138,16 @@ LINPHONE_PUBLIC void linphone_conference_info_add_participant(LinphoneConference
  * @param participant The participant (#LinphoneAddress) to remove. @notnil
  */
 LINPHONE_PUBLIC void linphone_conference_info_remove_participant(LinphoneConferenceInfo *conference_info,
-                                                                 LinphoneAddress *participant);
+                                                                 const LinphoneAddress *participant);
+
+/**
+ * Find a participant information in the conference information.
+ * @param conference_info The #LinphoneConferenceInfo object. @notnil
+ * @param participant The participant (#LinphoneAddress) to search. @notnil
+ * @return The participant information (#LinphoneParticipantInfo). @maybenil
+ */
+LINPHONE_PUBLIC const LinphoneParticipantInfo *
+linphone_conference_info_find_participant(LinphoneConferenceInfo *conference_info, const LinphoneAddress *participant);
 
 /**
  * Retrieve the URI of the conference.
@@ -184,7 +228,7 @@ linphone_conference_info_get_security_level(const LinphoneConferenceInfo *confer
  * @param security_level The desired security level of the conference.
  */
 LINPHONE_PUBLIC void linphone_conference_info_set_security_level(LinphoneConferenceInfo *conference_info,
-																 LinphoneConferenceSecurityLevel security_level);
+                                                                 LinphoneConferenceSecurityLevel security_level);
 
 /**
  * Retrieve the conference as an Icalendar string.
diff --git a/include/linphone/api/c-factory.h b/include/linphone/api/c-factory.h
index af0268fc16..593fd9779b 100644
--- a/include/linphone/api/c-factory.h
+++ b/include/linphone/api/c-factory.h
@@ -792,6 +792,15 @@ LINPHONE_PUBLIC LinphoneConferenceInfo *linphone_factory_create_conference_info(
 LINPHONE_PUBLIC LinphoneConferenceInfo *
 linphone_factory_create_conference_info_from_icalendar_content(LinphoneFactory *factory, LinphoneContent *content);
 
+/**
+ * Creates an object #LinphoneConferenceInfo from an Icalendar #LinphoneContent
+ * @param factory the #LinphoneFactory @notnil
+ * @param address the #LinphoneAddress of the participant @notnil
+ * @return a #LinphoneParticipantInfo @maybenil
+ */
+LINPHONE_PUBLIC LinphoneParticipantInfo *linphone_factory_create_participant_info(LinphoneFactory *factory,
+                                                                                  LinphoneAddress *address);
+
 /**
  * Creates an object #LinphoneConferenceSchedulerCbs
  * @param factory the #LinphoneFactory @notnil
diff --git a/include/linphone/api/c-participant-info.h b/include/linphone/api/c-participant-info.h
new file mode 100644
index 0000000000..7266c17f10
--- /dev/null
+++ b/include/linphone/api/c-participant-info.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2010-2022 Belledonne Communications SARL.
+ *
+ * This file is part of Liblinphone
+ * (see https://gitlab.linphone.org/BC/public/liblinphone).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LINPHONE_PARTICIPANT_INFO_H
+#define LINPHONE_PARTICIPANT_INFO_H
+
+#include "linphone/api/c-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup conference
+ * @{
+ */
+
+/**
+ * Create a new #LinphoneParticipantInfo object.
+ * @return The newly created #LinphoneParticipantInfo object. @notnil
+ */
+LINPHONE_PUBLIC LinphoneParticipantInfo *linphone_participant_info_new(LinphoneAddress *address);
+
+/**
+ * Take a reference on a #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @return the same #LinphoneParticipantInfo object. @notnil
+ */
+LINPHONE_PUBLIC LinphoneParticipantInfo *linphone_participant_info_ref(LinphoneParticipantInfo *participant_info);
+
+/**
+ * Clone an object #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @return the cloned #LinphoneParticipantInfo object. @notnil
+ */
+LINPHONE_PUBLIC LinphoneParticipantInfo *
+linphone_participant_info_clone(const LinphoneParticipantInfo *participant_info);
+
+/**
+ * Release a #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ */
+LINPHONE_PUBLIC void linphone_participant_info_unref(LinphoneParticipantInfo *participant_info);
+
+/**
+ * Get the address of the object #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @return the #LiphoneAddress of the #LinphoneParticipantInfo object. @notnil
+ */
+LINPHONE_PUBLIC const LinphoneAddress *
+linphone_participant_info_get_address(const LinphoneParticipantInfo *participant_info);
+
+/**
+ * Set the role of the object #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @param role the #LiphoneParticipantRole of the #LinphoneParticipantInfo object. @notnil
+ */
+LINPHONE_PUBLIC void linphone_participant_info_set_role(LinphoneParticipantInfo *participant_info,
+                                                        LinphoneParticipantRole role);
+
+/**
+ * Get the role of the object #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @return the #LiphoneParticipantRole of the #LinphoneParticipantInfo object. @notnil
+ */
+LINPHONE_PUBLIC LinphoneParticipantRole
+linphone_participant_info_get_role(const LinphoneParticipantInfo *participant_info);
+
+/**
+ * Set the a custom parameter to object #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @param name the name of the parameter. @notnil
+ * @param value the value of the parameter. @notnil
+ */
+LINPHONE_PUBLIC void
+linphone_participant_info_add_parameter(LinphoneParticipantInfo *participant_info, const char *name, const char *value);
+
+/**
+ * Get the value of a custom parameter of the object #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @param name the name of the parameter. @notnil
+ * @return value the value of the parameter. @notnil
+ */
+LINPHONE_PUBLIC const char *
+linphone_participant_info_get_parameter_value(const LinphoneParticipantInfo *participant_info, const char *name);
+
+/**
+ * Find whether a #LinphoneParticipantInfo has a parameter
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @param name the name of the parameter. @notnil
+ * @return TRUE if the parameter is present, FALSE otherwise
+ */
+LINPHONE_PUBLIC bool_t linphone_participant_info_has_parameter(const LinphoneParticipantInfo *participant_info,
+                                                               const char *name);
+
+/**
+ * Find the value of a custom parameter of the object #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @param name the name of the parameter. @notnil
+ */
+LINPHONE_PUBLIC void linphone_participant_info_remove_parameter(LinphoneParticipantInfo *participant_info,
+                                                                const char *name);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LINPHONE_PARTICIPANT_INFO_H
diff --git a/include/linphone/api/c-participant.h b/include/linphone/api/c-participant.h
index 09637f4104..f065acf54b 100644
--- a/include/linphone/api/c-participant.h
+++ b/include/linphone/api/c-participant.h
@@ -124,6 +124,13 @@ LINPHONE_PUBLIC LinphoneParticipantDevice *linphone_participant_find_device(cons
  */
 LINPHONE_PUBLIC time_t linphone_participant_get_creation_time(const LinphoneParticipant *participant);
 
+/**
+ * Get the role of the participant within the conference
+ * @param participant A #LinphoneParticipant object @notnil
+ * @return role within the conference #LinphoneParticipantRole
+ */
+LINPHONE_PUBLIC LinphoneParticipantRole linphone_participant_get_role(const LinphoneParticipant *participant);
+
 /**
  * @}
  */
diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h
index baec1b69e9..de442e0af6 100644
--- a/include/linphone/api/c-types.h
+++ b/include/linphone/api/c-types.h
@@ -31,6 +31,7 @@
 #include "linphone/enums/encryption-engine-enums.h"
 #include "linphone/enums/event-log-enums.h"
 #include "linphone/enums/participant-device-enums.h"
+#include "linphone/enums/participant-enums.h"
 #include "linphone/enums/security-event-enums.h"
 #include "linphone/utils/enum-generator.h"
 
@@ -197,6 +198,13 @@ typedef struct _LinphoneConferenceSchedulerCbs LinphoneConferenceSchedulerCbs;
  */
 typedef struct _LinphoneParticipant LinphoneParticipant;
 
+/**
+ * @brief Object defining all information related to a participant
+ *
+ * @ingroup conference
+ */
+typedef struct _LinphoneParticipantInfo LinphoneParticipantInfo;
+
 /**
  * @brief This object represents a unique device for a member of a #LinphoneConference or #LinphoneChatRoom.
  *
diff --git a/include/linphone/enums/participant-enums.h b/include/linphone/enums/participant-enums.h
new file mode 100644
index 0000000000..cf439f6663
--- /dev/null
+++ b/include/linphone/enums/participant-enums.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010-2023 Belledonne Communications SARL.
+ *
+ * This file is part of Liblinphone
+ * (see https://gitlab.linphone.org/BC/public/liblinphone).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _L_PARTICIPANT_ENUMS_H_
+#define _L_PARTICIPANT_ENUMS_H_
+// =============================================================================
+
+/**
+ * #LinphoneParticipantRole is used to define a role of a participant within a conference
+ * @ingroup conference
+ */
+typedef enum _LinphoneParticipantRole {
+	LinphoneParticipantRoleSpeaker = 0,  /**< participant is a speaker in the conference */
+	LinphoneParticipantRoleListener = 1, /**< participant is a listener in the conference. He/She cannot speak */
+	LinphoneParticipantRoleUnknown = 2   /**< participant role is unknown */
+} LinphoneParticipantRole;
+
+#endif // ifndef _L_PARTICIPANT_ENUMS_H_
diff --git a/include/linphone/misc.h b/include/linphone/misc.h
index 328564eb4d..bc01533412 100644
--- a/include/linphone/misc.h
+++ b/include/linphone/misc.h
@@ -109,6 +109,8 @@ linphone_core_log_collection_upload_state_to_string(const LinphoneCoreLogCollect
 
 LINPHONE_PUBLIC const char *linphone_call_state_to_string(LinphoneCallState cs);
 
+LINPHONE_PUBLIC const char *linphone_participant_role_to_string(LinphoneParticipantRole role);
+
 /**
  * Converts a #LinphoneConfiguringState enum to a string.
  * @param state #LinphoneConfiguringState the value for which we want a string representation
diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h
index 8c1c9272cd..893847af4c 100644
--- a/include/linphone/utils/utils.h
+++ b/include/linphone/utils/utils.h
@@ -31,8 +31,7 @@
 
 #include "bctoolbox/utils.hh"
 
-#include "address/address.h"
-#include "conference/session/streams.h"
+#include "conference/conference-info.h"
 #include "linphone/utils/enum-generator.h"
 
 // =============================================================================
@@ -261,7 +260,7 @@ private:
 LINPHONE_PUBLIC std::map<std::string, Version> parseCapabilityDescriptor(const std::string &descriptor);
 std::string getSipFragAddress(const Content &content);
 std::string getResourceLists(const std::list<std::shared_ptr<Address>> &addresses);
-std::list<std::shared_ptr<Address>> parseResourceLists(const Content &content);
+ConferenceInfo::participant_list_t parseResourceLists(const Content &content);
 std::shared_ptr<ConferenceInfo> createConferenceInfoFromOp(SalCallOp *op, bool remote);
 std::string computeHa1ForAlgorithm(const std::string &userId,
                                    const std::string &password,
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 80dd69d917..21af77fa4b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -111,6 +111,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
 	auth-info/auth-info.h
 	auth-info/auth-stack.h
 	c-wrapper/c-wrapper.h
+	c-wrapper/list-holder.h
 	c-wrapper/internal/c-sal.h
 	c-wrapper/internal/c-tools.h
 	call/call-log.h
@@ -168,6 +169,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
 	conference/params/call-session-params.h
 	conference/params/media-session-params-p.h
 	conference/params/media-session-params.h
+	conference/participant-info.h
 	conference/participant-device.h
 	conference/participant-imdn-state-p.h
 	conference/participant-imdn-state.h
@@ -374,6 +376,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
 	c-wrapper/api/c-magic-search.cpp
 	c-wrapper/api/c-magic-search-cbs.cpp
 	c-wrapper/api/c-participant.cpp
+	c-wrapper/api/c-participant-info.cpp
 	c-wrapper/api/c-participant-device.cpp
 	c-wrapper/api/c-participant-device-cbs.cpp
 	c-wrapper/api/c-participant-device-identity.cpp
@@ -420,6 +423,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
 	conference/local-conference.cpp
 	conference/params/call-session-params.cpp
 	conference/params/media-session-params.cpp
+	conference/participant-info.cpp
 	conference/participant-device.cpp
 	conference/participant-imdn-state.cpp
 	conference/participant.cpp
diff --git a/src/alert/alert.h b/src/alert/alert.h
index 256a3134f6..e238eccbf6 100644
--- a/src/alert/alert.h
+++ b/src/alert/alert.h
@@ -20,12 +20,15 @@
 #ifndef ALERT_H
 #define ALERT_H
 
+#include <memory>
+#include <unordered_map>
+
+#include <belle-sip/object++.hh>
+
 #include "call/call.h"
+#include "conference/session/streams.h"
 #include "dictionary/dictionary.h"
 #include "linphone/api/c-types.h"
-#include <belle-sip/object++.hh>
-#include <memory>
-#include <unordered_map>
 
 using namespace std;
 
@@ -151,4 +154,4 @@ private:
 };
 LINPHONE_END_NAMESPACE
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/c-wrapper/api/c-account-params.cpp b/src/c-wrapper/api/c-account-params.cpp
index 53f7303fb7..4dd82e9c9a 100644
--- a/src/c-wrapper/api/c-account-params.cpp
+++ b/src/c-wrapper/api/c-account-params.cpp
@@ -25,6 +25,7 @@
 #include "linphone/api/c-address.h"
 #include "linphone/core.h"
 #include "linphone/lpconfig.h"
+#include "linphone/utils/utils.h"
 #include "nat/nat-policy.h"
 #include "push-notification/push-notification-config.h"
 
diff --git a/src/c-wrapper/api/c-conference-info.cpp b/src/c-wrapper/api/c-conference-info.cpp
index b11308f58e..2b9b55867e 100644
--- a/src/c-wrapper/api/c-conference-info.cpp
+++ b/src/c-wrapper/api/c-conference-info.cpp
@@ -22,6 +22,7 @@
 #include "c-wrapper/c-wrapper.h"
 #include "c-wrapper/internal/c-tools.h"
 #include "conference/conference-info.h"
+#include "conference/participant-info.h"
 #include "linphone/api/c-address.h"
 
 // =============================================================================
@@ -50,46 +51,68 @@ const LinphoneAddress *linphone_conference_info_get_organizer(const LinphoneConf
 	return address && address->isValid() ? address->toC() : nullptr;
 }
 
-void linphone_conference_info_set_organizer(LinphoneConferenceInfo *conference_info, LinphoneAddress *organizer) {
+void linphone_conference_info_set_organizer(LinphoneConferenceInfo *conference_info, const LinphoneAddress *organizer) {
 	ConferenceInfo::toCpp(conference_info)->setOrganizer(Address::toCpp(organizer)->getSharedFromThis());
 }
 
-bctbx_list_t *linphone_conference_info_get_participants(const LinphoneConferenceInfo *conference_info) {
-	const auto &participants = ConferenceInfo::toCpp(conference_info)->getParticipants();
-	bctbx_list_t *participant_addresses = NULL;
-	for (const auto &participant : participants) {
-		const auto &address = participant.first;
-		participant_addresses = bctbx_list_append(participant_addresses, address->toC());
-	}
-	return participant_addresses;
+const bctbx_list_t *linphone_conference_info_get_participants(const LinphoneConferenceInfo *conference_info) {
+	return ConferenceInfo::toCpp(conference_info)->getParticipantAddressCList();
+}
+
+const bctbx_list_t *linphone_conference_info_get_participant_infos(const LinphoneConferenceInfo *conference_info) {
+	return ConferenceInfo::toCpp(conference_info)->getParticipantsCList();
 }
 
-void linphone_conference_info_set_participants(LinphoneConferenceInfo *conference_info, bctbx_list_t *participants) {
+void linphone_conference_info_set_participants(LinphoneConferenceInfo *conference_info,
+                                               const bctbx_list_t *participants) {
 	const std::list<std::shared_ptr<LinphonePrivate::Address>> participantsList =
 	    LinphonePrivate::Utils::bctbxListToCppSharedPtrList<LinphoneAddress, LinphonePrivate::Address>(participants);
-	ConferenceInfo::participant_list_t participantsMap;
-	ConferenceInfo::participant_params_t participantsParams;
-	for (const auto &p : participantsList) {
-		participantsMap[p] = participantsParams;
-	}
-	ConferenceInfo::toCpp(conference_info)->setParticipants(participantsMap);
+	ConferenceInfo::toCpp(conference_info)->setParticipants(participantsList);
+}
+
+void linphone_conference_info_set_participants_2(LinphoneConferenceInfo *conference_info,
+                                                 const bctbx_list_t *participant_infos) {
+	const std::list<std::shared_ptr<LinphonePrivate::ParticipantInfo>> participantInfos =
+	    LinphonePrivate::Utils::bctbxListToCppSharedPtrList<LinphoneParticipantInfo, LinphonePrivate::ParticipantInfo>(
+	        participant_infos);
+	ConferenceInfo::toCpp(conference_info)->setParticipants(participantInfos);
 }
 
-void linphone_conference_info_add_participant(LinphoneConferenceInfo *conference_info, LinphoneAddress *participant) {
+void linphone_conference_info_add_participant(LinphoneConferenceInfo *conference_info,
+                                              const LinphoneAddress *participant) {
 	ConferenceInfo::toCpp(conference_info)->addParticipant(Address::toCpp(participant)->getSharedFromThis());
 }
 
+void linphone_conference_info_add_participant_2(LinphoneConferenceInfo *conference_info,
+                                                const LinphoneParticipantInfo *participant_info) {
+	ConferenceInfo::toCpp(conference_info)
+	    ->addParticipant(ParticipantInfo::toCpp(participant_info)->getSharedFromThis());
+}
+
+void linphone_conference_info_update_participant(LinphoneConferenceInfo *conference_info,
+                                                 const LinphoneParticipantInfo *participant_info) {
+	ConferenceInfo::toCpp(conference_info)
+	    ->updateParticipant(ParticipantInfo::toCpp(participant_info)->getSharedFromThis());
+}
+
 void linphone_conference_info_remove_participant(LinphoneConferenceInfo *conference_info,
-                                                 LinphoneAddress *participant) {
+                                                 const LinphoneAddress *participant) {
 	ConferenceInfo::toCpp(conference_info)->removeParticipant(Address::toCpp(participant)->getSharedFromThis());
 }
 
+const LinphoneParticipantInfo *linphone_conference_info_find_participant(LinphoneConferenceInfo *conference_info,
+                                                                         const LinphoneAddress *participant) {
+	const auto &participant_info =
+	    ConferenceInfo::toCpp(conference_info)->findParticipant(Address::toCpp(participant)->getSharedFromThis());
+	return (participant_info) ? participant_info->toC() : NULL;
+}
+
 const LinphoneAddress *linphone_conference_info_get_uri(const LinphoneConferenceInfo *conference_info) {
 	const auto &address = ConferenceInfo::toCpp(conference_info)->getUri();
 	return address && address->isValid() ? address->toC() : nullptr;
 }
 
-void linphone_conference_info_set_uri(LinphoneConferenceInfo *conference_info, LinphoneAddress *uri) {
+void linphone_conference_info_set_uri(LinphoneConferenceInfo *conference_info, const LinphoneAddress *uri) {
 	ConferenceInfo::toCpp(conference_info)->setUri(Address::toCpp(uri)->getSharedFromThis());
 }
 
@@ -139,7 +162,7 @@ linphone_conference_info_get_security_level(const LinphoneConferenceInfo *confer
 }
 
 void linphone_conference_info_set_security_level(LinphoneConferenceInfo *conference_info,
-												 LinphoneConferenceSecurityLevel security_level) {
+                                                 LinphoneConferenceSecurityLevel security_level) {
 	ConferenceInfo::toCpp(conference_info)->setSecurityLevel((ConferenceParamsInterface::SecurityLevel)security_level);
 }
 
diff --git a/src/c-wrapper/api/c-factory.cpp b/src/c-wrapper/api/c-factory.cpp
index 19561f730a..b0feacc514 100644
--- a/src/c-wrapper/api/c-factory.cpp
+++ b/src/c-wrapper/api/c-factory.cpp
@@ -21,6 +21,7 @@
 #include <bctoolbox/defs.h>
 
 #include "c-wrapper/c-wrapper.h"
+#include "conference/participant-info.h"
 #include "factory/factory.h"
 #include "linphone/api/c-factory.h"
 
@@ -466,6 +467,12 @@ LinphoneConferenceInfo *linphone_factory_create_conference_info_from_icalendar_c
 	return conferenceInfo ? linphone_conference_info_ref(conferenceInfo->toC()) : nullptr;
 }
 
+LinphoneParticipantInfo *linphone_factory_create_participant_info(LinphoneFactory *factory, LinphoneAddress *address) {
+	std::shared_ptr<LinphonePrivate::ParticipantInfo> participantInfo =
+	    Factory::toCpp(factory)->createParticipantInfo(Address::toCpp(address)->getSharedFromThis());
+	return participantInfo ? linphone_participant_info_ref(participantInfo->toC()) : nullptr;
+}
+
 LinphoneConferenceSchedulerCbs *linphone_factory_create_conference_scheduler_cbs(LinphoneFactory *factory) {
 	return Factory::toCpp(factory)->createConferenceSchedulerCbs();
 }
diff --git a/src/c-wrapper/api/c-participant-info.cpp b/src/c-wrapper/api/c-participant-info.cpp
new file mode 100644
index 0000000000..53a1435769
--- /dev/null
+++ b/src/c-wrapper/api/c-participant-info.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2010-2023 Belledonne Communications SARL.
+ *
+ * This file is part of Liblinphone
+ * (see https://gitlab.linphone.org/BC/public/liblinphone).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "linphone/api/c-participant-info.h"
+#include "c-wrapper/c-wrapper.h"
+#include "c-wrapper/internal/c-tools.h"
+#include "conference/participant-info.h"
+#include "linphone/api/c-address.h"
+
+// =============================================================================
+
+using namespace LinphonePrivate;
+
+LinphoneParticipantInfo *linphone_participant_info_new(LinphoneAddress *address) {
+	return ParticipantInfo::createCObject(Address::toCpp(address)->getSharedFromThis());
+}
+
+LinphoneParticipantInfo *linphone_participant_info_ref(LinphoneParticipantInfo *participant_info) {
+	ParticipantInfo::toCpp(participant_info)->ref();
+	return participant_info;
+}
+
+LinphoneParticipantInfo *linphone_participant_info_clone(const LinphoneParticipantInfo *info) {
+	return static_cast<ParticipantInfo *>(ParticipantInfo::toCpp(info)->clone())->toC();
+}
+
+void linphone_participant_info_unref(LinphoneParticipantInfo *participant_info) {
+	ParticipantInfo::toCpp(participant_info)->unref();
+}
+
+const LinphoneAddress *linphone_participant_info_get_address(const LinphoneParticipantInfo *participant_info) {
+	const auto &addr = ParticipantInfo::toCpp(participant_info)->getAddress();
+	return addr->toC();
+}
+
+void linphone_participant_info_set_role(LinphoneParticipantInfo *participant_info, LinphoneParticipantRole role) {
+	return ParticipantInfo::toCpp(participant_info)->setRole((Participant::Role)role);
+}
+
+LinphoneParticipantRole linphone_participant_info_get_role(const LinphoneParticipantInfo *participant_info) {
+	return (LinphoneParticipantRole)ParticipantInfo::toCpp(participant_info)->getRole();
+}
+
+void linphone_participant_info_add_parameter(LinphoneParticipantInfo *participant_info,
+                                             const char *name,
+                                             const char *value) {
+	ParticipantInfo::toCpp(participant_info)->addParameter(L_C_TO_STRING(name), L_C_TO_STRING(value));
+}
+
+const char *linphone_participant_info_get_parameter_value(const LinphoneParticipantInfo *participant_info,
+                                                          const char *name) {
+	return L_STRING_TO_C(ParticipantInfo::toCpp(participant_info)->getParameterValue(L_C_TO_STRING(name)));
+}
+
+bool_t linphone_participant_info_has_parameter(const LinphoneParticipantInfo *participant_info, const char *name) {
+	return (bool_t)ParticipantInfo::toCpp(participant_info)->hasParameter(L_C_TO_STRING(name));
+}
+
+LINPHONE_PUBLIC void linphone_participant_info_remove_parameter(LinphoneParticipantInfo *participant_info,
+                                                                const char *name) {
+	ParticipantInfo::toCpp(participant_info)->removeParameter(L_C_TO_STRING(name));
+}
diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp
index 528136a90c..f2bfd23971 100644
--- a/src/c-wrapper/api/c-participant.cpp
+++ b/src/c-wrapper/api/c-participant.cpp
@@ -98,3 +98,19 @@ time_t linphone_participant_get_creation_time(const LinphoneParticipant *partici
 bool_t linphone_participant_preserve_session(const LinphoneParticipant *participant) {
 	return LinphonePrivate::Participant::toCpp(participant)->getPreserveSession();
 }
+
+LinphoneParticipantRole linphone_participant_get_role(const LinphoneParticipant *participant) {
+	return (LinphoneParticipantRole)LinphonePrivate::Participant::toCpp(participant)->getRole();
+}
+
+const char *linphone_participant_role_to_string(LinphoneParticipantRole role) {
+	switch (role) {
+		case LinphoneParticipantRoleSpeaker:
+			return "LinphoneParticipantRoleSpeaker";
+		case LinphoneParticipantRoleListener:
+			return "LinphoneParticipantRoleListener";
+		case LinphoneParticipantRoleUnknown:
+			return "LinphoneParticipantRoleUnknown";
+	}
+	return NULL;
+}
diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h
index 9872218125..f62f81d580 100644
--- a/src/c-wrapper/c-wrapper.h
+++ b/src/c-wrapper/c-wrapper.h
@@ -129,85 +129,6 @@ private:
 	bool mIsActive = true;
 };
 
-/*
- * Template for easy conversion from std::list to bctbx_list_t.
- * The authority list is the C++ one, the C one being only a const view of it.
- * _T must be an HybridObject; so that conversion from C++ type to C type is done automatically.
- */
-template <typename _T>
-class ListHolder {
-public:
-	ListHolder() = default;
-	ListHolder(const ListHolder<_T> &other) : mList(other.mList), mCList(nullptr) {
-	}
-	// The STL list is a public member, directly accessible.
-	std::list<std::shared_ptr<_T>> mList;
-	// Return a C list from the STL list.
-	const bctbx_list_t *getCList() const {
-		if (mCList) bctbx_list_free(mCList);
-		mCList = _T::getCListFromCppList(mList, false);
-		return mCList;
-	}
-	// Assign a C list. This replaces the STL list.
-	void setCList(const bctbx_list_t *clist) {
-		mList = _T::getCppListFromCList(clist);
-	}
-	~ListHolder() {
-		if (mCList) bctbx_list_free(mCList);
-	}
-
-private:
-	mutable bctbx_list_t *mCList = nullptr;
-};
-
-/*
- * Template class for classes that hold callbacks (such as LinphoneCallCbs, LinphoneAccountCbs etc.
- * The invocation of callbacks can be done with the LINPHONE_HYBRID_OBJECT_INVOKE_CBS() macro.
- */
-template <typename _CppCbsType>
-class LINPHONE_PUBLIC CallbacksHolder {
-public:
-	void addCallbacks(const std::shared_ptr<_CppCbsType> &callbacks) {
-		if (find(mCallbacksList.mList.begin(), mCallbacksList.mList.end(), callbacks) == mCallbacksList.mList.end()) {
-			mCallbacksList.mList.push_back(callbacks);
-			callbacks->setActive(true);
-		} else {
-			lError() << "Rejected Callbacks " << typeid(_CppCbsType).name() << " [" << (void *)callbacks.get()
-			         << "] added twice.";
-		}
-	}
-	void removeCallbacks(const std::shared_ptr<_CppCbsType> &callbacks) {
-		auto it = find(mCallbacksList.mList.begin(), mCallbacksList.mList.end(), callbacks);
-		if (it != mCallbacksList.mList.end()) {
-			mCallbacksList.mList.erase(it);
-			callbacks->setActive(false);
-		} else {
-			lError() << "Attempt to remove " << typeid(_CppCbsType).name() << " [" << (void *)callbacks.get()
-			         << "] that does not exist.";
-		}
-	}
-	void setCurrentCallbacks(const std::shared_ptr<_CppCbsType> &callbacks) {
-		mCurrentCallbacks = callbacks;
-	}
-	std::shared_ptr<_CppCbsType> getCurrentCallbacks() const {
-		return mCurrentCallbacks;
-	}
-	const std::list<std::shared_ptr<_CppCbsType>> &getCallbacksList() const {
-		return mCallbacksList.mList;
-	}
-	const bctbx_list_t *getCCallbacksList() const {
-		return mCallbacksList.getCList();
-	}
-	void clearCallbacksList() {
-		mCallbacksList.mList.clear();
-		mCurrentCallbacks = nullptr;
-	}
-
-private:
-	ListHolder<_CppCbsType> mCallbacksList;
-	std::shared_ptr<_CppCbsType> mCurrentCallbacks;
-};
-
 LINPHONE_END_NAMESPACE
 
 #include "internal/c-tools.h"
diff --git a/src/c-wrapper/list-holder.h b/src/c-wrapper/list-holder.h
new file mode 100644
index 0000000000..84124a8a1c
--- /dev/null
+++ b/src/c-wrapper/list-holder.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010-2023 Belledonne Communications SARL.
+ *
+ * This file is part of Liblinphone
+ * (see https://gitlab.linphone.org/BC/public/liblinphone).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Template for easy conversion from std::list to bctbx_list_t.
+ * The authority list is the C++ one, the C one being only a const view of it.
+ * _T must be an HybridObject; so that conversion from C++ type to C type is done automatically.
+ */
+
+#include "logger/logger.h"
+
+LINPHONE_BEGIN_NAMESPACE
+
+template <typename _T>
+class ListHolder {
+public:
+	ListHolder() = default;
+	ListHolder(const ListHolder<_T> &other) : mList(other.mList), mCList(nullptr) {
+	}
+	// The STL list is a public member, directly accessible.
+	std::list<std::shared_ptr<_T>> mList;
+	// Return a C list from the STL list.
+	const bctbx_list_t *getCList() const {
+		if (mCList) bctbx_list_free(mCList);
+		mCList = _T::getCListFromCppList(mList, false);
+		return mCList;
+	}
+	// Assign a C list. This replaces the STL list.
+	void setCList(const bctbx_list_t *clist) {
+		mList = _T::getCppListFromCList(clist);
+	}
+	~ListHolder() {
+		if (mCList) bctbx_list_free(mCList);
+	}
+
+private:
+	mutable bctbx_list_t *mCList = nullptr;
+};
+
+/*
+ * Template class for classes that hold callbacks (such as LinphoneCallCbs, LinphoneAccountCbs etc.
+ * The invocation of callbacks can be done with the LINPHONE_HYBRID_OBJECT_INVOKE_CBS() macro.
+ */
+template <typename _CppCbsType>
+class LINPHONE_PUBLIC CallbacksHolder {
+public:
+	void addCallbacks(const std::shared_ptr<_CppCbsType> &callbacks) {
+		if (find(mCallbacksList.mList.begin(), mCallbacksList.mList.end(), callbacks) == mCallbacksList.mList.end()) {
+			mCallbacksList.mList.push_back(callbacks);
+			callbacks->setActive(true);
+		} else {
+			lError() << "Rejected Callbacks " << typeid(_CppCbsType).name() << " [" << (void *)callbacks.get()
+			         << "] added twice.";
+		}
+	}
+	void removeCallbacks(const std::shared_ptr<_CppCbsType> &callbacks) {
+		auto it = find(mCallbacksList.mList.begin(), mCallbacksList.mList.end(), callbacks);
+		if (it != mCallbacksList.mList.end()) {
+			mCallbacksList.mList.erase(it);
+			callbacks->setActive(false);
+		} else {
+			lError() << "Attempt to remove " << typeid(_CppCbsType).name() << " [" << (void *)callbacks.get()
+			         << "] that does not exist.";
+		}
+	}
+	void setCurrentCallbacks(const std::shared_ptr<_CppCbsType> &callbacks) {
+		mCurrentCallbacks = callbacks;
+	}
+	std::shared_ptr<_CppCbsType> getCurrentCallbacks() const {
+		return mCurrentCallbacks;
+	}
+	const std::list<std::shared_ptr<_CppCbsType>> &getCallbacksList() const {
+		return mCallbacksList.mList;
+	}
+	const bctbx_list_t *getCCallbacksList() const {
+		return mCallbacksList.getCList();
+	}
+	void clearCallbacksList() {
+		mCallbacksList.mList.clear();
+		mCurrentCallbacks = nullptr;
+	}
+
+private:
+	ListHolder<_CppCbsType> mCallbacksList;
+	std::shared_ptr<_CppCbsType> mCurrentCallbacks;
+};
+
+LINPHONE_END_NAMESPACE
diff --git a/src/call/call.cpp b/src/call/call.cpp
index 67b609bbec..4d05081e10 100644
--- a/src/call/call.cpp
+++ b/src/call/call.cpp
@@ -542,10 +542,9 @@ void Call::createRemoteConference(const shared_ptr<CallSession> &session) {
 				time_t endTime = startTime + static_cast<time_t>(duration) * 60;
 				confParams->setEndTime(endTime);
 			}
-			std::list<std::shared_ptr<Address>> invitees{conferenceInfo->getOrganizerAddress()};
-			for (const auto &participant : conferenceInfo->getParticipants()) {
-				invitees.push_back(participant.first);
-			}
+			auto invitees = conferenceInfo->getParticipants();
+			const auto &organizer = conferenceInfo->getOrganizer();
+			invitees.push_back(organizer);
 
 			const std::shared_ptr<Address> confAddr = conferenceInfo->getUri();
 			const ConferenceId confId(confAddr, session->getLocalAddress());
@@ -558,9 +557,10 @@ void Call::createRemoteConference(const shared_ptr<CallSession> &session) {
 			const auto &remoteParams = static_pointer_cast<MediaSession>(session)->getRemoteParams();
 			confParams->setStartTime(remoteParams->getPrivate()->getStartTime());
 			confParams->setEndTime(remoteParams->getPrivate()->getEndTime());
-			auto organizer = Utils::getSipFragAddress(sipfrag);
 			auto invitees = Utils::parseResourceLists(resourceList);
-			invitees.push_back(Address::create(organizer));
+			const auto organizer = Utils::getSipFragAddress(sipfrag);
+			auto organizerInfo = Factory::get()->createParticipantInfo(Address::create(organizer));
+			invitees.push_back(organizerInfo);
 			remoteConference = std::shared_ptr<MediaConference::RemoteConference>(
 			    new MediaConference::RemoteConference(getCore(), session, remoteContactAddress, conferenceId, invitees,
 			                                          nullptr, confParams),
diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp
index 21ad93b098..d8e7385e68 100644
--- a/src/chat/chat-room/client-group-chat-room.cpp
+++ b/src/chat/chat-room/client-group-chat-room.cpp
@@ -33,6 +33,7 @@
 #include "conference/handlers/remote-conference-event-handler.h"
 #include "conference/handlers/remote-conference-list-event-handler.h"
 #include "conference/participant-device.h"
+#include "conference/participant-info.h"
 #include "conference/participant.h"
 #include "conference/remote-conference.h"
 #include "conference/session/call-session-p.h"
@@ -190,11 +191,12 @@ void ClientGroupChatRoomPrivate::confirmJoining(SalCallOp *op) {
 	if (!previousSession && !found) {
 		q->setState(ConferenceInterface::State::CreationPending);
 		// Handle participants addition
-		list<std::shared_ptr<Address>> identAddresses = Utils::parseResourceLists(op->getRemoteBody());
-		for (const auto &addr : identAddresses) {
-			auto participant = q->findParticipant(addr);
+		const auto participantList = Utils::parseResourceLists(op->getRemoteBody());
+		for (const auto &participantInfo : participantList) {
+			const auto &address = participantInfo->getAddress();
+			auto participant = q->findParticipant(address);
 			if (!participant) {
-				participant = Participant::create(q->getConference().get(), addr);
+				participant = Participant::create(q->getConference().get(), address);
 				q->getConference()->participants.push_back(participant);
 			}
 		}
@@ -417,8 +419,11 @@ ClientGroupChatRoom::ClientGroupChatRoom(const shared_ptr<Core> &core,
 	                                                         [](BCTBX_UNUSED(ConferenceListenerInterface * p)) {}));
 
 	getConference()->setSubject(subject);
-	for (const auto &addr : Utils::parseResourceLists(content))
-		getConference()->participants.push_back(Participant::create(getConference().get(), addr));
+	const auto participantList = Utils::parseResourceLists(content);
+	for (const auto &participantInfo : participantList) {
+		getConference()->participants.push_back(
+		    Participant::create(getConference().get(), participantInfo->getAddress()));
+	}
 
 	if (params->getEphemeralMode() == AbstractChatRoom::EphemeralMode::AdminManaged) {
 		d->capabilities |= ClientGroupChatRoom::Capabilities::Ephemeral;
diff --git a/src/chat/chat-room/server-group-chat-room.cpp b/src/chat/chat-room/server-group-chat-room.cpp
index 422fde411f..38cd2f93fb 100644
--- a/src/chat/chat-room/server-group-chat-room.cpp
+++ b/src/chat/chat-room/server-group-chat-room.cpp
@@ -30,6 +30,7 @@
 #include "conference/handlers/local-conference-event-handler.h"
 #include "conference/handlers/local-conference-list-event-handler.h"
 #include "conference/local-conference.h"
+#include "conference/participant-info.h"
 #include "conference/participant.h"
 #include "conference/session/call-session-p.h"
 #include "content/content-disposition.h"
@@ -624,18 +625,18 @@ void ServerGroupChatRoomPrivate::unSubscribeRegistrationForParticipant(const std
 }
 
 bool ServerGroupChatRoomPrivate::initializeParticipants(const shared_ptr<Participant> &initiator, SalCallOp *op) {
-
 	handleSubjectChange(op);
 	// Handle participants addition
-	list<std::shared_ptr<Address>> identAddresses = Utils::parseResourceLists(op->getRemoteBody());
+	const auto participantList = Utils::parseResourceLists(op->getRemoteBody());
+	std::list<std::shared_ptr<Address>> identAddresses;
 	// DO not try to add participants with invalid address
-	for (auto it = identAddresses.begin(); it != identAddresses.end();) {
-		if (!((*it)->isValid())) {
-			lError() << "ServerGroupChatRoomPrivate::initializeParticipants(): removing invalid address "
-			         << ((*it)->toString()) << " at position " << std::distance(it, identAddresses.begin());
-			it = identAddresses.erase(it);
+	for (auto it = participantList.begin(); it != participantList.end(); ++it) {
+		const auto &address = (*it)->getAddress();
+		if (!(address->isValid())) {
+			lError() << "ServerGroupChatRoomPrivate::initializeParticipants(): removing invalid address " << *address
+			         << " at position " << std::distance(it, participantList.begin());
 		} else {
-			++it;
+			identAddresses.push_back(address);
 		}
 	}
 	if (identAddresses.empty()) {
diff --git a/src/chat/ics/ics.cpp b/src/chat/ics/ics.cpp
index 6e24020382..9a865500c9 100644
--- a/src/chat/ics/ics.cpp
+++ b/src/chat/ics/ics.cpp
@@ -22,10 +22,12 @@
 #include <iomanip>
 #include <sstream>
 
-#include "ics.h"
-
 #include "bctoolbox/utils.hh"
+
 #include "chat/ics/parser/ics-parser.h"
+#include "conference/conference-params.h"
+#include "conference/participant-info.h"
+#include "ics.h"
 
 // =============================================================================
 
@@ -46,7 +48,7 @@ void Ics::Event::setOrganizer(const std::string &organizer) {
 	setOrganizer(organizer, params);
 }
 
-void Ics::Event::setOrganizer(const std::string &organizer, const attendee_params_t &params) {
+void Ics::Event::setOrganizer(const std::string &organizer, const Ics::Event::attendee_params_t &params) {
 	mOrganizer = std::make_pair(organizer, params);
 }
 
@@ -59,7 +61,7 @@ void Ics::Event::addAttendee(const std::string &attendee) {
 	addAttendee(attendee, params);
 }
 
-void Ics::Event::addAttendee(const std::string &attendee, const attendee_params_t &params) {
+void Ics::Event::addAttendee(const std::string &attendee, const Ics::Event::attendee_params_t &params) {
 	mAttendees.insert(std::make_pair(attendee, params));
 }
 
@@ -280,6 +282,14 @@ std::string Ics::Icalendar::asString() const {
 	return bctoolbox::Utils::fold(output.str());
 }
 
+std::shared_ptr<ParticipantInfo>
+Ics::Icalendar::fillParticipantInfo(const std::shared_ptr<Address> &address,
+                                    const Ics::Event::attendee_params_t &params) const {
+	auto participantInfo = ParticipantInfo::create(address);
+	participantInfo->setParameters(params);
+	return participantInfo;
+}
+
 std::shared_ptr<ConferenceInfo> Ics::Icalendar::toConferenceInfo() const {
 	if (mEvents.empty()) return nullptr;
 
@@ -287,11 +297,11 @@ std::shared_ptr<ConferenceInfo> Ics::Icalendar::toConferenceInfo() const {
 	const auto &event = mEvents.front(); // It should always be one event
 
 	if (!event->getOrganizerAddress().empty()) {
-		const auto &org = event->getOrganizer();
-		const auto &orgAddress = Address::create(org.first);
-		const auto &orgParams = org.second;
+		const auto &[orgAddressStr, orgParams] = event->getOrganizer();
+		const auto &orgAddress = Address::create(orgAddressStr);
 		if (orgAddress && orgAddress->isValid()) {
-			confInfo->setOrganizer(orgAddress, orgParams);
+			const auto organizerInfo = fillParticipantInfo(orgAddress, orgParams);
+			confInfo->setOrganizer(organizerInfo);
 		} else {
 			lWarning() << "Could not parse organizer's address: " << event->getOrganizerAddress()
 			           << " because it is not a valid address";
@@ -302,7 +312,8 @@ std::shared_ptr<ConferenceInfo> Ics::Icalendar::toConferenceInfo() const {
 		if (!address.empty()) {
 			const auto addr = Address::create(address);
 			if (addr && addr->isValid()) {
-				confInfo->addParticipant(addr, params);
+				const auto participantInfo = fillParticipantInfo(addr, params);
+				confInfo->addParticipant(participantInfo);
 			} else {
 				lWarning() << "Could not parse attendee's address: " << address << " because it is not a valid address";
 			}
diff --git a/src/chat/ics/ics.h b/src/chat/ics/ics.h
index cf35f58870..e67b25a7e1 100644
--- a/src/chat/ics/ics.h
+++ b/src/chat/ics/ics.h
@@ -122,6 +122,9 @@ public:
 	void setCreationTime(time_t time);
 
 private:
+	std::shared_ptr<ParticipantInfo> fillParticipantInfo(const std::shared_ptr<Address> &address,
+	                                                     const Ics::Event::attendee_params_t &params) const;
+
 	Method mMethod = Method::Request;
 	std::list<std::shared_ptr<Event>> mEvents;
 };
diff --git a/src/conference/conference-info.cpp b/src/conference/conference-info.cpp
index b60ffcc0e5..e111c98589 100644
--- a/src/conference/conference-info.cpp
+++ b/src/conference/conference-info.cpp
@@ -21,8 +21,10 @@
 #include "conference-info.h"
 
 #include "chat/ics/ics.h"
+#include "factory/factory.h"
 #include "linphone/api/c-address.h"
 #include "linphone/types.h"
+#include "participant-info.h"
 #include "private.h"
 
 #include "c-wrapper/c-wrapper.h"
@@ -33,8 +35,6 @@ using namespace std;
 
 LINPHONE_BEGIN_NAMESPACE
 
-const std::string ConferenceInfo::sequenceParam = "X-SEQ";
-
 ConferenceInfo::ConferenceInfo() {
 }
 
@@ -43,84 +43,115 @@ const ConferenceInfo::organizer_t &ConferenceInfo::getOrganizer() const {
 }
 
 const std::shared_ptr<Address> &ConferenceInfo::getOrganizerAddress() const {
-	return getOrganizer().first;
+	const auto &organizer = getOrganizer();
+	mOrganizerAddress = organizer ? organizer->getAddress() : nullptr;
+	return mOrganizerAddress;
 }
 
-void ConferenceInfo::setOrganizer(const std::shared_ptr<Address> &organizer, const participant_params_t &params) {
-	mOrganizer = std::make_pair(Address::create(organizer->getUri()), params);
+void ConferenceInfo::setOrganizer(const std::shared_ptr<const ParticipantInfo> &organizer) {
+	mOrganizer = organizer->clone()->toSharedPtr();
 }
 
-void ConferenceInfo::setOrganizer(const std::shared_ptr<Address> &organizer) {
-	ConferenceInfo::participant_params_t params;
-	setOrganizer(organizer, params);
+void ConferenceInfo::setOrganizer(const std::shared_ptr<const Address> &organizer) {
+	auto organizerInfo = Factory::get()->createParticipantInfo(Address::create(organizer->getUri()));
+	for (const auto &[name, value] : organizer->getParams()) {
+		organizerInfo->addParameter(name, value);
+	}
+	setOrganizer(organizerInfo);
 }
 
-void ConferenceInfo::addOrganizerParam(const std::string &param, const std::string &value) {
-	mOrganizer.second[param] = value;
+const ConferenceInfo::participant_list_t &ConferenceInfo::getParticipants() const {
+	return mParticipants;
 }
 
-const std::string ConferenceInfo::getOrganizerParam(const std::string &param) const {
-	try {
-		const auto &params = mOrganizer.second;
-		return params.at(param);
-	} catch (std::out_of_range &) {
-		return std::string();
+const bctbx_list_t *ConferenceInfo::getParticipantsCList() const {
+	mParticipantList.mList = mParticipants;
+	return mParticipantList.getCList();
+}
+
+const std::list<std::shared_ptr<Address>> &ConferenceInfo::getParticipantAddressList() const {
+	updateParticipantAddresses();
+	return mParticipantAddresses.mList;
+}
+
+const bctbx_list_t *ConferenceInfo::getParticipantAddressCList() const {
+	updateParticipantAddresses();
+	return mParticipantAddresses.getCList();
+}
+
+void ConferenceInfo::updateParticipantAddresses() const {
+	std::list<std::shared_ptr<Address>> addressList;
+	for (const auto &participantInfo : mParticipants) {
+		addressList.push_back(participantInfo->getAddress());
 	}
+	mParticipantAddresses.mList = addressList;
 }
 
-const ConferenceInfo::participant_list_t &ConferenceInfo::getParticipants() const {
-	return mParticipants;
+void ConferenceInfo::setParticipants(const std::list<std::shared_ptr<Address>> &participants) {
+	for (const auto &info : participants) {
+		addParticipant(info);
+	}
 }
 
-void ConferenceInfo::setParticipants(const participant_list_t &participants) {
-	for (const auto &p : participants) {
-		addParticipant(p.first, p.second);
+void ConferenceInfo::setParticipants(const ConferenceInfo::participant_list_t &participants) {
+	for (const auto &info : participants) {
+		addParticipant(info);
+	}
+}
+
+void ConferenceInfo::addParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo) {
+	const auto &address = participantInfo->getAddress();
+	if (hasParticipant(address)) {
+		mParticipants.push_back(participantInfo->clone()->toSharedPtr());
+	} else {
+		lInfo() << "Participant with address " << *address << " is already in the list of conference info " << this
+		        << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")";
 	}
 }
 
-void ConferenceInfo::addParticipant(const std::shared_ptr<Address> &participant) {
-	ConferenceInfo::participant_params_t params;
-	addParticipant(participant, params);
+void ConferenceInfo::addParticipant(const std::shared_ptr<const Address> &participant) {
+	auto participantInfo = Factory::get()->createParticipantInfo(participant->clone()->toSharedPtr());
+	addParticipant(participantInfo);
 }
 
-void ConferenceInfo::addParticipant(const std::shared_ptr<Address> &participant, const participant_params_t &params) {
-	mParticipants.insert(std::make_pair(Address::create(participant->getUri()), params));
+void ConferenceInfo::removeParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo) {
+	removeParticipant(participantInfo->getAddress());
 }
 
-void ConferenceInfo::removeParticipant(const std::shared_ptr<Address> &participant) {
-	auto it = std::find_if(mParticipants.begin(), mParticipants.end(),
-	                       [&participant](const auto &p) { return (participant->weakEqual(*p.first)); });
+void ConferenceInfo::removeParticipant(const std::shared_ptr<const Address> &participant) {
+	auto it = findParticipantIt(participant);
 	if (it == mParticipants.cend()) {
-		lInfo() << "Unable to find participant with address " << participant << " in conference info " << this
-		        << " (address " << *getUri() << ")";
+		lInfo() << "Unable to remove participant with address " << *participant << " in conference info " << this
+		        << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")";
 	} else {
 		mParticipants.erase(it);
 	}
 }
 
-void ConferenceInfo::addParticipantParam(const std::shared_ptr<Address> &participant,
-                                         const std::string &param,
-                                         const std::string &value) {
-	auto it = std::find_if(mParticipants.begin(), mParticipants.end(),
-	                       [&participant](const auto &p) { return (participant->weakEqual(*p.first)); });
-	if (it != mParticipants.end()) {
-		auto &params = (*it).second;
-		params[param] = value;
-	}
+void ConferenceInfo::updateParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo) {
+	removeParticipant(participantInfo);
+	addParticipant(participantInfo);
 }
 
-const std::string ConferenceInfo::getParticipantParam(const std::shared_ptr<Address> &participant,
-                                                      const std::string &param) const {
-	try {
-		auto it = std::find_if(mParticipants.begin(), mParticipants.end(),
-		                       [&participant](const auto &p) { return (participant->weakEqual(*p.first)); });
-		if (it != mParticipants.cend()) {
-			const auto &params = (*it).second;
-			return params.at(param);
-		}
-	} catch (std::out_of_range &) {
-	}
-	return std::string();
+ConferenceInfo::participant_list_t::const_iterator
+ConferenceInfo::findParticipantIt(const std::shared_ptr<const Address> &address) const {
+	return std::find_if(mParticipants.begin(), mParticipants.end(),
+	                    [&address](const auto &p) { return (address->weakEqual(*p->getAddress())); });
+}
+
+bool ConferenceInfo::hasParticipant(const std::shared_ptr<const Address> &address) const {
+	return (findParticipantIt(address) == mParticipants.end());
+}
+
+const std::shared_ptr<ParticipantInfo>
+ConferenceInfo::findParticipant(const std::shared_ptr<const Address> &address) const {
+	auto it = findParticipantIt(address);
+	if (it != mParticipants.end()) {
+		return *it;
+	};
+	lInfo() << "Unable to find participant with address " << *address << " in conference info " << this << " (address "
+	        << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")";
+	return nullptr;
 }
 
 bool ConferenceInfo::isValidUri() const {
@@ -131,7 +162,7 @@ const std::shared_ptr<Address> &ConferenceInfo::getUri() const {
 	return mUri;
 }
 
-void ConferenceInfo::setUri(const std::shared_ptr<Address> uri) {
+void ConferenceInfo::setUri(const std::shared_ptr<const Address> uri) {
 	mUri = Address::create(uri->getUri());
 }
 
@@ -232,14 +263,17 @@ void ConferenceInfo::updateFrom(const std::shared_ptr<ConferenceInfo> &info) {
 	setIcsSequence(info->getIcsSequence() + 1);
 
 	const auto &participants = info->getParticipants();
-
 	for (auto &participant : mParticipants) {
-		const auto &otherParticipant =
+		const auto &pAddress = participant->getAddress();
+		const auto &otherParticipantIt =
 		    std::find_if(participants.cbegin(), participants.cend(),
-		                 [&participant](const auto &p) { return (p.first == participant.first); });
+		                 [&pAddress](const auto &p) { return (pAddress->weakEqual(*p->getAddress())); });
 
-		if (otherParticipant != participants.cend()) {
-			participant.second = otherParticipant->second;
+		if (otherParticipantIt != participants.cend()) {
+			const auto &otherParticipant = (*otherParticipantIt);
+			// Copy sequence number in order to keep it inceasing.
+			// IF this is not done, the sequence number may be arbitrarly changed and clients could get out of sync
+			participant->setSequenceNumber(otherParticipant->getSequenceNumber());
 		}
 	}
 }
@@ -272,7 +306,7 @@ const string ConferenceInfo::toIcsString(bool cancel, int sequence) const {
 	const auto &organizerAddress = getOrganizerAddress();
 	if (organizerAddress && organizerAddress->isValid()) {
 		const auto uri = organizerAddress->asStringUriOnly();
-		event->setOrganizer(uri, mOrganizer.second);
+		event->setOrganizer(uri, mOrganizer->getAllParameters());
 	}
 
 	event->setSummary(mSubject);
@@ -282,10 +316,11 @@ const string ConferenceInfo::toIcsString(bool cancel, int sequence) const {
 		const auto uri = mUri->asStringUriOnly();
 		event->setXConfUri(uri);
 	}
-	for (const auto &[address, params] : mParticipants) {
+	for (const auto &participantInfo : mParticipants) {
+		const auto &address = participantInfo->getAddress();
 		if (address->isValid()) {
 			const auto uri = address->asStringUriOnly();
-			event->addAttendee(uri, params);
+			event->addAttendee(uri, participantInfo->getAllParameters());
 		}
 	}
 
@@ -330,32 +365,6 @@ void ConferenceInfo::setCreationTime(time_t time) {
 	mCreationTime = time;
 }
 
-const std::string ConferenceInfo::memberParametersToString(const ConferenceInfo::participant_params_t &params) {
-	std::string str;
-	for (const auto &[name, value] : params) {
-		if (!str.empty()) {
-			str.append(";");
-		}
-		str.append(name + "=" + value);
-	}
-	return str;
-}
-
-const ConferenceInfo::participant_params_t ConferenceInfo::stringToMemberParameters(const std::string &paramsString) {
-	ConferenceInfo::participant_params_t params;
-	if (!paramsString.empty()) {
-		const auto &splittedValue = bctoolbox::Utils::split(Utils::trim(paramsString), ";");
-		for (const auto &param : splittedValue) {
-			auto equal = param.find("=");
-			string name = param.substr(0, equal);
-			string value = param.substr(equal + 1, param.size());
-			params.insert(std::make_pair(name, value));
-		}
-	}
-
-	return params;
-}
-
 std::ostream &operator<<(std::ostream &lhs, ConferenceInfo::State s) {
 	switch (s) {
 		case ConferenceInfo::State::New:
diff --git a/src/conference/conference-info.h b/src/conference/conference-info.h
index ba9fdc27ea..2028907888 100644
--- a/src/conference/conference-info.h
+++ b/src/conference/conference-info.h
@@ -28,6 +28,7 @@
 #include <belle-sip/object++.hh>
 
 #include "address/address.h"
+#include "c-wrapper/list-holder.h"
 #include "conference/conference-params-interface.h"
 #include "linphone/api/c-types.h"
 #include "linphone/types.h"
@@ -35,6 +36,8 @@
 // =============================================================================
 
 LINPHONE_BEGIN_NAMESPACE
+
+class ParticipantInfo;
 class LINPHONE_PUBLIC ConferenceInfo : public bellesip::HybridObject<LinphoneConferenceInfo, ConferenceInfo> {
 public:
 	struct AddressCmp {
@@ -43,10 +46,8 @@ public:
 		}
 	};
 
-	static const std::string sequenceParam;
-	using participant_params_t = std::map<std::string, std::string>;
-	using participant_list_t = std::map<std::shared_ptr<Address>, participant_params_t, AddressCmp>;
-	using organizer_t = std::pair<std::shared_ptr<Address>, participant_params_t>;
+	using participant_list_t = std::list<std::shared_ptr<ParticipantInfo>>;
+	using organizer_t = std::shared_ptr<ParticipantInfo>;
 
 	enum class State {
 		New = LinphoneConferenceInfoStateNew,
@@ -60,31 +61,33 @@ public:
 		return new ConferenceInfo(*this);
 	}
 
-	static const std::string memberParametersToString(const participant_params_t &params);
-	static const participant_params_t stringToMemberParameters(const std::string &params);
-
 	const organizer_t &getOrganizer() const;
 	const std::shared_ptr<Address> &getOrganizerAddress() const;
-	void setOrganizer(const std::shared_ptr<Address> &organizer, const participant_params_t &params);
-	void setOrganizer(const std::shared_ptr<Address> &organizer);
-
-	void addOrganizerParam(const std::string &param, const std::string &value);
-	const std::string getOrganizerParam(const std::string &param) const;
+	void setOrganizer(const std::shared_ptr<const ParticipantInfo> &organizer);
+	void setOrganizer(const std::shared_ptr<const Address> &organizer);
 
+	const std::list<std::shared_ptr<Address>> &getParticipantAddressList() const;
+	const bctbx_list_t *getParticipantAddressCList() const;
 	const participant_list_t &getParticipants() const;
+	const bctbx_list_t *getParticipantsCList() const;
+
+	void setParticipants(const std::list<std::shared_ptr<Address>> &participants);
 	void setParticipants(const participant_list_t &participants);
-	void addParticipant(const std::shared_ptr<Address> &participant);
-	void addParticipant(const std::shared_ptr<Address> &participant, const participant_params_t &params);
-	void removeParticipant(const std::shared_ptr<Address> &participant);
 
-	void addParticipantParam(const std::shared_ptr<Address> &participant,
-	                         const std::string &param,
-	                         const std::string &value);
-	const std::string getParticipantParam(const std::shared_ptr<Address> &participant, const std::string &param) const;
+	void addParticipant(const std::shared_ptr<const Address> &participant);
+	void addParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo);
+
+	void removeParticipant(const std::shared_ptr<const Address> &participant);
+	void removeParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo);
+
+	bool hasParticipant(const std::shared_ptr<const Address> &address) const;
+	const std::shared_ptr<ParticipantInfo> findParticipant(const std::shared_ptr<const Address> &address) const;
+
+	void updateParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo);
 
 	bool isValidUri() const;
 	const std::shared_ptr<Address> &getUri() const;
-	void setUri(const std::shared_ptr<Address> uri);
+	void setUri(const std::shared_ptr<const Address> uri);
 
 	time_t getDateTime() const;
 	void setDateTime(time_t dateTime);
@@ -124,8 +127,14 @@ public:
 	void setCreationTime(time_t time);
 
 private:
+	void updateParticipantAddresses() const;
+	participant_list_t::const_iterator findParticipantIt(const std::shared_ptr<const Address> &address) const;
+
 	organizer_t mOrganizer;
+	mutable std::shared_ptr<Address> mOrganizerAddress;
 	participant_list_t mParticipants;
+	mutable ListHolder<Address> mParticipantAddresses;
+	mutable ListHolder<ParticipantInfo> mParticipantList;
 	std::shared_ptr<Address> mUri;
 	time_t mDateTime = (time_t)-1;
 	unsigned int mDuration = 0;
diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h
index 6304531fa9..e2c28568e7 100644
--- a/src/conference/conference-interface.h
+++ b/src/conference/conference-interface.h
@@ -119,10 +119,10 @@ public:
 	virtual const std::string &getSubject() const = 0;
 
 	/*
-	* Get the subject of this conference
-	* @return The subject of the chat room in UTF8
-	*/
-	virtual const std::string &getUtf8Subject () const = 0;
+	 * Get the subject of this conference
+	 * @return The subject of the chat room in UTF8
+	 */
+	virtual const std::string &getUtf8Subject() const = 0;
 
 	/*
 	 * Set the subject of this conference. If not focus,  this operation is only available if the local participant
diff --git a/src/conference/conference-scheduler.cpp b/src/conference/conference-scheduler.cpp
index fc1e9900ba..d9f2990dda 100644
--- a/src/conference/conference-scheduler.cpp
+++ b/src/conference/conference-scheduler.cpp
@@ -23,8 +23,9 @@
 #include "account/account.h"
 #include "c-wrapper/c-wrapper.h"
 #include "chat/chat-message/chat-message-p.h"
-#include "conference-scheduler.h"
+#include "conference/conference-scheduler.h"
 #include "conference/params/call-session-params-p.h"
+#include "conference/participant-info.h"
 #include "conference/session/media-session.h"
 #include "content/file-content.h"
 #include "core/core-p.h"
@@ -85,21 +86,19 @@ const std::shared_ptr<ConferenceInfo> ConferenceScheduler::getInfo() const {
 void ConferenceScheduler::fillCancelList(const ConferenceInfo::participant_list_t &oldList,
                                          const ConferenceInfo::participant_list_t &newList) {
 	mCancelToSend.clear();
-	for (const auto &participant : oldList) {
-		const bool participantFound = (std::find_if(newList.cbegin(), newList.cend(), [&participant](const auto &e) {
-			                               return (e.first->weakEqual(*participant.first));
-		                               }) != newList.cend());
+	for (const auto &oldParticipantInfo : oldList) {
+		const auto &address = oldParticipantInfo->getAddress();
+		// Workaroud for CLang issue: https://github.com/llvm/llvm-project/issues/52720
+		const bool participantFound =
+		    (std::find_if(newList.cbegin(), newList.cend(), [&address = address](const auto &e) {
+			     return (address->weakEqual(*e->getAddress()));
+		     }) != newList.cend());
 		if (!participantFound) {
-			auto sequence = -1;
-			try {
-				const auto params = participant.second;
-				const auto &value = params.at(ConferenceInfo::sequenceParam);
-				if (!value.empty()) {
-					sequence = std::atoi(value.c_str()) + 1;
-				}
-			} catch (std::out_of_range &) {
+			auto sequence = oldParticipantInfo->getSequenceNumber();
+			if (sequence >= 0) {
+				sequence++;
 			}
-			mCancelToSend.insert(std::make_pair(participant.first, sequence));
+			mCancelToSend.insert(std::make_pair(address, sequence));
 		}
 	}
 }
@@ -109,13 +108,21 @@ void ConferenceScheduler::cancelConference(const std::shared_ptr<ConferenceInfo>
 		auto clone = info->clone()->toSharedPtr();
 		while (!clone->getParticipants().empty()) {
 			const auto &participants = clone->getParticipants();
-			const auto &participant = *(participants.begin());
-			clone->removeParticipant(participant.first);
+			clone->removeParticipant(*(participants.begin()));
 		}
 		setInfo(clone);
 	}
 }
 
+std::shared_ptr<Address>
+ConferenceScheduler::createParticipantAddress(const ConferenceInfo::participant_list_t::value_type &p) const {
+	std::shared_ptr<Address> address = Address::create(p->getAddress()->getUri());
+	for (const auto &[name, value] : p->getAllParameters()) {
+		address->setParam(name, value);
+	}
+	return address;
+}
+
 void ConferenceScheduler::setInfo(const std::shared_ptr<ConferenceInfo> &info) {
 	if (!info) {
 		lWarning() << "[Conference Scheduler] [" << this
@@ -146,7 +153,7 @@ void ConferenceScheduler::setInfo(const std::shared_ptr<ConferenceInfo> &info) {
 	const auto &participants = clone->getParticipants();
 	const auto participantListEmpty = participants.empty();
 	const bool participantFound = (std::find_if(participants.cbegin(), participants.cend(), [&creator](const auto &p) {
-		                               return (creator->weakEqual(*(p.first)));
+		                               return (creator->weakEqual(*p->getAddress()));
 	                               }) != participants.cend());
 	if (!creator->weakEqual(*organizer) && !participantFound) {
 		lWarning() << "[Conference Scheduler] [" << this << "] Address " << creator->toString()
@@ -232,7 +239,7 @@ void ConferenceScheduler::setInfo(const std::shared_ptr<ConferenceInfo> &info) {
 
 	std::list<std::shared_ptr<Address>> invitees;
 	for (const auto &p : mConferenceInfo->getParticipants()) {
-		invitees.push_back(p.first);
+		invitees.push_back(createParticipantAddress(p));
 	}
 
 	if (isUpdate) {
@@ -353,10 +360,9 @@ void ConferenceScheduler::onCallSessionSetTerminated(const shared_ptr<CallSessio
 			// Participant with the focus call is admin
 			L_GET_CPP_PTR_FROM_C_OBJECT(new_params)->addCustomContactParameter("admin", Utils::toString(true));
 			std::list<std::shared_ptr<Address>> addressesList;
-			for (const auto &p : mConferenceInfo->getParticipants()) {
-				addressesList.push_back(p.first);
+			for (const auto &participantInfo : mConferenceInfo->getParticipants()) {
+				addressesList.push_back(participantInfo->getAddress());
 			}
-
 			addressesList.sort([](const auto &addr1, const auto &addr2) { return *addr1 < *addr2; });
 			addressesList.unique([](const auto &addr1, const auto &addr2) { return addr1->weakEqual(*addr2); });
 
@@ -374,8 +380,8 @@ void ConferenceScheduler::onCallSessionSetTerminated(const shared_ptr<CallSessio
 			LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(getCore()->getCCore());
 			bool_t initiate_video = !!linphone_video_activation_policy_get_automatically_initiate(pol);
 			linphone_call_params_enable_video(
-				new_params,
-				static_pointer_cast<MediaSession>(session)->getMediaParams()->videoEnabled() && initiate_video);
+			    new_params,
+			    static_pointer_cast<MediaSession>(session)->getMediaParams()->videoEnabled() && initiate_video);
 			linphone_video_activation_policy_unref(pol);
 
 			linphone_core_invite_address_with_params_2(getCore()->getCCore(), remoteAddress->toC(), new_params,
@@ -415,10 +421,9 @@ shared_ptr<ChatMessage> ConferenceScheduler::createInvitationChatMessage(shared_
 		    std::find_if(mCancelToSend.cbegin(), mCancelToSend.cend(),
 		                 [&participant](const auto &p) { return (participant->weakEqual(*p.first)); });
 		if (cancelParticipant == mCancelToSend.cend()) {
-			const auto participantSequence =
-			    mConferenceInfo->getParticipantParam(participant, ConferenceInfo::sequenceParam);
-			if (!participantSequence.empty()) {
-				sequence = std::atoi(participantSequence.c_str());
+			const auto &participantInfo = mConferenceInfo->findParticipant(participant);
+			if (participantInfo) {
+				sequence = participantInfo->getSequenceNumber();
 			}
 		} else {
 			sequence = (*cancelParticipant).second;
@@ -467,12 +472,12 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 
 	const auto &participants = mConferenceInfo->getParticipants();
 	const bool participantFound = (std::find_if(participants.cbegin(), participants.cend(), [&sender](const auto &p) {
-		                               return (sender->weakEqual(*p.first));
+		                               return (sender->weakEqual(*p->getAddress()));
 	                               }) != participants.cend());
-	const auto &organizer = mConferenceInfo->getOrganizerAddress();
+	const auto organizer = mConferenceInfo->getOrganizerAddress();
 	if (!sender->weakEqual(*organizer) && !participantFound) {
-		lWarning() << "[Conference Scheduler] [" << this << "] Unable to find the address " << sender
-		           << " sending invitations among the list of participants or the organizer (" << organizer
+		lWarning() << "[Conference Scheduler] [" << this << "] Unable to find the address " << *sender
+		           << " sending invitations among the list of participants or the organizer (" << *organizer
 		           << ") of conference " << *mConferenceInfo->getUri();
 		return;
 	}
@@ -489,12 +494,20 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 	}
 
 	std::list<std::shared_ptr<Address>> invitees;
-	for (const auto &p : participants) {
-		invitees.push_back(p.first);
+	for (const auto &participantInfo : participants) {
+		invitees.push_back(participantInfo->getAddress());
 	}
-	for (const auto &p : mCancelToSend) {
-		invitees.push_back(p.first);
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?format=multiple&id=81767
+#if __GNUC__ == 7
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif //  __GNUC__ == 7
+	for (const auto &[address, value] : mCancelToSend) {
+		invitees.push_back(address);
 	}
+#if __GNUC__ == 7
+#pragma GCC diagnostic pop
+#endif //  __GNUC__ == 7
 
 	mInvitationsToSend.clear();
 	for (auto participant : invitees) {
@@ -505,14 +518,24 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 			        << "] from chat room participants as it is ourselves";
 		}
 
-		const std::string &sequence = mConferenceInfo->getParticipantParam(participant, ConferenceInfo::sequenceParam);
-		const int newSequence = (sequence.empty()) ? 0 : std::atoi(sequence.c_str()) + 1;
-		mConferenceInfo->addParticipantParam(participant, ConferenceInfo::sequenceParam, std::to_string(newSequence));
+		const auto &participantInfo = mConferenceInfo->findParticipant(participant);
+		if (participantInfo) {
+			auto newParticipantInfo = participantInfo->clone()->toSharedPtr();
+			const auto &sequence = newParticipantInfo->getSequenceNumber();
+			const auto newSequence = (sequence < 0) ? 0 : sequence + 1;
+			newParticipantInfo->setSequenceNumber(newSequence);
+			mConferenceInfo->updateParticipant(newParticipantInfo);
+		}
 	}
 
-	const std::string &organizerSequence = mConferenceInfo->getOrganizerParam(ConferenceInfo::sequenceParam);
-	const int newOrganizerSequence = (organizerSequence.empty()) ? 0 : std::atoi(organizerSequence.c_str()) + 1;
-	mConferenceInfo->addOrganizerParam(ConferenceInfo::sequenceParam, std::to_string(newOrganizerSequence));
+	const auto &organizerInfo = mConferenceInfo->getOrganizer();
+	if (organizerInfo) {
+		auto newOrganizerInfo = organizerInfo->clone()->toSharedPtr();
+		const auto &sequence = newOrganizerInfo->getSequenceNumber();
+		const auto newSequence = (sequence < 0) ? 0 : sequence + 1;
+		newOrganizerInfo->setSequenceNumber(newSequence);
+		mConferenceInfo->setOrganizer(newOrganizerInfo);
+	}
 
 	if (!sender->weakEqual(*organizer)) {
 		const bool organizerFound =
diff --git a/src/conference/conference-scheduler.h b/src/conference/conference-scheduler.h
index b3365820a4..7a5290070e 100644
--- a/src/conference/conference-scheduler.h
+++ b/src/conference/conference-scheduler.h
@@ -80,6 +80,7 @@ private:
 	void setState(State newState);
 	std::string stateToString(State state);
 
+	std::shared_ptr<Address> createParticipantAddress(const ConferenceInfo::participant_list_t::value_type &p) const;
 	std::shared_ptr<ChatMessage> createInvitationChatMessage(std::shared_ptr<AbstractChatRoom> chatRoom,
 	                                                         const std::shared_ptr<Address> participant,
 	                                                         bool cancel);
diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp
index fa7d368c91..0cf6a1a25e 100644
--- a/src/conference/conference.cpp
+++ b/src/conference/conference.cpp
@@ -23,6 +23,7 @@
 #include "conference.h"
 #include "conference/params/media-session-params-p.h"
 #include "conference/participant-device.h"
+#include "conference/participant-info.h"
 #include "conference/session/call-session-p.h"
 #include "conference/session/media-session.h"
 #include "content/content-disposition.h"
@@ -715,22 +716,14 @@ std::shared_ptr<ConferenceInfo> Conference::createConferenceInfo() const {
 	return nullptr;
 }
 
-std::shared_ptr<ConferenceInfo>
-Conference::createConferenceInfoWithOrganizer(const std::shared_ptr<Address> &organizer) const {
-	// Add participants that are currently in the conference
-	std::list<std::shared_ptr<Address>> participantAddresses;
-	for (const auto &p : getParticipants()) {
-		const auto &pAddress = p->getAddress();
-		participantAddresses.push_back(pAddress);
-	}
-
-	return createConferenceInfoWithCustomParticipantList(organizer, participantAddresses);
-}
-
 std::shared_ptr<ConferenceInfo> Conference::createConferenceInfoWithCustomParticipantList(
-    const std::shared_ptr<Address> &organizer, const std::list<std::shared_ptr<Address>> invitedParticipants) const {
+    const std::shared_ptr<Address> &organizer, const ConferenceInfo::participant_list_t invitedParticipants) const {
 	std::shared_ptr<ConferenceInfo> info = ConferenceInfo::create();
-	info->setOrganizer(organizer);
+	auto organizerInfo = ParticipantInfo::create(Address::create(organizer->getUri()));
+	for (const auto &[name, value] : organizer->getParams()) {
+		organizerInfo->addParameter(name, value);
+	}
+	info->setOrganizer(organizerInfo);
 	for (const auto &participant : invitedParticipants) {
 		info->addParticipant(participant);
 	}
@@ -823,9 +816,9 @@ void Conference::updateParticipantsInConferenceInfo(const std::shared_ptr<Addres
 		auto info = createOrGetConferenceInfo();
 		if (info) {
 			const auto &currentParticipants = info->getParticipants();
-			const auto participantAddressIt =
-			    std::find_if(currentParticipants.begin(), currentParticipants.end(),
-			                 [&participantAddress](const auto &p) { return (*p.first == *participantAddress); });
+			const auto participantAddressIt = std::find_if(
+			    currentParticipants.begin(), currentParticipants.end(),
+			    [&participantAddress](const auto &p) { return (participantAddress->weakEqual(*p->getAddress())); });
 			if (participantAddressIt == currentParticipants.end()) {
 				info->addParticipant(participantAddress);
 
diff --git a/src/conference/conference.h b/src/conference/conference.h
index ec346119b4..2f19adba71 100644
--- a/src/conference/conference.h
+++ b/src/conference/conference.h
@@ -247,9 +247,7 @@ protected:
 	virtual std::shared_ptr<ConferenceInfo> createConferenceInfo() const;
 	virtual std::shared_ptr<ConferenceInfo>
 	createConferenceInfoWithCustomParticipantList(const std::shared_ptr<Address> &organizer,
-	                                              const std::list<std::shared_ptr<Address>> invitedParticipants) const;
-	virtual std::shared_ptr<ConferenceInfo>
-	createConferenceInfoWithOrganizer(const std::shared_ptr<Address> &organizer) const;
+	                                              const ConferenceInfo::participant_list_t invitedParticipants) const;
 
 private:
 	L_DISABLE_COPY(Conference);
diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp
index dbb13b371c..b0e5b81406 100644
--- a/src/conference/handlers/local-conference-event-handler.cpp
+++ b/src/conference/handlers/local-conference-event-handler.cpp
@@ -195,6 +195,7 @@ Content LocalConferenceEventHandler::createNotifyFullState(const shared_ptr<Even
 		user.setEndpoint(endpoints);
 		user.setEntity(participant->getAddress()->asStringUriOnly());
 		user.getRoles()->getEntry().push_back(participant->isAdmin() ? "admin" : "participant");
+		user.getRoles()->getEntry().push_back(Participant::roleToText(participant->getRole()));
 		user.setState(StateType::full);
 
 		for (const auto &device : participant->getDevices()) {
@@ -539,6 +540,9 @@ string LocalConferenceEventHandler::createNotifyParticipantAdded(const std::shar
 	user.setRoles(roles);
 	user.setEntity(pAddress->asStringUriOnly());
 	user.getRoles()->getEntry().push_back((participant && participant->isAdmin()) ? "admin" : "participant");
+	if (participant) {
+		user.getRoles()->getEntry().push_back(Participant::roleToText(participant->getRole()));
+	}
 	user.setState(StateType::full);
 
 	confInfo.getUsers()->getUser().push_back(user);
diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp
index 2b61c78842..4d9c980f5b 100644
--- a/src/conference/handlers/remote-conference-event-handler.cpp
+++ b/src/conference/handlers/remote-conference-event-handler.cpp
@@ -324,18 +324,26 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 
 			auto &roles = user.getRoles();
 			if (roles) {
-
 				auto &entry = roles->getEntry();
-				bool isAdmin = (find(entry, "admin") != entry.end() ? true : false);
 
+				// Admin
+				bool isAdmin = (find(entry, "admin") != entry.end() ? true : false);
 				if (participant->isAdmin() != isAdmin) {
-
 					participant->setAdmin(isAdmin);
-
 					if (!isFullState) {
 						conf->notifyParticipantSetAdmin(creationTime, isFullState, participant, isAdmin);
 					}
 				}
+
+				// Role
+				bool isSpeaker = (find(entry, "speaker") != entry.end() ? true : false);
+				bool isListener = (find(entry, "listener") != entry.end() ? true : false);
+				if (isListener) {
+					participant->setRole(Participant::Role::Listener);
+				} else if (isSpeaker || (state == StateType::full)) {
+					// When a participant is added, then set its role to speaker by default to be backward compatible
+					participant->setRole(Participant::Role::Speaker);
+				}
 			}
 
 			for (const auto &endpoint : user.getEndpoint()) {
@@ -425,7 +433,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 					                        }
 					                    }
 					*/
-					bool mediaCapabilityChanged = false;
+					std::set<LinphoneStreamType> mediaCapabilityChanged;
 					for (const auto &media : endpoint.getMedia()) {
 						const std::string mediaType = media.getType().get();
 						LinphoneStreamType streamType = LinphoneStreamTypeUnknown;
@@ -441,7 +449,9 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 
 						LinphoneMediaDirection mediaDirection =
 						    RemoteConferenceEventHandler::mediaStatusToMediaDirection(media.getStatus().get());
-						mediaCapabilityChanged |= device->setStreamCapability(mediaDirection, streamType);
+						if (device->setStreamCapability(mediaDirection, streamType)) {
+							mediaCapabilityChanged.insert(streamType);
+						}
 						if (media.getLabel()) {
 							const std::string label = media.getLabel().get();
 							if (!label.empty()) {
@@ -459,19 +469,19 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 						}
 					}
 
-					bool mediaAvailabilityChanged = device->updateStreamAvailabilities();
+					auto mediaAvailabilityChanged = device->updateStreamAvailabilities();
 					// Do not notify availability changed during full states and participant addition because it is
 					// already done by the listener method onFullStateReceived
 					if (!isFullState && (state != StateType::full) &&
 					    (previousDeviceState != ParticipantDevice::State::ScheduledForJoining) &&
 					    (previousDeviceState != ParticipantDevice::State::Joining) &&
 					    (previousDeviceState != ParticipantDevice::State::Alerting)) {
-						if (mediaAvailabilityChanged) {
+						if (!mediaAvailabilityChanged.empty()) {
 							conf->notifyParticipantDeviceMediaAvailabilityChanged(creationTime, isFullState,
 							                                                      participant, device);
 						}
 
-						if (mediaCapabilityChanged) {
+						if (!mediaCapabilityChanged.empty()) {
 							conf->notifyParticipantDeviceMediaCapabilityChanged(creationTime, isFullState, participant,
 							                                                    device);
 						}
diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp
index 724088abec..1f3a49d6b4 100644
--- a/src/conference/participant-device.cpp
+++ b/src/conference/participant-device.cpp
@@ -429,10 +429,14 @@ LinphoneMediaDirection ParticipantDevice::computeDeviceMediaDirection(const bool
 	return LinphoneMediaDirectionInactive;
 }
 
-bool ParticipantDevice::updateMediaCapabilities() {
-	bool mediaCapabilityChanged = false;
+std::set<LinphoneStreamType> ParticipantDevice::updateMediaCapabilities() {
+	std::set<LinphoneStreamType> mediaCapabilityChanged;
 	const auto &conference = getConference();
 
+	auto resultAudioDir = LinphoneMediaDirectionInactive;
+	auto resultVideoDir = LinphoneMediaDirectionInactive;
+	auto resultTextDir = LinphoneMediaDirectionInactive;
+
 	if (conference) {
 		const auto &isMe = conference->isMe(getAddress());
 		const auto &conferenceParams = conference->getCurrentParams();
@@ -485,26 +489,42 @@ bool ParticipantDevice::updateMediaCapabilities() {
 
 			if (mSession->getPrivate()->isInConference()) {
 				const auto audioSsrc = mMediaSession->getSsrc(LinphoneStreamTypeAudio);
-				mediaCapabilityChanged |= setSsrc(LinphoneStreamTypeAudio, audioSsrc);
+				if (setSsrc(LinphoneStreamTypeAudio, audioSsrc)) {
+					mediaCapabilityChanged.insert(LinphoneStreamTypeAudio);
+				}
 
 				const auto videoSsrc = mMediaSession->getSsrc(LinphoneStreamTypeVideo);
-				mediaCapabilityChanged |= setSsrc(LinphoneStreamTypeVideo, videoSsrc);
+				if (setSsrc(LinphoneStreamTypeVideo, videoSsrc)) {
+					mediaCapabilityChanged.insert(LinphoneStreamTypeVideo);
+				}
 			}
 		}
-		mediaCapabilityChanged |= setStreamCapability(
-		    computeDeviceMediaDirection(conferenceAudioEnabled, audioEnabled, audioDir), LinphoneStreamTypeAudio);
-		mediaCapabilityChanged |= setStreamCapability(
-		    computeDeviceMediaDirection(conferenceVideoEnabled, videoEnabled, videoDir), LinphoneStreamTypeVideo);
-		mediaCapabilityChanged |= setStreamCapability(
-		    computeDeviceMediaDirection(conferenceTextEnabled, textEnabled, textDir), LinphoneStreamTypeText);
+		resultAudioDir = computeDeviceMediaDirection(conferenceAudioEnabled, audioEnabled, audioDir);
+		resultVideoDir = computeDeviceMediaDirection(conferenceVideoEnabled, videoEnabled, videoDir);
+		resultTextDir = computeDeviceMediaDirection(conferenceTextEnabled, textEnabled, textDir);
 	} else {
-		mediaCapabilityChanged |= setStreamCapability(LinphoneMediaDirectionInactive, LinphoneStreamTypeAudio);
-		mediaCapabilityChanged |= setStreamCapability(LinphoneMediaDirectionInactive, LinphoneStreamTypeVideo);
-		mediaCapabilityChanged |= setStreamCapability(LinphoneMediaDirectionInactive, LinphoneStreamTypeText);
-		mediaCapabilityChanged |= setSsrc(LinphoneStreamTypeAudio, 0);
-		mediaCapabilityChanged |= setSsrc(LinphoneStreamTypeVideo, 0);
+		if (setSsrc(LinphoneStreamTypeAudio, 0)) {
+			mediaCapabilityChanged.insert(LinphoneStreamTypeAudio);
+		}
+
+		if (setSsrc(LinphoneStreamTypeVideo, 0)) {
+			mediaCapabilityChanged.insert(LinphoneStreamTypeVideo);
+		}
+
+		resultAudioDir = LinphoneMediaDirectionInactive;
+		resultVideoDir = LinphoneMediaDirectionInactive;
+		resultTextDir = LinphoneMediaDirectionInactive;
 	}
 
+	if (setStreamCapability(resultAudioDir, LinphoneStreamTypeAudio)) {
+		mediaCapabilityChanged.insert(LinphoneStreamTypeAudio);
+	}
+	if (setStreamCapability(resultVideoDir, LinphoneStreamTypeVideo)) {
+		mediaCapabilityChanged.insert(LinphoneStreamTypeVideo);
+	}
+	if (setStreamCapability(resultTextDir, LinphoneStreamTypeText)) {
+		mediaCapabilityChanged.insert(LinphoneStreamTypeText);
+	}
 	return mediaCapabilityChanged;
 }
 
@@ -515,9 +535,9 @@ bool ParticipantDevice::computeStreamAvailable(const bool conferenceEnable,
 	return ((resultDir == LinphoneMediaDirectionSendOnly) || (resultDir == LinphoneMediaDirectionSendRecv));
 }
 
-bool ParticipantDevice::updateStreamAvailabilities() {
+std::set<LinphoneStreamType> ParticipantDevice::updateStreamAvailabilities() {
 	const auto &conference = getConference();
-	auto streamAvailabilityChanged = false;
+	std::set<LinphoneStreamType> streamAvailabilityChanged;
 
 	const auto session = getSession() ? getSession() : (conference ? conference->getMainSession() : nullptr);
 	if (conference) {
@@ -526,20 +546,14 @@ bool ParticipantDevice::updateStreamAvailabilities() {
 		const auto &conferenceVideoEnabled = conferenceParams.videoEnabled();
 		const auto &conferenceTextEnabled = conferenceParams.chatEnabled();
 		if (session) {
+			auto audioEnabled = false;
+			auto videoEnabled = false;
+			auto textEnabled = false;
 			if (session->getPrivate()->isInConference() && conferenceParams.localParticipantEnabled()) {
 				if (conference->isMe(getAddress())) {
-					streamAvailabilityChanged |=
-					    setStreamAvailability(computeStreamAvailable(conferenceAudioEnabled, conferenceAudioEnabled,
-					                                                 getStreamCapability(LinphoneStreamTypeAudio)),
-					                          LinphoneStreamTypeAudio);
-					streamAvailabilityChanged |=
-					    setStreamAvailability(computeStreamAvailable(conferenceVideoEnabled, conferenceVideoEnabled,
-					                                                 getStreamCapability(LinphoneStreamTypeVideo)),
-					                          LinphoneStreamTypeVideo);
-					streamAvailabilityChanged |=
-					    setStreamAvailability(computeStreamAvailable(conferenceTextEnabled, conferenceTextEnabled,
-					                                                 getStreamCapability(LinphoneStreamTypeText)),
-					                          LinphoneStreamTypeText);
+					audioEnabled = conferenceAudioEnabled;
+					videoEnabled = conferenceVideoEnabled;
+					textEnabled = conferenceTextEnabled;
 				} else {
 					std::shared_ptr<ParticipantDevice> meDev = nullptr;
 					if (conferenceParams.getAccount()) {
@@ -548,24 +562,12 @@ bool ParticipantDevice::updateStreamAvailabilities() {
 							meDev = conference->getMe()->findDevice(devAddr);
 						}
 					}
-					auto audioEnabled =
+					audioEnabled =
 					    (meDev) ? meDev->getStreamAvailability(LinphoneStreamTypeAudio) : conferenceAudioEnabled;
-					auto videoEnabled =
+					videoEnabled =
 					    (meDev) ? meDev->getStreamAvailability(LinphoneStreamTypeVideo) : conferenceVideoEnabled;
-					auto textEnabled =
+					textEnabled =
 					    (meDev) ? meDev->getStreamAvailability(LinphoneStreamTypeText) : conferenceTextEnabled;
-					streamAvailabilityChanged |=
-					    setStreamAvailability(computeStreamAvailable(conferenceAudioEnabled, audioEnabled,
-					                                                 getStreamCapability(LinphoneStreamTypeAudio)),
-					                          LinphoneStreamTypeAudio);
-					streamAvailabilityChanged |=
-					    setStreamAvailability(computeStreamAvailable(conferenceVideoEnabled, videoEnabled,
-					                                                 getStreamCapability(LinphoneStreamTypeVideo)),
-					                          LinphoneStreamTypeVideo);
-					streamAvailabilityChanged |=
-					    setStreamAvailability(computeStreamAvailable(conferenceTextEnabled, textEnabled,
-					                                                 getStreamCapability(LinphoneStreamTypeText)),
-					                          LinphoneStreamTypeText);
 				}
 			} else {
 				// A conference server is a passive element, therefore it may happen that the negotiated capabilities
@@ -575,42 +577,43 @@ bool ParticipantDevice::updateStreamAvailabilities() {
 				const MediaSessionParams *params = (session->getPrivate()->isInConference())
 				                                       ? static_pointer_cast<MediaSession>(session)->getRemoteParams()
 				                                       : static_pointer_cast<MediaSession>(session)->getMediaParams();
-
-				auto audioEnabled = false;
-				auto videoEnabled = false;
-				auto textEnabled = false;
 				if (params) {
 					audioEnabled = params->audioEnabled();
 					videoEnabled = params->videoEnabled();
 					textEnabled = params->realtimeTextEnabled();
 				}
-
-				streamAvailabilityChanged |=
-				    setStreamAvailability(computeStreamAvailable(conferenceAudioEnabled, audioEnabled,
-				                                                 getStreamCapability(LinphoneStreamTypeAudio)),
-				                          LinphoneStreamTypeAudio);
-				streamAvailabilityChanged |=
-				    setStreamAvailability(computeStreamAvailable(conferenceVideoEnabled, videoEnabled,
-				                                                 getStreamCapability(LinphoneStreamTypeVideo)),
-				                          LinphoneStreamTypeVideo);
-				streamAvailabilityChanged |=
-				    setStreamAvailability(computeStreamAvailable(conferenceTextEnabled, textEnabled,
-				                                                 getStreamCapability(LinphoneStreamTypeText)),
-				                          LinphoneStreamTypeText);
+			}
+			if (setStreamAvailability(computeStreamAvailable(conferenceAudioEnabled, audioEnabled,
+			                                                 getStreamCapability(LinphoneStreamTypeAudio)),
+			                          LinphoneStreamTypeAudio)) {
+				streamAvailabilityChanged.insert(LinphoneStreamTypeAudio);
+			}
+			if (setStreamAvailability(computeStreamAvailable(conferenceVideoEnabled, videoEnabled,
+			                                                 getStreamCapability(LinphoneStreamTypeVideo)),
+			                          LinphoneStreamTypeVideo)) {
+				streamAvailabilityChanged.insert(LinphoneStreamTypeVideo);
+			}
+			if (setStreamAvailability(computeStreamAvailable(conferenceTextEnabled, textEnabled,
+			                                                 getStreamCapability(LinphoneStreamTypeText)),
+			                          LinphoneStreamTypeText)) {
+				streamAvailabilityChanged.insert(LinphoneStreamTypeText);
 			}
 		} else if (conference->isMe(getAddress()) && conferenceParams.localParticipantEnabled()) {
-			streamAvailabilityChanged |=
-			    setStreamAvailability(computeStreamAvailable(conferenceAudioEnabled, conferenceAudioEnabled,
+			if (setStreamAvailability(computeStreamAvailable(conferenceAudioEnabled, conferenceAudioEnabled,
 			                                                 getStreamCapability(LinphoneStreamTypeAudio)),
-			                          LinphoneStreamTypeAudio);
-			streamAvailabilityChanged |=
-			    setStreamAvailability(computeStreamAvailable(conferenceVideoEnabled, conferenceVideoEnabled,
+			                          LinphoneStreamTypeAudio)) {
+				streamAvailabilityChanged.insert(LinphoneStreamTypeAudio);
+			}
+			if (setStreamAvailability(computeStreamAvailable(conferenceVideoEnabled, conferenceVideoEnabled,
 			                                                 getStreamCapability(LinphoneStreamTypeVideo)),
-			                          LinphoneStreamTypeVideo);
-			streamAvailabilityChanged |=
-			    setStreamAvailability(computeStreamAvailable(conferenceTextEnabled, conferenceTextEnabled,
+			                          LinphoneStreamTypeVideo)) {
+				streamAvailabilityChanged.insert(LinphoneStreamTypeVideo);
+			}
+			if (setStreamAvailability(computeStreamAvailable(conferenceTextEnabled, conferenceTextEnabled,
 			                                                 getStreamCapability(LinphoneStreamTypeText)),
-			                          LinphoneStreamTypeText);
+			                          LinphoneStreamTypeText)) {
+				streamAvailabilityChanged.insert(LinphoneStreamTypeText);
+			}
 		}
 	}
 
diff --git a/src/conference/participant-device.h b/src/conference/participant-device.h
index a0e27cd9df..ca6947bde8 100644
--- a/src/conference/participant-device.h
+++ b/src/conference/participant-device.h
@@ -22,6 +22,7 @@
 #define _L_PARTICIPANT_DEVICE_H_
 
 #include <ctime>
+#include <set>
 #include <string>
 
 #include <belle-sip/object++.hh>
@@ -50,9 +51,8 @@ class Participant;
 class ParticipantDeviceCbs;
 
 class LINPHONE_PUBLIC ParticipantDevice : public bellesip::HybridObject<LinphoneParticipantDevice, ParticipantDevice>,
-                          public UserDataAccessor,
-                          public CallbacksHolder<ParticipantDeviceCbs>
-                           {
+                                          public UserDataAccessor,
+                                          public CallbacksHolder<ParticipantDeviceCbs> {
 public:
 	enum class State {
 		Joining = LinphoneParticipantDeviceStateJoining,
@@ -172,17 +172,18 @@ public:
 	void *getUserData() const;
 	void setUserData(void *ud);
 
-	// Media getters and setters
-	bool updateMediaCapabilities();
-	bool updateStreamAvailabilities();
+	std::set<LinphoneStreamType> updateMediaCapabilities();
+	std::set<LinphoneStreamType> updateStreamAvailabilities();
 
 	bool adminModeSupported() const;
 	void enableAdminModeSupport(bool support);
 
+	// Media getters and setters
 	void *createWindowId() const;
 	void setWindowId(void *newWindowId);
 	void *getWindowId() const;
 
+	// Media getters and setters
 	bool setLabel(const std::string &label, const LinphoneStreamType type);
 	const std::string &getLabel(const LinphoneStreamType type) const;
 
diff --git a/src/conference/participant-info.cpp b/src/conference/participant-info.cpp
new file mode 100644
index 0000000000..09ec6728e3
--- /dev/null
+++ b/src/conference/participant-info.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2010-2023 Belledonne Communications SARL.
+ *
+ * This file is part of Liblinphone
+ * (see https://gitlab.linphone.org/BC/public/liblinphone).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "participant-info.h"
+#include "address/address.h"
+
+using namespace std;
+
+LINPHONE_BEGIN_NAMESPACE
+
+const std::string ParticipantInfo::sequenceParameter = "X-SEQ";
+const std::string ParticipantInfo::roleParameter = "X-ROLE";
+
+ParticipantInfo::ParticipantInfo(const std::shared_ptr<Address> &address) {
+	mAddress = Address::create(address->getUri());
+}
+
+ParticipantInfo::~ParticipantInfo() {
+}
+
+ParticipantInfo *ParticipantInfo::clone() const {
+	return new ParticipantInfo(*this);
+}
+
+ParticipantInfo::ParticipantInfo(const ParticipantInfo &other) : HybridObject(other) {
+	mAddress = other.mAddress;
+	mRole = other.mRole;
+	mSequence = other.mSequence;
+	mParameters = other.mParameters;
+}
+
+const std::shared_ptr<Address> &ParticipantInfo::getAddress() const {
+	return mAddress;
+}
+
+void ParticipantInfo::setRole(Participant::Role role) {
+	mRole = role;
+};
+
+Participant::Role ParticipantInfo::getRole() const {
+	return mRole;
+};
+
+void ParticipantInfo::setSequenceNumber(const int &nb) {
+	mSequence = nb;
+};
+
+const int &ParticipantInfo::getSequenceNumber() const {
+	return mSequence;
+};
+
+void ParticipantInfo::setParameters(const ParticipantInfo::participant_params_t &params) {
+	mParameters.clear();
+	addParameters(params);
+}
+
+void ParticipantInfo::addParameter(const std::string &name, const std::string &value) {
+	if (name.compare(ParticipantInfo::sequenceParameter) == 0) {
+		setSequenceNumber(std::stoi(value));
+	} else if (name.compare(ParticipantInfo::roleParameter) == 0) {
+		setRole(Participant::textToRole(value));
+	} else {
+		mParameters[name] = value;
+	}
+}
+
+void ParticipantInfo::addParameters(const ParticipantInfo::participant_params_t &params) {
+	for (const auto &[name, value] : params) {
+		addParameter(name, value);
+	}
+}
+
+bool ParticipantInfo::hasParameter(const std::string &name) const {
+	return (mParameters.find(name) == mParameters.end());
+}
+
+const std::string &ParticipantInfo::getParameterValue(const std::string &name) const {
+	try {
+		return mParameters.at(name);
+	} catch (std::out_of_range &) {
+		lInfo() << "Unable to find parameter " << name << " associated to participant info " << this << " with address "
+		        << *getAddress();
+		return Utils::getEmptyConstRefObject<string>();
+	}
+}
+
+void ParticipantInfo::removeParameter(const std::string &name) {
+	auto it = mParameters.find(name);
+	if (it == mParameters.end()) {
+		lInfo() << "Unable to remove parameter " << name << " associated to participant info " << this
+		        << " with address " << *getAddress();
+	} else {
+		mParameters.erase(it);
+	}
+}
+
+ParticipantInfo::participant_params_t ParticipantInfo::getAllParameters() const {
+	auto params = mParameters;
+	if (mSequence >= 0) {
+		params[ParticipantInfo::sequenceParameter] = std::to_string(mSequence);
+	}
+	const auto &role = getRole();
+	if (role != Participant::Role::Unknown) {
+		params[ParticipantInfo::roleParameter] = Participant::roleToText(role);
+	}
+	return params;
+}
+
+const std::string ParticipantInfo::memberParametersToString(const ParticipantInfo::participant_params_t &params) {
+	std::string str;
+	for (const auto &[name, value] : params) {
+		if (!str.empty()) {
+			str.append(";");
+		}
+		str.append(name + "=" + value);
+	}
+	return str;
+}
+
+const ParticipantInfo::participant_params_t ParticipantInfo::stringToMemberParameters(const std::string &paramsString) {
+	ParticipantInfo::participant_params_t params;
+	if (!paramsString.empty()) {
+		const auto &splittedValue = bctoolbox::Utils::split(Utils::trim(paramsString), ";");
+		for (const auto &param : splittedValue) {
+			auto equal = param.find("=");
+			string name = param.substr(0, equal);
+			string value = param.substr(equal + 1, param.size());
+			params.insert(std::make_pair(name, value));
+		}
+	}
+
+	return params;
+}
+
+LINPHONE_END_NAMESPACE
diff --git a/src/conference/participant-info.h b/src/conference/participant-info.h
new file mode 100644
index 0000000000..df9be9bcaf
--- /dev/null
+++ b/src/conference/participant-info.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010-2023 Belledonne Communications SARL.
+ *
+ * This file is part of Liblinphone
+ * (see https://gitlab.linphone.org/BC/public/liblinphone).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _L_PARTICIPANT_INFO_H_
+#define _L_PARTICIPANT_INFO_H_
+
+#include <belle-sip/object++.hh>
+
+#include "conference/participant.h"
+
+// =============================================================================
+
+LINPHONE_BEGIN_NAMESPACE
+
+class Address;
+
+class LINPHONE_PUBLIC ParticipantInfo : public bellesip::HybridObject<LinphoneParticipantInfo, ParticipantInfo> {
+public:
+	using participant_params_t = std::map<std::string, std::string>;
+
+	static const std::string sequenceParameter;
+	static const std::string roleParameter;
+
+	ParticipantInfo(const std::shared_ptr<Address> &address);
+	virtual ~ParticipantInfo();
+
+	ParticipantInfo(const ParticipantInfo &other);
+
+	ParticipantInfo *clone() const override;
+
+	const std::shared_ptr<Address> &getAddress() const;
+
+	void setRole(Participant::Role role);
+	Participant::Role getRole() const;
+
+	void setSequenceNumber(const int &nb);
+	const int &getSequenceNumber() const;
+
+	void setParameters(const participant_params_t &params);
+	void addParameter(const std::string &name, const std::string &value);
+	void addParameters(const participant_params_t &params);
+	const std::string &getParameterValue(const std::string &param) const;
+	bool hasParameter(const std::string &name) const;
+	void removeParameter(const std::string &name);
+
+	ParticipantInfo::participant_params_t getAllParameters() const;
+
+	static const std::string memberParametersToString(const participant_params_t &params);
+	static const participant_params_t stringToMemberParameters(const std::string &params);
+
+private:
+	std::shared_ptr<Address> mAddress;
+	Participant::Role mRole = Participant::Role::Unknown;
+	int mSequence = -1;
+	participant_params_t mParameters;
+};
+
+LINPHONE_END_NAMESPACE
+
+#endif // _L_PARTICIPANT_INFO_H_
diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp
index 6f7cc7df8e..4bea9e919a 100644
--- a/src/conference/participant.cpp
+++ b/src/conference/participant.cpp
@@ -20,6 +20,8 @@
 
 #include <algorithm>
 
+#include "participant.h"
+
 #include "core/core.h"
 #include "params/media-session-params.h"
 #include "participant.h"
@@ -140,13 +142,13 @@ std::shared_ptr<ParticipantDevice> Participant::addDevice(const std::shared_ptr<
 	 * we cannot afford to call Address:toString() for nothing when logs are disabled */
 	if (getCore() && (linphone_core_get_global_state(getCore()->getCCore()) == LinphoneGlobalOn)) {
 		if (bctbx_log_level_enabled(BCTBX_LOG_DOMAIN, BCTBX_LOG_MESSAGE)) {
-			lInfo() << "Add device " << (name.empty() ? "<no-name>" : name) << " with address " << gruu->toString()
-			        << " to participant " << getAddress()->toString();
+			lInfo() << "Add device " << (name.empty() ? "<no-name>" : name) << " with address " << *gruu
+			        << " to participant " << *getAddress();
 		}
 	} else {
 		if (bctbx_log_level_enabled(BCTBX_LOG_DOMAIN, BCTBX_LOG_DEBUG)) {
-			lDebug() << "Add device " << (name.empty() ? "<no-name>" : name) << " with address " << gruu->toString()
-			         << " to participant " << getAddress()->toString();
+			lDebug() << "Add device " << (name.empty() ? "<no-name>" : name) << " with address " << *gruu
+			         << " to participant " << *getAddress();
 		}
 	}
 	device = ParticipantDevice::create(getSharedFromThis(), gruu, name);
@@ -297,4 +299,37 @@ void Participant::setUserData(void *ud) {
 	mUserData = ud;
 }
 
+string Participant::roleToText(const Participant::Role &role) {
+	std::string roleText = std::string();
+	switch (role) {
+		case Participant::Role::Speaker:
+			roleText = "speaker";
+			break;
+		case Participant::Role::Listener:
+			roleText = "listener";
+			break;
+		case Participant::Role::Unknown:
+			roleText = "unknown";
+			break;
+	}
+	return roleText;
+}
+
+Participant::Role Participant::textToRole(const string &str) {
+	Participant::Role role = Participant::Role::Speaker;
+	if (str.compare("speaker") == 0) {
+		role = Participant::Role::Speaker;
+	} else if (str.compare("listener") == 0) {
+		role = Participant::Role::Listener;
+	} else if (str.compare("unknown") == 0) {
+		role = Participant::Role::Unknown;
+	}
+	return role;
+}
+
+ostream &operator<<(ostream &stream, Participant::Role role) {
+	const auto &str = Participant::roleToText(role);
+	return stream << str;
+}
+
 LINPHONE_END_NAMESPACE
diff --git a/src/conference/participant.h b/src/conference/participant.h
index 970928c038..d9add46b6c 100644
--- a/src/conference/participant.h
+++ b/src/conference/participant.h
@@ -40,9 +40,9 @@
 class LocalConferenceTester;
 
 namespace LinphoneTest {
-	class LocalConferenceTester;
-	class ClientConference;
-}
+class LocalConferenceTester;
+class ClientConference;
+} // namespace LinphoneTest
 
 LINPHONE_BEGIN_NAMESPACE
 
@@ -82,6 +82,15 @@ class LINPHONE_PUBLIC Participant : public bellesip::HybridObject<LinphonePartic
 	friend class ::LocalConferenceTester;
 
 public:
+	enum class Role {
+		Speaker = LinphoneParticipantRoleSpeaker,
+		Listener = LinphoneParticipantRoleListener,
+		Unknown = LinphoneParticipantRoleUnknown
+	};
+
+	static std::string roleToText(const Participant::Role &role);
+	static Participant::Role textToRole(const std::string &str);
+
 	explicit Participant(Conference *conference,
 	                     const std::shared_ptr<Address> &address,
 	                     std::shared_ptr<CallSession> callSession);
@@ -132,6 +141,13 @@ public:
 	void *getUserData() const;
 	void setUserData(void *ud);
 
+	inline void setRole(Role role) {
+		mRole = role;
+	};
+	inline Role getRole() const {
+		return mRole;
+	};
+
 protected:
 	std::shared_ptr<Core> getCore() const {
 		return mConference ? mConference->getCore() : nullptr;
@@ -184,6 +200,7 @@ private:
 	std::list<std::shared_ptr<ParticipantDevice>> devices;
 	time_t creationTime;
 	bool preserveSession = false;
+	Role mRole = Role::Listener;
 
 	void *mUserData = nullptr;
 
@@ -195,6 +212,8 @@ inline std::ostream &operator<<(std::ostream &os, const Participant &participant
 	return os;
 }
 
+std::ostream &operator<<(std::ostream &stream, Participant::Role role);
+
 LINPHONE_END_NAMESPACE
 
 #endif // ifndef _L_PARTICIPANT_H_
diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h
index 52bab2ec2a..1b0d7acd4b 100644
--- a/src/conference/session/media-session-p.h
+++ b/src/conference/session/media-session-p.h
@@ -338,11 +338,18 @@ private:
 	SalStreamDescription &addStreamToMd(std::shared_ptr<SalMediaDescription> md,
 	                                    int streamIdx,
 	                                    const std::shared_ptr<SalMediaDescription> &oldMd);
+	std::list<unsigned int> getProtectedStreamNumbers(std::shared_ptr<SalMediaDescription> md);
 
 	static const std::string ecStateStore;
 	static const int ecStateMaxLen;
 	static constexpr const int rtpExtHeaderMidNumber = RTP_EXTENSION_MID;
 
+	static const std::string DTXAudioContentAttribute;
+	static const std::string EncryptedActiveSpeakerVideoContentAttribute;
+	static const std::string ActiveSpeakerVideoContentAttribute;
+	static const std::string GridVideoContentAttribute;
+	static const std::string ThumbnailVideoContentAttribute;
+
 	std::weak_ptr<Participant> me;
 
 	std::unique_ptr<StreamsGroup> streamsGroup;
diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp
index c37af9bff1..b4b7923135 100644
--- a/src/conference/session/media-session.cpp
+++ b/src/conference/session/media-session.cpp
@@ -77,6 +77,12 @@ inline OrtpRtcpXrStatSummaryFlag operator|(OrtpRtcpXrStatSummaryFlag a, OrtpRtcp
 const string MediaSessionPrivate::ecStateStore = ".linphone.ecstate";
 const int MediaSessionPrivate::ecStateMaxLen = 1048576; /* 1Mo */
 
+const string MediaSessionPrivate::DTXAudioContentAttribute = "DTX";
+const string MediaSessionPrivate::EncryptedActiveSpeakerVideoContentAttribute = "only-active-speaker";
+const string MediaSessionPrivate::ActiveSpeakerVideoContentAttribute = "speaker";
+const string MediaSessionPrivate::GridVideoContentAttribute = "main";
+const string MediaSessionPrivate::ThumbnailVideoContentAttribute = "thumbnail";
+
 // =============================================================================
 void MediaSessionPrivate::setDtlsFingerprint(const std::string &fingerPrint) {
 	dtlsCertificateFingerprint = fingerPrint;
@@ -277,6 +283,15 @@ void MediaSessionPrivate::accepted() {
 	const auto conferenceInfo = (log) ? log->getConferenceInfo() : nullptr;
 	bool updatingConference = conferenceInfo && (conferenceInfo->getState() == ConferenceInfo::State::Updated);
 
+	std::shared_ptr<MediaConference::Conference> conference = nullptr;
+	if (listener) {
+		conference = listener->getCallSessionConference(q->getSharedFromThis());
+	}
+	// Paused by remote state is not allowed when the call is in a conference. In fact, a conference server is not
+	// allowed to paused a call unilaterally. This assumption also aims at simplifying the management of the
+	// PausedByRemote state as it is simply triggered by SIP messages without really knowing the will of the other party
+	bool pausedByRemoteNotAllowed = ((conference && !isInConference()) || updatingConference);
+
 	// Do not reject media session if the client is trying to update a conference
 	if (rejectMediaSession(rmd, md) && !updatingConference) {
 		lInfo() << "Rejecting media session";
@@ -303,7 +318,7 @@ void MediaSessionPrivate::accepted() {
 					// The call always enters state PausedByRemote if all streams are rejected. This is done to support
 					// some clients who accept to stop the streams by setting the RTP port to 0 If the call is part of a
 					// conference, then it shouldn't be paused if it is just trying to update the conference
-					if (!updatingConference && !localDesc->hasDir(SalStreamInactive) &&
+					if (!pausedByRemoteNotAllowed && !localDesc->hasDir(SalStreamInactive) &&
 					    (md->hasDir(SalStreamRecvOnly) || md->hasDir(SalStreamInactive) || md->isEmpty())) {
 						nextState = CallSession::State::PausedByRemote;
 						nextStateMsg = "Call paused by remote";
@@ -1264,7 +1279,9 @@ void MediaSessionPrivate::runStunTestsIfNeeded() {
 			                                             : getParams()->getConferenceVideoLayout();
 			isConferenceLayoutActiveSpeaker = (confLayout == ConferenceLayout::ActiveSpeaker);
 		}
-		const auto mainStreamAttrValue = isConferenceLayoutActiveSpeaker ? "speaker" : "main";
+		const auto mainStreamAttrValue = isConferenceLayoutActiveSpeaker
+		                                     ? MediaSessionPrivate::ActiveSpeakerVideoContentAttribute
+		                                     : MediaSessionPrivate::GridVideoContentAttribute;
 		const auto videoStreamIndex =
 		    conference ? md->findIdxStreamWithContent(mainStreamAttrValue) : md->findIdxBestStream(SalVideo);
 		int videoPort = portFromStreamIndex(videoStreamIndex);
@@ -1613,6 +1630,8 @@ void MediaSessionPrivate::fillConferenceParticipantStream(SalStreamDescription &
 			// A participant device can only send a video stream if its video direction has the send component (i.e.
 			// SendOnly or SendRecv)
 			if (conference && (participantDevice == dev)) {
+				// If the core is holding the conference, then the device is the one that is active in the session.
+				// Otherwise it is me
 				dir = (isInLocalConference)
 				          ? SalStreamRecvOnly
 				          : (((getParams()->getPrivate()->getSalVideoDirection() == SalStreamSendOnly) ||
@@ -1620,7 +1639,7 @@ void MediaSessionPrivate::fillConferenceParticipantStream(SalStreamDescription &
 				                 ? SalStreamSendOnly
 				                 : SalStreamInactive);
 			} else {
-				if (content.compare("main") == 0) {
+				if (content.compare(MediaSessionPrivate::GridVideoContentAttribute) == 0) {
 					dir = (isInLocalConference) ? SalStreamRecvOnly : SalStreamSendOnly;
 				} else {
 					const auto &mediaDir = dev->getStreamCapability(sal_stream_type_to_linphone(type));
@@ -1632,7 +1651,6 @@ void MediaSessionPrivate::fillConferenceParticipantStream(SalStreamDescription &
 						case LinphoneMediaDirectionRecvOnly:
 						case LinphoneMediaDirectionInactive:
 						case LinphoneMediaDirectionInvalid:
-							dir = SalStreamInactive;
 							dir = (label.empty()) ? SalStreamInactive : SalStreamRecvOnly;
 							break;
 					}
@@ -1648,7 +1666,8 @@ void MediaSessionPrivate::fillConferenceParticipantStream(SalStreamDescription &
 			if (type == SalVideo) {
 				validateVideoStreamDirection(cfg);
 			}
-			if (getParams()->rtpBundleEnabled()) addStreamToBundle(md, newStream, cfg, mid);
+			if (getParams()->rtpBundleEnabled() && (dir != SalStreamInactive))
+				addStreamToBundle(md, newStream, cfg, mid);
 			cfg.replacePayloads(l);
 			newStream.addActualConfiguration(cfg);
 			newStream.setSupportedEncryptions(encs);
@@ -1723,48 +1742,73 @@ void MediaSessionPrivate::fillLocalStreamDescription(SalStreamDescription &strea
 	if (customSdpAttributes) stream.custom_sdp_attributes = sal_custom_sdp_attribute_clone(customSdpAttributes);
 }
 
-SalStreamDescription &MediaSessionPrivate::addStreamToMd(std::shared_ptr<SalMediaDescription> md,
-                                                         int streamIdx,
-                                                         const std::shared_ptr<SalMediaDescription> &oldMd) {
+std::list<unsigned int> MediaSessionPrivate::getProtectedStreamNumbers(std::shared_ptr<SalMediaDescription> md) {
 	L_Q();
-	const auto currentMdSize = md->streams.size();
-	std::list<unsigned int> protectedStreamNumbers;
-	std::list<unsigned int> protectedStreamNumbersOldMd;
+	std::list<unsigned int> streamNumbers;
 	// Protected streams are only meaningful when the call is in a conference
-	auto conference = listener ? listener->getCallSessionConference(q->getSharedFromThis()) : nullptr;
+	const auto conference = listener ? listener->getCallSessionConference(q->getSharedFromThis()) : nullptr;
 	// Protected streams are the first audio stream and the first 2 video streams as they handle local participant
 	// medias
-	auto firstAudioStream = md->findFirstStreamIdxOfType(SalAudio);
-	if (firstAudioStream > -1) {
-		protectedStreamNumbers.push_back(static_cast<unsigned int>(firstAudioStream));
-	}
-	auto firstVideoStream = md->findFirstStreamIdxOfType(SalVideo);
-	if (firstVideoStream > -1) {
-		protectedStreamNumbers.push_back(static_cast<unsigned int>(firstVideoStream));
-		if (conference) {
-			auto secondVideoStream = md->findFirstStreamIdxOfType(SalVideo, firstVideoStream + 1);
-			if (secondVideoStream > -1) {
-				protectedStreamNumbers.push_back(static_cast<unsigned int>(secondVideoStream));
-			}
+	if (conference) {
+		auto firstAudioStream = md->findFirstStreamIdxOfType(SalAudio);
+		if (firstAudioStream > -1) {
+			streamNumbers.push_back(static_cast<unsigned int>(firstAudioStream));
 		}
-	}
 
-	if (oldMd) {
-		auto firstAudioStreamOldMd = oldMd->findFirstStreamIdxOfType(SalAudio);
-		if (firstAudioStreamOldMd > -1) {
-			protectedStreamNumbersOldMd.push_back(static_cast<unsigned int>(firstAudioStreamOldMd));
+		const auto &currentConfParams = conference->getCurrentParams();
+		const auto &confSecurityLevel = currentConfParams.getSecurityLevel();
+		const std::string activeSpeakerAttribute((confSecurityLevel == ConferenceParams::SecurityLevel::EndToEnd)
+		                                             ? MediaSessionPrivate::EncryptedActiveSpeakerVideoContentAttribute
+		                                             : MediaSessionPrivate::ActiveSpeakerVideoContentAttribute);
+		const std::string gridAttribute(MediaSessionPrivate::GridVideoContentAttribute);
+
+		bool isInLocalConference = getParams()->getPrivate()->getInConference();
+		auto participantDevice = isInLocalConference ? conference->findParticipantDevice(q->getSharedFromThis())
+		                                             : conference->getMe()->findDevice(q->getSharedFromThis());
+
+		std::string deviceLabel;
+		if (participantDevice) {
+			deviceLabel = participantDevice->getLabel(LinphoneStreamTypeVideo);
 		}
-		auto firstVideoStreamOldMd = oldMd->findFirstStreamIdxOfType(SalVideo);
-		if (firstVideoStreamOldMd > -1) {
-			protectedStreamNumbersOldMd.push_back(static_cast<unsigned int>(firstVideoStreamOldMd));
-			if (conference) {
-				auto secondVideoStreamOldMd = oldMd->findFirstStreamIdxOfType(SalVideo, firstVideoStreamOldMd + 1);
-				if (secondVideoStreamOldMd > -1) {
-					protectedStreamNumbersOldMd.push_back(static_cast<unsigned int>(secondVideoStreamOldMd));
-				}
+
+		const auto mainActiveSpeakerVideoStreamLabel =
+		    md->findIdxStreamWithContent(activeSpeakerAttribute, deviceLabel);
+		const auto mainGridVideoStreamLabel = md->findIdxStreamWithContent(gridAttribute, deviceLabel);
+		const auto mainActiveSpeakerVideoStreamNoLabel = md->findIdxStreamWithContent(activeSpeakerAttribute);
+		const auto mainGridVideoStreamNoLabel = md->findIdxStreamWithContent(gridAttribute);
+		const auto mainVideoStreamLabel =
+		    (mainActiveSpeakerVideoStreamLabel > -1) ? mainActiveSpeakerVideoStreamLabel : mainGridVideoStreamLabel;
+		const auto mainVideoStreamNoLabel = (mainActiveSpeakerVideoStreamNoLabel > -1)
+		                                        ? mainActiveSpeakerVideoStreamNoLabel
+		                                        : mainGridVideoStreamNoLabel;
+		const auto mainVideoStream = (mainVideoStreamLabel > -1) ? mainVideoStreamLabel : mainVideoStreamNoLabel;
+		if (mainVideoStream > -1) {
+			streamNumbers.push_back(static_cast<unsigned int>(mainVideoStream));
+			const auto thumbnailVideoStreamLabel =
+			    md->findIdxStreamWithContent(MediaSessionPrivate::ThumbnailVideoContentAttribute, deviceLabel);
+			const auto thumbnailVideoStreamNoLabel =
+			    md->findIdxStreamWithContent(MediaSessionPrivate::ThumbnailVideoContentAttribute);
+			const auto thumbnailVideoStream =
+			    (thumbnailVideoStreamLabel > -1) ? thumbnailVideoStreamLabel : thumbnailVideoStreamNoLabel;
+			if (thumbnailVideoStream > -1) {
+				streamNumbers.push_back(static_cast<unsigned int>(thumbnailVideoStream));
 			}
 		}
 	}
+	return streamNumbers;
+}
+
+SalStreamDescription &MediaSessionPrivate::addStreamToMd(std::shared_ptr<SalMediaDescription> md,
+                                                         int streamIdx,
+                                                         const std::shared_ptr<SalMediaDescription> &oldMd) {
+	L_Q();
+	const auto currentMdSize = md->streams.size();
+	const auto conference = listener ? listener->getCallSessionConference(q->getSharedFromThis()) : nullptr;
+	std::list<unsigned int> protectedStreamNumbers = getProtectedStreamNumbers(md);
+	std::list<unsigned int> protectedStreamNumbersOldMd;
+	if (oldMd) {
+		protectedStreamNumbersOldMd = getProtectedStreamNumbers(oldMd);
+	}
 
 	// Search for a free slot
 	int freeSlot = -1;
@@ -1799,7 +1843,7 @@ SalStreamDescription &MediaSessionPrivate::addStreamToMd(std::shared_ptr<SalMedi
 					    (std::find(protectedStreamNumbersOldMd.cbegin(), protectedStreamNumbersOldMd.cend(),
 					               mdStreamIdx) != protectedStreamNumbersOldMd.cend());
 					auto oldStream = oldMd->getStreamIdx(static_cast<unsigned int>(mdStreamIdx));
-					if (!protectedIdx && (oldStream.getLabel() == stream.getLabel())) {
+					if (conference && !protectedIdx && (oldStream.getLabel() == stream.getLabel())) {
 						idxOldMd = static_cast<int>(mdStreamIdx);
 						break;
 					}
@@ -1858,7 +1902,8 @@ void MediaSessionPrivate::addConferenceLocalParticipantStreams(bool add,
 		if (((type == SalVideo) && isVideoConferenceEnabled) || (type == SalAudio)) {
 			std::list<OrtpPayloadType *> emptyList;
 			bool isInLocalConference = getParams()->getPrivate()->getInConference();
-			const std::string content((type == SalAudio) ? "DTX" : "thumbnail");
+			const std::string content((type == SalAudio) ? MediaSessionPrivate::DTXAudioContentAttribute
+			                                             : MediaSessionPrivate::ThumbnailVideoContentAttribute);
 			const auto &participantDevice = isInLocalConference
 			                                    ? conference->findParticipantDevice(q->getSharedFromThis())
 			                                    : conference->getMe()->findDevice(q->getSharedFromThis());
@@ -1963,9 +2008,13 @@ void MediaSessionPrivate::addConferenceParticipantStreams(std::shared_ptr<SalMed
 			    (isInLocalConference) ? remoteContactAddress : q->getContactAddress();
 
 			if (localIsOfferer && !linphone_core_conference_server_enabled(q->getCore()->getCCore())) {
-				const std::string participantContent(
-				    (type == SalAudio) ? "DTX" : ((isConferenceLayoutActiveSpeaker) ? "thumbnail" : ""));
-				const std::string HDParticipantVideoContent("only-active-speaker");
+				const std::string participantContent((type == SalAudio)
+				                                         ? MediaSessionPrivate::DTXAudioContentAttribute
+				                                         : ((isConferenceLayoutActiveSpeaker)
+				                                                ? MediaSessionPrivate::ThumbnailVideoContentAttribute
+				                                                : ""));
+				const std::string HDParticipantVideoContent(
+				    MediaSessionPrivate::EncryptedActiveSpeakerVideoContentAttribute);
 				const std::string bundleNameStreamPrefix((type == SalVideo) ? "vs" : "as");
 				const std::string bundleNameHDStreamPrefix("vsHD");
 
@@ -2330,9 +2379,11 @@ void MediaSessionPrivate::makeLocalMediaDescription(bool localIsOfferer,
 		}
 	}
 
-	const std::string activeSpeakerAttribute(
-	    (confSecurityLevel == ConferenceParams::SecurityLevel::EndToEnd) ? "only-active-speaker" : "speaker");
-	const std::string mainStreamAttrValue(isConferenceLayoutActiveSpeaker ? activeSpeakerAttribute : "main");
+	const std::string activeSpeakerAttribute((confSecurityLevel == ConferenceParams::SecurityLevel::EndToEnd)
+	                                             ? MediaSessionPrivate::EncryptedActiveSpeakerVideoContentAttribute
+	                                             : MediaSessionPrivate::ActiveSpeakerVideoContentAttribute);
+	const std::string mainStreamAttrValue(
+	    isConferenceLayoutActiveSpeaker ? activeSpeakerAttribute : MediaSessionPrivate::GridVideoContentAttribute);
 
 	auto callVideoEnabled =
 	    (!conferenceCreated && conference) ? getCurrentParams()->videoEnabled() : getParams()->videoEnabled();
@@ -2342,7 +2393,8 @@ void MediaSessionPrivate::makeLocalMediaDescription(bool localIsOfferer,
 	// It is necessary to check for both Grid and ActiveSpeaker layout in order to cover the case when the layout is
 	// changed
 	const SalStreamDescription &oldGridLayoutMainVideoStream =
-	    refMd ? refMd->findStreamWithContent("main") : Utils::getEmptyConstRefObject<SalStreamDescription>();
+	    refMd ? refMd->findStreamWithContent(MediaSessionPrivate::GridVideoContentAttribute)
+	          : Utils::getEmptyConstRefObject<SalStreamDescription>();
 	const SalStreamDescription &oldActiveSpeakerLayoutMainVideoStream =
 	    refMd ? refMd->findStreamWithContent(activeSpeakerAttribute)
 	          : Utils::getEmptyConstRefObject<SalStreamDescription>();
@@ -3265,18 +3317,17 @@ bool MediaSessionPrivate::canSoundResourcesBeFreed() const {
 LinphoneStatus MediaSessionPrivate::pause() {
 	L_Q();
 	if (state == CallSession::State::Paused) {
-		lWarning() << "Media session (local address " << q->getLocalAddress()->toString() << " remote address "
-		           << q->getRemoteAddress()->toString() << ") is in state " << Utils::toString(state)
-		           << " is already paused";
+		lWarning() << "Media session (local address " << *q->getLocalAddress() << " remote address "
+		           << *q->getRemoteAddress() << ") is in state " << Utils::toString(state) << " is already paused";
 		return 0;
 	} else if (state == CallSession::State::Pausing) {
-		lWarning() << "Media session (local address " << q->getLocalAddress()->toString() << " remote address "
-		           << q->getRemoteAddress()->toString() << ") is in state " << Utils::toString(state)
+		lWarning() << "Media session (local address " << *q->getLocalAddress() << " remote address "
+		           << *q->getRemoteAddress() << ") is in state " << Utils::toString(state)
 		           << " is already in the process of being paused";
 		return 0;
 	} else if (!canSoundResourcesBeFreed()) {
-		lWarning() << "Media session (local address " << q->getLocalAddress()->toString() << " remote address "
-		           << q->getRemoteAddress()->toString() << ") is in state " << Utils::toString(state)
+		lWarning() << "Media session (local address " << *q->getLocalAddress() << " remote address "
+		           << *q->getRemoteAddress() << ") is in state " << Utils::toString(state)
 		           << " hence it cannot be paused";
 		return -1;
 	}
@@ -3292,9 +3343,8 @@ LinphoneStatus MediaSessionPrivate::pause() {
 			if (listener) {
 				if (conference) {
 					if (conference->findParticipantDevice(q->getSharedFromThis())) {
-						lWarning() << "Unable to pause media session (local address "
-						           << q->getLocalAddress()->toString() << " remote address "
-						           << q->getRemoteAddress()->toString()
+						lWarning() << "Unable to pause media session (local address " << *q->getLocalAddress()
+						           << " remote address " << *q->getRemoteAddress()
 						           << ") because it is part of a conference. Please use the dedicated conference API "
 						              "to execute the desired actions";
 						return -1;
@@ -3460,9 +3510,10 @@ int MediaSessionPrivate::getMainVideoStreamIdx(const std::shared_ptr<SalMediaDes
 			const auto &confSecurityLevel = currentConfParams.getSecurityLevel();
 			const auto mainStreamAttrValue =
 			    isConferenceLayoutActiveSpeaker
-			        ? ((confSecurityLevel == ConferenceParams::SecurityLevel::EndToEnd) ? "only-active-speaker"
-			                                                                            : "speaker")
-			        : "main";
+			        ? ((confSecurityLevel == ConferenceParams::SecurityLevel::EndToEnd)
+			               ? MediaSessionPrivate::EncryptedActiveSpeakerVideoContentAttribute
+			               : MediaSessionPrivate::ActiveSpeakerVideoContentAttribute)
+			        : MediaSessionPrivate::GridVideoContentAttribute;
 			streamIdx = md->findIdxStreamWithContent(mainStreamAttrValue);
 		} else {
 			streamIdx = md->findIdxBestStream(SalVideo);
@@ -3496,7 +3547,7 @@ int MediaSessionPrivate::getThumbnailStreamIdx(const std::shared_ptr<SalMediaDes
 			                       : meDevices.front()->getLabel(LinphoneStreamTypeVideo);
 			if (!label.empty()) {
 				if (md) {
-					const auto content = "thumbnail";
+					const auto content = MediaSessionPrivate::ThumbnailVideoContentAttribute;
 					streamIdx = md->findIdxStreamWithContent(content, label);
 				}
 			}
@@ -4018,10 +4069,11 @@ MediaSession::~MediaSession() {
 ConferenceLayout MediaSession::computeConferenceLayout(const std::shared_ptr<SalMediaDescription> &md) {
 	ConferenceLayout layout = ConferenceLayout::ActiveSpeaker;
 	if (md) {
-		if (md->findIdxStreamWithContent("main") != -1) {
+		if (md->findIdxStreamWithContent(MediaSessionPrivate::GridVideoContentAttribute) != -1) {
 			layout = ConferenceLayout::Grid;
-		} else if ((md->findIdxStreamWithContent("only-active-speaker") != -1) ||
-		           (md->findIdxStreamWithContent("speaker") != -1)) {
+		} else if ((md->findIdxStreamWithContent(MediaSessionPrivate::EncryptedActiveSpeakerVideoContentAttribute) !=
+		            -1) ||
+		           (md->findIdxStreamWithContent(MediaSessionPrivate::ActiveSpeakerVideoContentAttribute) != -1)) {
 			layout = ConferenceLayout::ActiveSpeaker;
 		} else {
 			lDebug() << "Unable to deduce layout from media description " << md;
diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp
index 6a29d50148..0a55569f66 100644
--- a/src/core/core-chat-room.cpp
+++ b/src/core/core-chat-room.cpp
@@ -439,7 +439,6 @@ void CorePrivate::loadChatRooms() {
 #ifdef HAVE_ADVANCED_IM
 	if (remoteListEventHandler) remoteListEventHandler->clearHandlers();
 #endif
-
 	if (!mainDb->isInitialized()) return;
 	for (auto &chatRoom : mainDb->getChatRooms()) {
 		insertChatRoom(chatRoom);
diff --git a/src/core/core.cpp b/src/core/core.cpp
index ceed7a1f33..b7decff433 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -878,7 +878,7 @@ bool Core::hasSpec(const std::string &spec) const {
 #if __GNUC__ == 7
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#endif
+#endif //  __GNUC__ == 7
 	const auto [name, version] = Core::getSpecNameVersion(spec);
 #if __GNUC__ == 7
 #pragma GCC diagnostic pop
@@ -893,7 +893,7 @@ void Core::removeSpec(const std::string &spec) {
 #if __GNUC__ == 7
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#endif
+#endif //  __GNUC__ == 7
 	const auto [name, version] = Core::getSpecNameVersion(spec);
 #if __GNUC__ == 7
 #pragma GCC diagnostic pop
diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h
index 6f618f0868..2a1f08847c 100644
--- a/src/db/main-db-p.h
+++ b/src/db/main-db-p.h
@@ -26,6 +26,7 @@
 #include "linphone/utils/utils.h"
 
 #include "abstract/abstract-db-p.h"
+#include "conference/participant-info.h"
 #include "containers/lru-cache.h"
 #include "event-log/event-log.h"
 #include "main-db.h"
@@ -73,10 +74,10 @@ private:
 	long long insertOrUpdateConferenceInfoParticipant(long long conferenceInfoId,
 	                                                  long long participantSipAddressId,
 	                                                  bool deleted,
-	                                                  const ConferenceInfo::participant_params_t params);
+	                                                  const ParticipantInfo::participant_params_t params);
 	long long insertOrUpdateConferenceInfoOrganizer(long long conferenceInfoId,
 	                                                long long organizerSipAddressId,
-	                                                const ConferenceInfo::participant_params_t params);
+	                                                const ParticipantInfo::participant_params_t params);
 	long long insertOrUpdateConferenceCall(const std::shared_ptr<CallLog> &callLog,
 	                                       const std::shared_ptr<ConferenceInfo> &conferenceInfo = nullptr);
 
diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp
index cad6893d41..2243dd8391 100644
--- a/src/db/main-db.cpp
+++ b/src/db/main-db.cpp
@@ -634,22 +634,23 @@ long long MainDbPrivate::insertConferenceInfo(const std::shared_ptr<ConferenceIn
 	}
 
 	insertOrUpdateConferenceInfoOrganizer(conferenceInfoId, organizerSipAddressId,
-	                                      conferenceInfo->getOrganizer().second);
+	                                      conferenceInfo->getOrganizer()->getAllParameters());
 
 	const auto &participantList = conferenceInfo->getParticipants();
 	for (const auto &participantAddress : participantList) {
-		insertOrUpdateConferenceInfoParticipant(conferenceInfoId, insertSipAddress(participantAddress.first), false,
-		                                        participantAddress.second);
+		insertOrUpdateConferenceInfoParticipant(conferenceInfoId, insertSipAddress(participantAddress->getAddress()),
+		                                        false, participantAddress->getAllParameters());
 	}
 
 	for (const auto &oldParticipantAddress : dbParticipantList) {
 		const bool deleted =
 		    (std::find_if(participantList.cbegin(), participantList.cend(), [&oldParticipantAddress](const auto &p) {
-			     return (p.first->weakEqual(*oldParticipantAddress.first));
+			     return (p->getAddress()->weakEqual(*oldParticipantAddress->getAddress()));
 		     }) == participantList.cend());
 		if (deleted) {
-			insertOrUpdateConferenceInfoParticipant(conferenceInfoId, insertSipAddress(oldParticipantAddress.first),
-			                                        true, oldParticipantAddress.second);
+			insertOrUpdateConferenceInfoParticipant(conferenceInfoId,
+			                                        insertSipAddress(oldParticipantAddress->getAddress()), true,
+			                                        oldParticipantAddress->getAllParameters());
 		}
 	}
 
@@ -663,10 +664,10 @@ long long MainDbPrivate::insertConferenceInfo(const std::shared_ptr<ConferenceIn
 
 long long MainDbPrivate::insertOrUpdateConferenceInfoOrganizer(long long conferenceInfoId,
                                                                long long organizerSipAddressId,
-                                                               const ConferenceInfo::participant_params_t params) {
+                                                               const ParticipantInfo::participant_params_t params) {
 #ifdef HAVE_DB_STORAGE
 	long long conferenceInfoOrganizerId = selectConferenceInfoOrganizerId(conferenceInfoId);
-	auto paramsStr = ConferenceInfo::memberParametersToString(params);
+	auto paramsStr = ParticipantInfo::memberParametersToString(params);
 	if (conferenceInfoOrganizerId >= 0) {
 		*dbSession.getBackendSession() << "UPDATE conference_info_organizer SET"
 		                                  " organizer_sip_address_id = :organizerSipAddressId, params = :paramsStr"
@@ -690,11 +691,11 @@ long long MainDbPrivate::insertOrUpdateConferenceInfoOrganizer(long long confere
 long long MainDbPrivate::insertOrUpdateConferenceInfoParticipant(long long conferenceInfoId,
                                                                  long long participantSipAddressId,
                                                                  bool deleted,
-                                                                 const ConferenceInfo::participant_params_t params) {
+                                                                 const ParticipantInfo::participant_params_t params) {
 #ifdef HAVE_DB_STORAGE
 	long long conferenceInfoParticipantId =
 	    selectConferenceInfoParticipantId(conferenceInfoId, participantSipAddressId);
-	auto paramsStr = ConferenceInfo::memberParametersToString(params);
+	auto paramsStr = ParticipantInfo::memberParametersToString(params);
 	int participantDeleted = deleted ? 1 : 0;
 	if (conferenceInfoParticipantId >= 0) {
 		*dbSession.getBackendSession() << "UPDATE conference_info_participant SET"
@@ -1142,17 +1143,16 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceCallEvent(const soci::row &r
 			    (session->prepare << participantsQuery, soci::use(conferenceInfoId));
 			for (const auto &participantRow : participantRows) {
 				std::shared_ptr<Address> participant = Address::create(participantRow.get<string>(0));
-				ConferenceInfo::participant_params_t participantParams;
-				conferenceInfo->addParticipant(participant, participantParams);
+				auto participantInfo = ParticipantInfo::create(participant);
+				conferenceInfo->addParticipant(participantInfo);
 			}
 
 			// For backward compability purposes, get the organizer from conference_info table and set the sequence
 			// number to that of the conference info stored in the db It may be overridden if the conference organizer
 			// has been stored in table conference_info_organizer.
-			std::shared_ptr<Address> organizer = Address::create(row.get<string>(16));
-			ConferenceInfo::participant_params_t defaultOrganizerParams;
-			defaultOrganizerParams.insert(std::make_pair(ConferenceInfo::sequenceParam, std::to_string(icsSequence)));
-			conferenceInfo->setOrganizer(organizer, defaultOrganizerParams);
+			std::shared_ptr<Address> organizerAddress = Address::create(row.get<string>(16));
+			ParticipantInfo::participant_params_t organizerParams;
+			organizerParams.insert(std::make_pair(ParticipantInfo::sequenceParameter, std::to_string(icsSequence)));
 			static const string organizerQuery =
 			    "SELECT sip_address.value, conference_info_organizer.params"
 			    " FROM sip_address, conference_info, conference_info_organizer"
@@ -1162,12 +1162,13 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceCallEvent(const soci::row &r
 
 			soci::rowset<soci::row> organizerRows = (session->prepare << organizerQuery, soci::use(conferenceInfoId));
 			for (const auto &organizerRow : organizerRows) {
-				std::shared_ptr<Address> organizerAddress = Address::create(organizerRow.get<string>(0));
+				organizerAddress = Address::create(organizerRow.get<string>(0));
 				const string organizerParamsStr = organizerRow.get<string>(1);
-				ConferenceInfo::participant_params_t organizerParams =
-				    ConferenceInfo::stringToMemberParameters(organizerParamsStr);
-				conferenceInfo->setOrganizer(organizerAddress, organizerParams);
+				organizerParams = ParticipantInfo::stringToMemberParameters(organizerParamsStr);
 			}
+			auto organizerInfo = ParticipantInfo::create(organizerAddress);
+			organizerInfo->setParameters(organizerParams);
+			conferenceInfo->setOrganizer(organizerInfo);
 
 			cache(conferenceInfo, conferenceInfoId);
 		}
@@ -1936,20 +1937,20 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row &
 		if (deleted == 0) {
 			std::shared_ptr<Address> participantAddress = Address::create(participantRow.get<string>(0));
 			const string participantParamsStr = participantRow.get<string>(2);
-			ConferenceInfo::participant_params_t participantParams =
-			    ConferenceInfo::stringToMemberParameters(participantParamsStr);
-			conferenceInfo->addParticipant(participantAddress, participantParams);
+			ParticipantInfo::participant_params_t participantParams =
+			    ParticipantInfo::stringToMemberParameters(participantParamsStr);
+			auto participantInfo = ParticipantInfo::create(participantAddress);
+			participantInfo->setParameters(participantParams);
+			conferenceInfo->addParticipant(participantInfo);
 		}
 	}
 
 	// For backward compability purposes, get the organizer from conference_info table and set the sequence number to
 	// that of the conference info stored in the db It may be overridden if the conference organizer has been stored in
 	// table conference_info_organizer.
-	std::shared_ptr<Address> organizer = Address::create(row.get<string>(1));
-	ConferenceInfo::participant_params_t defaultOrganizerParams;
-	defaultOrganizerParams.insert(std::make_pair(ConferenceInfo::sequenceParam, std::to_string(icsSequence)));
-	conferenceInfo->setOrganizer(organizer, defaultOrganizerParams);
-
+	std::shared_ptr<Address> organizerAddress = Address::create(row.get<string>(1));
+	ParticipantInfo::participant_params_t organizerParams;
+	organizerParams.insert(std::make_pair(ParticipantInfo::sequenceParameter, std::to_string(icsSequence)));
 	static const string organizerQuery = "SELECT sip_address.value, conference_info_organizer.params"
 	                                     " FROM sip_address, conference_info, conference_info_organizer"
 	                                     " WHERE conference_info.id = :conferenceInfoId"
@@ -1958,12 +1959,13 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row &
 
 	soci::rowset<soci::row> organizerRows = (session->prepare << organizerQuery, soci::use(dbConferenceInfoId));
 	for (const auto &organizerRow : organizerRows) {
-		std::shared_ptr<Address> organizerAddress = Address::create(organizerRow.get<string>(0));
+		organizerAddress = Address::create(organizerRow.get<string>(0));
 		const string organizerParamsStr = organizerRow.get<string>(1);
-		ConferenceInfo::participant_params_t organizerParams =
-		    ConferenceInfo::stringToMemberParameters(organizerParamsStr);
-		conferenceInfo->setOrganizer(organizerAddress, organizerParams);
+		organizerParams = ParticipantInfo::stringToMemberParameters(organizerParamsStr);
 	}
+	auto organizerInfo = ParticipantInfo::create(organizerAddress);
+	organizerInfo->setParameters(organizerParams);
+	conferenceInfo->setOrganizer(organizerInfo);
 
 	cache(conferenceInfo, dbConferenceInfoId);
 
@@ -4652,7 +4654,7 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const {
 		soci::session *session = d->dbSession.getBackendSession();
 
 		soci::rowset<soci::row> rows = (session->prepare << query);
-		// SOCI use a hack for sqlite3:
+		// SOCI uses a hack for sqlite3:
 		// "sqlite3 type system does not have a date or time field.  Also it does not reliably id other data types.
 		// It has a tendency to see everything as text.
 		// sqlite3_column_decltype returns the text that is used in the create table statement"
diff --git a/src/factory/factory.cpp b/src/factory/factory.cpp
index 14155aa561..b82652c8a3 100644
--- a/src/factory/factory.cpp
+++ b/src/factory/factory.cpp
@@ -55,6 +55,7 @@
 #include "alert/alert.h"
 #include "chat/ics/ics.h"
 #include "conference/conference-info.h"
+#include "conference/participant-info.h"
 #include "content/file-content.h"
 #include "core/paths/paths.h"
 #include "dictionary/dictionary.h"
@@ -821,6 +822,10 @@ std::shared_ptr<ConferenceInfo> Factory::createConferenceInfoFromIcalendarConten
 #pragma GCC diagnostic pop
 #endif // _MSC_VER
 
+std::shared_ptr<ParticipantInfo> Factory::createParticipantInfo(const std::shared_ptr<Address> &address) const {
+	return ParticipantInfo::create(address);
+}
+
 #ifndef _MSC_VER
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
diff --git a/src/factory/factory.h b/src/factory/factory.h
index 95314db407..10ced792dd 100644
--- a/src/factory/factory.h
+++ b/src/factory/factory.h
@@ -217,9 +217,10 @@ public:
 	void setVfsEncryption(const uint16_t encryptionModule, const uint8_t *secret, const size_t secretSize);
 
 	std::shared_ptr<ConferenceInfo> createConferenceInfo() const;
-
 	std::shared_ptr<ConferenceInfo> createConferenceInfoFromIcalendarContent(LinphoneContent *content) const;
 
+	std::shared_ptr<ParticipantInfo> createParticipantInfo(const std::shared_ptr<Address> &address) const;
+
 	LinphoneConferenceSchedulerCbs *createConferenceSchedulerCbs() const;
 
 	LinphoneContent *createQRCode(const std::string &code,
diff --git a/src/sal/sal_media_description.cpp b/src/sal/sal_media_description.cpp
index a1e0138338..569c31e5d7 100644
--- a/src/sal/sal_media_description.cpp
+++ b/src/sal/sal_media_description.cpp
@@ -161,29 +161,24 @@ SalMediaDescription::SalMediaDescription(belle_sdp_session_description_t *sdp)
 
 	/* Get ICE remote ufrag and remote pwd, and ice_lite flag */
 	value = belle_sdp_session_description_get_attribute_value(sdp, "ice-ufrag");
-	if (value)
-		ice_ufrag = L_C_TO_STRING(value);
+	if (value) ice_ufrag = L_C_TO_STRING(value);
 
 	value = belle_sdp_session_description_get_attribute_value(sdp, "ice-pwd");
-	if (value)
-		ice_pwd = L_C_TO_STRING(value);
+	if (value) ice_pwd = L_C_TO_STRING(value);
 
 	value = belle_sdp_session_description_get_attribute_value(sdp, "ice-lite");
-	if (value)
-		ice_lite = true;
+	if (value) ice_lite = true;
 
 	/* Get session RTCP-XR attributes if any */
 	sdp_parse_session_rtcp_xr_parameters(sdp, &rtcp_xr);
 
 	/* Do we have Lime Ik attribute */
 	value = belle_sdp_session_description_get_attribute_value(sdp, "Ik");
-	if (value)
-		haveLimeIk = true;
+	if (value) haveLimeIk = true;
 
 	/* get ready to parse also lime-Ik */
 	value = belle_sdp_session_description_get_attribute_value(sdp, "lime-Ik");
-	if (value)
-		haveLimeIk = true;
+	if (value) haveLimeIk = true;
 
 	value = belle_sdp_session_description_get_attribute_value(sdp, "record");
 	if (value) {
@@ -259,8 +254,7 @@ bool SalMediaDescription::hasDir(const SalStreamDir &stream_dir) const {
 		if (containsStreamWithDir(SalStreamSendOnly) || containsStreamWithDir(SalStreamSendRecv) ||
 		    containsStreamWithDir(SalStreamRecvOnly))
 			return false;
-		else
-			return true;
+		else return true;
 	}
 	return false;
 }
@@ -272,8 +266,7 @@ const SalMediaDescriptionParams &SalMediaDescription::getParams() const {
 bool SalMediaDescription::containsStreamWithDir(const SalStreamDir &stream_dir, const SalStreamType &type) const {
 	/* we are looking for at least one stream with requested direction, inactive streams are ignored*/
 	for (auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
+		if (!stream.enabled()) continue;
 		if ((stream.getType() == type) && (stream.getDirection() == stream_dir)) {
 			return true;
 		}
@@ -289,8 +282,7 @@ bool SalMediaDescription::containsStreamWithDir(const SalStreamDir &stream_dir,
 bool SalMediaDescription::containsStreamWithDir(const SalStreamDir &stream_dir) const {
 	/* we are looking for at least one stream with requested direction, inactive streams are ignored*/
 	for (auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
+		if (!stream.enabled()) continue;
 		if (stream.getDirection() == stream_dir) {
 			return true;
 		}
@@ -352,8 +344,7 @@ std::list<int> SalMediaDescription::getTransportOwnerIndexes() const {
 int SalMediaDescription::getIndexOfTransportOwner(const SalStreamDescription &sd) const {
 	std::string master_mid;
 	int index;
-	if (sd.getChosenConfiguration().getMid().empty() == true)
-		return -1; /* not part of any bundle */
+	if (sd.getChosenConfiguration().getMid().empty() == true) return -1; /* not part of any bundle */
 	/* lookup the mid in the bundle descriptions */
 	const auto &bundle = getBundleFromMid(sd.getChosenConfiguration().getMid());
 	if (bundle == Utils::getEmptyConstRefObject<SalStreamBundle>()) {
@@ -407,7 +398,7 @@ SalMediaDescription::findStreamItWithLabel(SalStreamType type, const std::string
 }
 
 const SalStreamDescription &SalMediaDescription::findStreamWithLabel(SalStreamType type,
-																	 const std::string label) const {
+                                                                     const std::string label) const {
 	const auto &streamIt = findStreamItWithLabel(type, label);
 	if (streamIt != streams.end()) {
 		return *streamIt;
@@ -477,7 +468,7 @@ std::vector<SalStreamDescription>::const_iterator
 SalMediaDescription::findStreamItWithContent(const std::string content, const std::string label) const {
 	const auto &streamIt = std::find_if(streams.cbegin(), streams.cend(), [&content, &label](const auto &stream) {
 		return ((content.empty() && stream.getContent().empty()) || stream.getContent().compare(content) == 0) &&
-			   (stream.getLabel().compare(label) == 0);
+		       ((label.empty() && stream.getLabel().empty()) || (stream.getLabel().compare(label) == 0));
 	});
 	return streamIt;
 }
@@ -502,8 +493,7 @@ int SalMediaDescription::findIdxStreamWithContent(const std::string content, con
 unsigned int SalMediaDescription::nbStreamsOfType(SalStreamType type) const {
 	unsigned int nb = 0;
 	for (const auto &stream : streams) {
-		if (stream.getType() == type)
-			nb++;
+		if (stream.getType() == type) nb++;
 	}
 	return nb;
 }
@@ -511,8 +501,7 @@ unsigned int SalMediaDescription::nbStreamsOfType(SalStreamType type) const {
 unsigned int SalMediaDescription::nbActiveStreamsOfType(SalStreamType type) const {
 	unsigned int nb = 0;
 	for (const auto &stream : streams) {
-		if (stream.enabled() && (stream.getType() == type))
-			nb++;
+		if (stream.enabled() && (stream.getType() == type)) nb++;
 	}
 	return nb;
 }
@@ -529,8 +518,7 @@ const SalStreamDescription &SalMediaDescription::getActiveStreamOfType(SalStream
 
 const SalStreamDescription &SalMediaDescription::findSecureStreamOfType(SalStreamType type) const {
 	auto idx = findIdxStream(SalProtoRtpSavpf, type);
-	if (idx == -1)
-		idx = findIdxStream(SalProtoRtpSavp, type);
+	if (idx == -1) idx = findIdxStream(SalProtoRtpSavp, type);
 	if (idx != -1) {
 		return getStreamIdx(static_cast<unsigned int>(idx));
 	}
@@ -547,16 +535,11 @@ const SalStreamDescription &SalMediaDescription::findBestStream(SalStreamType ty
 
 int SalMediaDescription::findIdxBestStream(SalStreamType type) const {
 	auto idx = findIdxStream(SalProtoUdpTlsRtpSavpf, type);
-	if (idx == -1)
-		idx = findIdxStream(SalProtoUdpTlsRtpSavp, type);
-	if (idx == -1)
-		idx = findIdxStream(SalProtoRtpSavpf, type);
-	if (idx == -1)
-		idx = findIdxStream(SalProtoRtpSavp, type);
-	if (idx == -1)
-		idx = findIdxStream(SalProtoRtpAvpf, type);
-	if (idx == -1)
-		idx = findIdxStream(SalProtoRtpAvp, type);
+	if (idx == -1) idx = findIdxStream(SalProtoUdpTlsRtpSavp, type);
+	if (idx == -1) idx = findIdxStream(SalProtoRtpSavpf, type);
+	if (idx == -1) idx = findIdxStream(SalProtoRtpSavp, type);
+	if (idx == -1) idx = findIdxStream(SalProtoRtpAvpf, type);
+	if (idx == -1) idx = findIdxStream(SalProtoRtpAvp, type);
 	return idx;
 }
 
@@ -597,7 +580,7 @@ const SalStreamDescription &SalMediaDescription::findStreamWithSdpAttribute(
 }
 
 std::vector<SalStreamDescription>::const_iterator SalMediaDescription::findStreamItWithSdpAttribute(
-	const std::vector<std::pair<std::string, std::string>> &attributes) const {
+    const std::vector<std::pair<std::string, std::string>> &attributes) const {
 	return std::find_if(streams.cbegin(), streams.cend(), [&attributes](const auto &stream) {
 		bool found = true;
 		for (const auto &[attrName, attrValue] : attributes) {
@@ -613,7 +596,7 @@ std::vector<SalStreamDescription>::const_iterator SalMediaDescription::findStrea
 }
 
 std::vector<SalStreamDescription>::const_iterator SalMediaDescription::findStreamItWithSdpAttribute(
-	const SalStreamType type, const std::vector<std::pair<std::string, std::string>> &attributes) const {
+    const SalStreamType type, const std::vector<std::pair<std::string, std::string>> &attributes) const {
 	return std::find_if(streams.cbegin(), streams.cend(), [&type, &attributes](const auto &stream) {
 		bool found = true;
 		for (const auto &[attrName, attrValue] : attributes) {
@@ -629,11 +612,11 @@ std::vector<SalStreamDescription>::const_iterator SalMediaDescription::findStrea
 }
 
 std::vector<SalStreamDescription>::const_iterator SalMediaDescription::findFirstStreamItOfType(SalStreamType type,
-																							   int startingIdx) const {
+                                                                                               int startingIdx) const {
 	auto streamSize = static_cast<int>(streams.size());
 	auto idx = (startingIdx < 0) ? 0 : ((startingIdx >= streamSize) ? (streamSize - 1) : startingIdx);
 	const auto &streamIt = std::find_if(streams.cbegin() + idx, streams.cend(),
-										[&type](const auto &stream) { return (stream.getType() == type); });
+	                                    [&type](const auto &stream) { return (stream.getType() == type); });
 	return streamIt;
 }
 
@@ -664,23 +647,20 @@ const std::list<SalStreamDescription> SalMediaDescription::findAllStreamsOfType(
 }
 
 bool SalMediaDescription::isEmpty() const {
-	if (getNbActiveStreams() > 0)
-		return false;
+	if (getNbActiveStreams() > 0) return false;
 	return true;
 }
 
 bool SalMediaDescription::isAcceptable() const {
 	for (auto &stream : streams) {
-		if (!stream.isAcceptable())
-			return false;
+		if (!stream.isAcceptable()) return false;
 	}
 	return true;
 }
 
 void SalMediaDescription::setDir(SalStreamDir stream_dir) {
 	for (auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
+		if (!stream.enabled()) continue;
 		stream.setDirection(stream_dir);
 	}
 }
@@ -688,8 +668,7 @@ void SalMediaDescription::setDir(SalStreamDir stream_dir) {
 int SalMediaDescription::getNbActiveStreams() const {
 	int nb = 0;
 	for (auto &stream : streams) {
-		if (stream.enabled())
-			nb++;
+		if (stream.enabled()) nb++;
 	}
 	return nb;
 }
@@ -699,8 +678,7 @@ bool SalMediaDescription::hasIceParams() const {
 	bool foundIceCandidates = true;
 	bool foundIceStreamDescParams = true;
 	for (const auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
+		if (!stream.enabled()) continue;
 		foundIceCandidates &= stream.hasIceCandidates();
 		foundIceStreamDescParams &= stream.hasIceParams();
 	}
@@ -710,61 +688,46 @@ bool SalMediaDescription::hasIceParams() const {
 }
 
 bool SalMediaDescription::hasAvpf() const {
-	if (streams.empty())
-		return false;
+	if (streams.empty()) return false;
 	for (const auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
-		if (stream.hasAvpf() != true)
-			return false;
+		if (!stream.enabled()) continue;
+		if (stream.hasAvpf() != true) return false;
 	}
 	return true;
 }
 
 bool SalMediaDescription::hasImplicitAvpf() const {
-	if (streams.empty())
-		return false;
+	if (streams.empty()) return false;
 	for (const auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
-		if (stream.hasImplicitAvpf() != true)
-			return false;
+		if (!stream.enabled()) continue;
+		if (stream.hasImplicitAvpf() != true) return false;
 	}
 	return true;
 }
 
 bool SalMediaDescription::hasSrtp() const {
-	if (streams.empty())
-		return false;
+	if (streams.empty()) return false;
 	for (const auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
-		if (stream.hasSrtp() != true)
-			return false;
+		if (!stream.enabled()) continue;
+		if (stream.hasSrtp() != true) return false;
 	}
 	return true;
 }
 
 bool SalMediaDescription::hasDtls() const {
-	if (streams.empty())
-		return false;
+	if (streams.empty()) return false;
 	for (const auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
-		if (stream.hasDtls() != true)
-			return false;
+		if (!stream.enabled()) continue;
+		if (stream.hasDtls() != true) return false;
 	}
 	return true;
 }
 
 bool SalMediaDescription::hasZrtp() const {
-	if (streams.empty())
-		return false;
+	if (streams.empty()) return false;
 	for (const auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
-		if (stream.hasZrtp() != true)
-			return false;
+		if (!stream.enabled()) continue;
+		if (stream.hasZrtp() != true) return false;
 	}
 	return true;
 }
@@ -774,17 +737,13 @@ bool SalMediaDescription::hasLimeIk() const {
 }
 
 bool SalMediaDescription::hasIpv6() const {
-	if (streams.empty())
-		return false;
+	if (streams.empty()) return false;
 	for (const auto &stream : streams) {
-		if (!stream.enabled())
-			continue;
+		if (!stream.enabled()) continue;
 		if (stream.getRtpAddress().empty() == false) {
-			if (!stream.hasIpv6())
-				return false;
+			if (!stream.hasIpv6()) return false;
 		} else {
-			if (addr.find(':') == std::string::npos)
-				return false;
+			if (addr.find(':') == std::string::npos) return false;
 		}
 	}
 	return true;
@@ -801,9 +760,8 @@ bool SalMediaDescription::operator!=(const SalMediaDescription &other) const {
 int SalMediaDescription::compareToActualConfiguration(const SalMediaDescription &otherMd) const {
 	int result = globalEqual(otherMd);
 	for (auto stream1 = streams.cbegin(), stream2 = otherMd.streams.cbegin();
-		 (stream1 != streams.cend() && stream2 != otherMd.streams.cend()); ++stream1, ++stream2) {
-		if (!stream1->enabled() && !stream2->enabled())
-			continue;
+	     (stream1 != streams.cend() && stream2 != otherMd.streams.cend()); ++stream1, ++stream2) {
+		if (!stream1->enabled() && !stream2->enabled()) continue;
 		result |= stream1->compareToActualConfiguration(*stream2);
 	}
 	return result;
@@ -812,9 +770,8 @@ int SalMediaDescription::compareToActualConfiguration(const SalMediaDescription
 int SalMediaDescription::compareToChosenConfiguration(const SalMediaDescription &otherMd) const {
 	int result = globalEqual(otherMd);
 	for (auto stream1 = streams.cbegin(), stream2 = otherMd.streams.cbegin();
-		 (stream1 != streams.cend() && stream2 != otherMd.streams.cend()); ++stream1, ++stream2) {
-		if (!stream1->enabled() && !stream2->enabled())
-			continue;
+	     (stream1 != streams.cend() && stream2 != otherMd.streams.cend()); ++stream1, ++stream2) {
+		if (!stream1->enabled() && !stream2->enabled()) continue;
 		result |= stream1->compareToChosenConfiguration(*stream2);
 	}
 	return result;
@@ -823,9 +780,8 @@ int SalMediaDescription::compareToChosenConfiguration(const SalMediaDescription
 int SalMediaDescription::equal(const SalMediaDescription &otherMd) const {
 	int result = globalEqual(otherMd);
 	for (auto stream1 = streams.cbegin(), stream2 = otherMd.streams.cbegin();
-		 (stream1 != streams.cend() && stream2 != otherMd.streams.cend()); ++stream1, ++stream2) {
-		if (!stream1->enabled() && !stream2->enabled())
-			continue;
+	     (stream1 != streams.cend() && stream2 != otherMd.streams.cend()); ++stream1, ++stream2) {
+		if (!stream1->enabled() && !stream2->enabled()) continue;
 		result |= stream1->equal(*stream2);
 	}
 	return result;
@@ -834,15 +790,12 @@ int SalMediaDescription::equal(const SalMediaDescription &otherMd) const {
 int SalMediaDescription::globalEqual(const SalMediaDescription &otherMd) const {
 	int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
 
-	if (addr.compare(otherMd.addr) != 0)
-		result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
+	if (addr.compare(otherMd.addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
 	if (addr.empty() == false && otherMd.addr.empty() == false &&
-		ms_is_multicast(L_STRING_TO_C(addr)) != ms_is_multicast(L_STRING_TO_C(otherMd.addr)))
+	    ms_is_multicast(L_STRING_TO_C(addr)) != ms_is_multicast(L_STRING_TO_C(otherMd.addr)))
 		result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED;
-	if (streams.size() != otherMd.streams.size())
-		result |= SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED;
-	if (bandwidth != otherMd.bandwidth)
-		result |= SAL_MEDIA_DESCRIPTION_BANDWIDTH_CHANGED;
+	if (streams.size() != otherMd.streams.size()) result |= SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED;
+	if (bandwidth != otherMd.bandwidth) result |= SAL_MEDIA_DESCRIPTION_BANDWIDTH_CHANGED;
 
 	/* ICE */
 	if (ice_ufrag.compare(otherMd.ice_ufrag) != 0 && !otherMd.ice_ufrag.empty())
@@ -926,8 +879,7 @@ const std::string SalMediaDescription::printDifferences(int result) {
 	if (result) {
 		ms_fatal("There are unhandled result bitmasks in SalMediaDescription::printDifferences(), fix it");
 	}
-	if (out.empty())
-		out = "NONE";
+	if (out.empty()) out = "NONE";
 	return out;
 }
 
diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp
index 8525230455..314ca42315 100644
--- a/src/utils/utils.cpp
+++ b/src/utils/utils.cpp
@@ -29,6 +29,7 @@
 
 #include "c-wrapper/internal/c-tools.h"
 #include "conference/conference-info.h"
+#include "conference/participant-info.h"
 #include "linphone/utils/utils.h"
 #include "logger/logger.h"
 #include "private.h"
@@ -371,7 +372,8 @@ std::string Utils::getResourceLists(const std::list<std::shared_ptr<Address>> &a
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
-std::list<std::shared_ptr<Address>> Utils::parseResourceLists(const Content &content) {
+ConferenceInfo::participant_list_t Utils::parseResourceLists(const Content &content) {
+	ConferenceInfo::participant_list_t resources;
 #ifdef HAVE_ADVANCED_IM
 	if ((content.getContentType() == ContentType::ResourceLists) &&
 	    ((content.getContentDisposition().weakEqual(ContentDisposition::RecipientList)) ||
@@ -379,19 +381,22 @@ std::list<std::shared_ptr<Address>> Utils::parseResourceLists(const Content &con
 		std::istringstream data(content.getBodyAsString());
 		std::unique_ptr<Xsd::ResourceLists::ResourceLists> rl(
 		    Xsd::ResourceLists::parseResourceLists(data, Xsd::XmlSchema::Flags::dont_validate));
-		std::list<std::shared_ptr<Address>> addresses;
 		for (const auto &l : rl->getList()) {
 			for (const auto &entry : l.getEntry()) {
-				std::shared_ptr<Address> addr = Address::create(entry.getUri());
-				addresses.push_back(addr);
+				Address address(entry.getUri());
+				auto participantInfo = ParticipantInfo::create(Address::create(address.getUri()));
+				for (const auto &[name, value] : address.getParams()) {
+					participantInfo->addParameter(name, value);
+				}
+				resources.push_back(participantInfo);
 			}
 		}
-		return addresses;
+		return resources;
 	}
-	return std::list<std::shared_ptr<Address>>();
+	return resources;
 #else
 	lWarning() << "Advanced IM such as group chat is disabled!";
-	return std::list<std::shared_ptr<Address>>();
+	return resources;
 #endif
 }
 #ifndef _MSC_VER
@@ -405,14 +410,19 @@ std::shared_ptr<ConferenceInfo> Utils::createConferenceInfoFromOp(SalCallOp *op,
 	const auto resourceList = op->getContentInRemote(ContentType::ResourceLists);
 
 	if (!sipfrag.isEmpty()) {
-		auto organizer = Utils::getSipFragAddress(sipfrag);
-		info->setOrganizer(Address::create(organizer));
+		auto organizerStr = Utils::getSipFragAddress(sipfrag);
+		auto organizer = Address::create(organizerStr);
+		auto organizerInfo = ParticipantInfo::create(Address::create(organizer->getUri()));
+		for (const auto &[name, value] : organizer->getParams()) {
+			organizerInfo->addParameter(name, value);
+		}
+		info->setOrganizer(organizerInfo);
 	}
 
 	if (!resourceList.isEmpty()) {
 		auto invitees = Utils::parseResourceLists(resourceList);
-		for (const auto &i : invitees) {
-			info->addParticipant(i);
+		for (const auto &invitee : invitees) {
+			info->addParticipant(invitee);
 		}
 	}
 
diff --git a/tester/audio_video_conference_tester.c b/tester/audio_video_conference_tester.c
index 4820515ab8..d024c33517 100644
--- a/tester/audio_video_conference_tester.c
+++ b/tester/audio_video_conference_tester.c
@@ -421,23 +421,27 @@ static void check_conference_volumes(LinphoneCall *call) {
 
 			for (bctbx_list_t *it_d = devices; it_d != NULL; it_d = it_d->next) {
 				LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)it_d->data;
-				if (linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeAudio)) {
-					BC_ASSERT_NOT_EQUAL((unsigned long)linphone_participant_device_get_ssrc(d, LinphoneStreamTypeAudio),
-					                    0, unsigned long, "%0lu");
-					BC_ASSERT_NOT_EQUAL(linphone_conference_get_participant_device_volume(conference, d),
-					                    AUDIOSTREAMVOLUMES_NOT_FOUND, int, "%d");
-					BC_ASSERT_GREATER(linphone_conference_get_participant_device_volume(conference, d),
-					                  MS_VOLUME_DB_LOWEST, int, "%d");
-				} else {
+				if (linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeAudio) ==
+				    LinphoneMediaDirectionInactive) {
 					BC_ASSERT_EQUAL((unsigned long)linphone_participant_device_get_ssrc(d, LinphoneStreamTypeAudio), 0,
 					                unsigned long, "%0lu");
-				}
-				if (linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo)) {
-					BC_ASSERT_NOT_EQUAL((unsigned long)linphone_participant_device_get_ssrc(d, LinphoneStreamTypeVideo),
-					                    0, unsigned long, "%0lu");
 				} else {
+					BC_ASSERT_NOT_EQUAL((unsigned long)linphone_participant_device_get_ssrc(d, LinphoneStreamTypeAudio),
+					                    0, unsigned long, "%0lu");
+					if (linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeAudio)) {
+						BC_ASSERT_NOT_EQUAL(linphone_conference_get_participant_device_volume(conference, d),
+						                    AUDIOSTREAMVOLUMES_NOT_FOUND, int, "%d");
+						BC_ASSERT_GREATER(linphone_conference_get_participant_device_volume(conference, d),
+						                  MS_VOLUME_DB_LOWEST, int, "%d");
+					}
+				}
+				if (linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+				    LinphoneMediaDirectionInactive) {
 					BC_ASSERT_EQUAL((unsigned long)linphone_participant_device_get_ssrc(d, LinphoneStreamTypeVideo), 0,
 					                unsigned long, "%0lu");
+				} else {
+					BC_ASSERT_NOT_EQUAL((unsigned long)linphone_participant_device_get_ssrc(d, LinphoneStreamTypeVideo),
+					                    0, unsigned long, "%0lu");
 				}
 			}
 			bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
@@ -542,13 +546,15 @@ static void simple_conference_base(LinphoneCoreManager *marie,
 			linphone_call_terminate(marie_call_pauline);
 			linphone_call_terminate(marie_call_laure);
 			BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd,
-			                             initial_marie_stat.number_of_LinphoneCallEnd + 2, 10000));
+			                             initial_marie_stat.number_of_LinphoneCallEnd + 2,
+			                             liblinphone_tester_sip_timeout));
 			BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd,
 			                             initial_pauline_stat.number_of_LinphoneCallEnd + 1, 5000));
 			BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd,
 			                             initial_laure_stat.number_of_LinphoneCallEnd + 1, 5000));
 			BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased,
-			                             initial_marie_stat.number_of_LinphoneCallReleased + 3, 10000));
+			                             initial_marie_stat.number_of_LinphoneCallReleased + 3,
+			                             liblinphone_tester_sip_timeout));
 			BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased,
 			                             initial_pauline_stat.number_of_LinphoneCallReleased + 1, 5000));
 			BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased,
@@ -682,7 +688,8 @@ static void simple_conference_base(LinphoneCoreManager *marie,
 					BC_ASSERT_PTR_NULL(pauline_conference);
 					linphone_address_unref(pauline_uri);
 					BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneSubscriptionTerminated,
-					                             pauline_stat.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+					                             pauline_stat.number_of_LinphoneSubscriptionTerminated + 1,
+					                             liblinphone_tester_sip_timeout));
 
 					LinphoneAddress *laure_uri = linphone_address_new(linphone_core_get_identity(laure->lc));
 					LinphoneConference *laure_conference =
@@ -690,7 +697,8 @@ static void simple_conference_base(LinphoneCoreManager *marie,
 					BC_ASSERT_PTR_NULL(laure_conference);
 					linphone_address_unref(laure_uri);
 					BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionTerminated,
-					                             laure_stat.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+					                             laure_stat.number_of_LinphoneSubscriptionTerminated + 1,
+					                             liblinphone_tester_sip_timeout));
 
 					LinphoneAddress *marie_uri = linphone_address_new(linphone_core_get_identity(marie->lc));
 					LinphoneConference *marie_conference =
@@ -702,11 +710,14 @@ static void simple_conference_base(LinphoneCoreManager *marie,
 			} else {
 				// Call between Marie and Laure
 				BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPausing,
-				                             marie_stat.number_of_LinphoneCallPausing + 1, 10000));
+				                             marie_stat.number_of_LinphoneCallPausing + 1,
+				                             liblinphone_tester_sip_timeout));
 				BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPaused,
-				                             marie_stat.number_of_LinphoneCallPaused + 1, 10000));
+				                             marie_stat.number_of_LinphoneCallPaused + 1,
+				                             liblinphone_tester_sip_timeout));
 				BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallPausedByRemote,
-				                             laure_stat.number_of_LinphoneCallPausedByRemote + 1, 10000));
+				                             laure_stat.number_of_LinphoneCallPausedByRemote + 1,
+				                             liblinphone_tester_sip_timeout));
 
 				// Conference on Laure's side
 				BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneConferenceStateTerminationPending,
@@ -769,19 +780,26 @@ static void simple_conference_base(LinphoneCoreManager *marie,
 			}
 
 			linphone_core_terminate_call(marie->lc, marie_call_laure);
-			BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, 10000));
-			BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 1, 10000));
-			BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, 10000));
-			BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, 1, 10000));
+			BC_ASSERT_TRUE(
+			    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
 
 			BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc));
 			linphone_call_terminate(marie_call_pauline);
 		} else {
 			linphone_core_pause_call(marie->lc, marie_call_laure);
-			BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPaused, 2, 10000));
-			BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallPausedByRemote, 1, 10000));
+			BC_ASSERT_TRUE(
+			    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPaused, 2, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallPausedByRemote, 1,
+			                             liblinphone_tester_sip_timeout));
 			linphone_core_terminate_call(marie->lc, marie_call_laure);
-			BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, is_remote_conf ? 2 : 1, 10000));
+			BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, is_remote_conf ? 2 : 1,
+			                             liblinphone_tester_sip_timeout));
 		}
 	} else {
 		bctbx_list_t *participants = bctbx_list_append(NULL, laure);
@@ -793,15 +811,24 @@ static void simple_conference_base(LinphoneCoreManager *marie,
 		}
 		bctbx_list_free(participants);
 	}
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, is_remote_conf ? 2 : 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, is_remote_conf ? 3 : 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, is_remote_conf ? 2 : 1, 10000));
-	if (is_remote_conf) BC_ASSERT_TRUE(wait_for_list(lcs, &focus->stat.number_of_LinphoneCallEnd, 3, 10000));
-
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, is_remote_conf ? 2 : 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, is_remote_conf ? 3 : 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, is_remote_conf ? 2 : 1, 10000));
-	if (is_remote_conf) BC_ASSERT_TRUE(wait_for_list(lcs, &focus->stat.number_of_LinphoneCallReleased, 3, 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, is_remote_conf ? 2 : 1,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, is_remote_conf ? 3 : 2,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, is_remote_conf ? 2 : 1,
+	                             liblinphone_tester_sip_timeout));
+	if (is_remote_conf)
+		BC_ASSERT_TRUE(wait_for_list(lcs, &focus->stat.number_of_LinphoneCallEnd, 3, liblinphone_tester_sip_timeout));
+
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, is_remote_conf ? 2 : 1,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, is_remote_conf ? 3 : 2,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, is_remote_conf ? 2 : 1,
+	                             liblinphone_tester_sip_timeout));
+	if (is_remote_conf)
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &focus->stat.number_of_LinphoneCallReleased, 3, liblinphone_tester_sip_timeout));
 
 end:
 	BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCoreLastCallEnded, 1, int, "%d");
@@ -962,17 +989,20 @@ static void simple_conference_notify_speaking_device(void) {
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneParticipantDeviceStopSpeaking, 2, 20000));
 
 	// No need to wait as much this time as pauline should also be notified at the same time
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneParticipantDeviceStartSpeaking, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneParticipantDeviceStopSpeaking, 1, 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneParticipantDeviceStartSpeaking, 1,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneParticipantDeviceStopSpeaking, 1,
+	                             liblinphone_tester_sip_timeout));
 
 	terminate_conference(new_participants, marie, NULL, NULL);
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
 
 	bctbx_list_free(new_participants);
 
@@ -1088,13 +1118,14 @@ static void simple_conference_notify_muted_device(void) {
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneParticipantDeviceMuted, 2, 5000));
 
 	terminate_conference(new_participants, marie, NULL, NULL);
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
 
 	bctbx_list_free(new_participants);
 
@@ -1319,10 +1350,13 @@ static void simple_conference_with_admin_changed(void) {
 	// Pauline ends all calls therefore Pauline exits the conference
 	// A new admin must be designated
 	linphone_core_terminate_all_calls(pauline->lc);
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &((LinphoneCoreManager *)focus)->stat.number_of_LinphoneCallEnd, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &((LinphoneCoreManager *)focus)->stat.number_of_LinphoneCallReleased, 1, 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &((LinphoneCoreManager *)focus)->stat.number_of_LinphoneCallEnd, 1,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &((LinphoneCoreManager *)focus)->stat.number_of_LinphoneCallReleased, 1,
+	                             liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneConferenceStateTerminationPending, 1, 5000));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneConferenceStateTerminated, 1, 5000));
@@ -1630,9 +1664,14 @@ static void simple_conference_with_participant_addition_from_non_admin(void) {
 				LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(d_it);
 				BC_ASSERT_PTR_NOT_NULL(d);
 				if (d) {
-					BC_ASSERT_TRUE(
-					    !!linphone_participant_device_get_is_muted(d) ==
-					    (linphone_address_weak_equal(linphone_participant_device_get_address(d), michelle->identity)));
+					bool_t is_muted =
+					    linphone_address_weak_equal(linphone_participant_device_get_address(d), michelle->identity);
+					int part_counter = 0;
+					do {
+						part_counter++;
+						wait_for_list(lcs, NULL, 0, 100);
+					} while ((part_counter < 100) && ((!!linphone_participant_device_get_is_muted(d)) != is_muted));
+					BC_ASSERT_TRUE((!!linphone_participant_device_get_is_muted(d)) == (!!is_muted));
 				}
 			}
 			bctbx_list_free_with_data(participant_device_list, (void (*)(void *))linphone_participant_device_unref);
@@ -1896,7 +1935,8 @@ static void simple_conference_with_subject_change_from_non_admin(void) {
 	for (bctbx_list_t *it = all_manangers_in_conf; 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_subject_changed,
-		                             (initial_participants_stats[idx].number_of_subject_changed + 1), 10000));
+		                             (initial_participants_stats[idx].number_of_subject_changed + 1),
+		                             liblinphone_tester_sip_timeout));
 
 		LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(m->lc));
 		LinphoneConference *conference =
@@ -2087,14 +2127,18 @@ static void simple_conference_with_one_participant_base(bool_t local) {
 
 	int marie_call_no = (int)bctbx_list_size(linphone_core_get_calls(marie->lc));
 	linphone_core_terminate_all_calls(marie->lc);
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallEnd, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallReleased, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, marie_call_no, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, marie_call_no, 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, marie_call_no, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, marie_call_no, liblinphone_tester_sip_timeout));
 
 	destroy_mgr_in_conference(pauline);
 	destroy_mgr_in_conference(laure);
@@ -2647,20 +2691,27 @@ static void simple_conference_with_user_defined_layout(const LinphoneConferenceL
 
 	int focus_call_no = (int)bctbx_list_size(linphone_core_get_calls(focus_mgr->lc));
 	linphone_core_terminate_all_calls(focus_mgr->lc);
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallEnd, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallReleased, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, (add_participant ? 5 : 4), 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, (add_participant ? 5 : 4), 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallEnd, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallReleased, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, (add_participant ? 5 : 4),
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, (add_participant ? 5 : 4),
+	                             liblinphone_tester_sip_timeout));
 	if (add_participant) {
-		BC_ASSERT_TRUE(wait_for_list(lcs, &chloe->stat.number_of_LinphoneCallEnd, 2, 10000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &chloe->stat.number_of_LinphoneCallReleased, 2, 10000));
+		BC_ASSERT_TRUE(wait_for_list(lcs, &chloe->stat.number_of_LinphoneCallEnd, 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &chloe->stat.number_of_LinphoneCallReleased, 2, liblinphone_tester_sip_timeout));
 	}
-	BC_ASSERT_TRUE(wait_for_list(lcs, &focus_mgr->stat.number_of_LinphoneCallEnd, focus_call_no, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &focus_mgr->stat.number_of_LinphoneCallReleased, focus_call_no, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &focus_mgr->stat.number_of_LinphoneCallEnd, focus_call_no, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &focus_mgr->stat.number_of_LinphoneCallReleased, focus_call_no,
+	                             liblinphone_tester_sip_timeout));
 
 	focus_call_no = (int)bctbx_list_size(linphone_core_get_calls(focus_mgr->lc));
 	BC_ASSERT_EQUAL(focus_call_no, 0, int, "%0d");
@@ -2847,14 +2898,18 @@ static void simple_conference_with_one_participant(void) {
 
 	int marie_call_no = (int)bctbx_list_size(linphone_core_get_calls(marie->lc));
 	linphone_core_terminate_all_calls(marie->lc);
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallEnd, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallReleased, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, marie_call_no, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, marie_call_no, 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, marie_call_no, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, marie_call_no, liblinphone_tester_sip_timeout));
 
 	linphone_conference_unref(conf);
 	destroy_mgr_in_conference(pauline);
@@ -3048,11 +3103,13 @@ static void simple_conference_with_subject_change_from_admin_base(bool_t enable_
 	for (bctbx_list_t *it = all_manangers_in_conf; 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_subject_changed,
-		                             (initial_participants_stats[idx].number_of_subject_changed + 1), 10000));
+		                             (initial_participants_stats[idx].number_of_subject_changed + 1),
+		                             liblinphone_tester_sip_timeout));
 		if (enable_video) {
 			BC_ASSERT_TRUE(wait_for_list(
 			    lcs, &m->stat.number_of_participant_devices_media_capability_changed,
-			    (initial_participants_stats[idx].number_of_participant_devices_media_capability_changed + 1), 10000));
+			    (initial_participants_stats[idx].number_of_participant_devices_media_capability_changed + 1),
+			    liblinphone_tester_sip_timeout));
 			BC_ASSERT_TRUE(wait_for_list(
 			    lcs, &m->stat.number_of_LinphoneCallUpdating,
 			    initial_participants_stats[idx].number_of_LinphoneCallUpdating + ((m == marie) ? 2 : 1), 3000));
@@ -3270,11 +3327,14 @@ static void simple_conference_through_inviting_participants(bool_t check_for_pro
 		linphone_call_accept(pauline_call);
 		linphone_call_accept(laure_call);
 
-		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 3, 10000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 3, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 3, 3000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallConnected, 1, 10000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallConnected, 1, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 3000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallConnected, 1, 10000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallConnected, 1, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 1, 3000));
 
 		// Conference may have already been created of call was paused before hence initial stats can lead to false
@@ -3317,14 +3377,17 @@ static void simple_conference_through_inviting_participants(bool_t check_for_pro
 		BC_ASSERT_PTR_NOT_NULL(conf_call);
 		linphone_core_remove_from_conference(marie->lc, conf_call);
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd,
-		                             initial_marie_stat.number_of_LinphoneCallEnd + 1, 10000));
+		                             initial_marie_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased,
-		                             initial_marie_stat.number_of_LinphoneCallReleased + 1, 10000));
+		                             initial_marie_stat.number_of_LinphoneCallReleased + 1,
+		                             liblinphone_tester_sip_timeout));
 
 		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd,
-		                             initial_pauline_stat.number_of_LinphoneCallEnd + 1, 10000));
+		                             initial_pauline_stat.number_of_LinphoneCallEnd + 1,
+		                             liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased,
-		                             initial_pauline_stat.number_of_LinphoneCallReleased + 1, 10000));
+		                             initial_pauline_stat.number_of_LinphoneCallReleased + 1,
+		                             liblinphone_tester_sip_timeout));
 
 		// Wait for all conferences to be terminated
 		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneConferenceStateTerminationPending,
@@ -3379,7 +3442,8 @@ static void simple_conference_through_inviting_participants(bool_t check_for_pro
 		                             initial_marie_stat.number_of_LinphoneSubscriptionTerminated + 1, 3000));
 
 		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_NotifyReceived,
-		                             (initial_laure_stat.number_of_NotifyReceived + 2), 10000));
+		                             (initial_laure_stat.number_of_NotifyReceived + 2),
+		                             liblinphone_tester_sip_timeout));
 
 		// CHeck that conference is not destroyed
 		BC_ASSERT_FALSE(wait_for_list(lcs, &laure->stat.number_of_LinphoneConferenceStateTerminationPending,
@@ -3413,17 +3477,20 @@ static void simple_conference_through_inviting_participants(bool_t check_for_pro
 		linphone_core_remove_from_conference(marie->lc, conf_call);
 
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd,
-		                             initial_marie_stat.number_of_LinphoneCallEnd + 1, 10000));
+		                             initial_marie_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased,
-		                             initial_marie_stat.number_of_LinphoneCallReleased + 1, 10000));
+		                             initial_marie_stat.number_of_LinphoneCallReleased + 1,
+		                             liblinphone_tester_sip_timeout));
 
 		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd,
-		                             initial_laure_stat.number_of_LinphoneCallEnd + 1, 10000));
+		                             initial_laure_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased,
-		                             initial_laure_stat.number_of_LinphoneCallReleased + 1, 10000));
+		                             initial_laure_stat.number_of_LinphoneCallReleased + 1,
+		                             liblinphone_tester_sip_timeout));
 
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneSubscriptionTerminated,
-		                             initial_marie_stat.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+		                             initial_marie_stat.number_of_LinphoneSubscriptionTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
 
 		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneConferenceStateTerminationPending,
 		                             (initial_laure_stat.number_of_LinphoneConferenceStateTerminationPending + 1),
@@ -3437,9 +3504,11 @@ static void simple_conference_through_inviting_participants(bool_t check_for_pro
 		                             (initial_marie_stat.number_of_LinphoneConferenceStateTerminationPending + 1),
 		                             5000));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneConferenceStateTerminated,
-		                             (initial_marie_stat.number_of_LinphoneConferenceStateTerminated + 1), 10000));
+		                             (initial_marie_stat.number_of_LinphoneConferenceStateTerminated + 1),
+		                             liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneConferenceStateDeleted,
-		                             (initial_marie_stat.number_of_LinphoneConferenceStateDeleted + 1), 10000));
+		                             (initial_marie_stat.number_of_LinphoneConferenceStateDeleted + 1),
+		                             liblinphone_tester_sip_timeout));
 
 		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionTerminated,
 		                             initial_laure_stat.number_of_LinphoneSubscriptionTerminated + 1, 3000));
@@ -3539,12 +3608,15 @@ static void _simple_conference_from_scratch(bool_t with_video) {
 		linphone_call_accept(pauline_call);
 		linphone_call_accept(laure_call);
 
-		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 2, 10000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 2, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2, 3000));
 
-		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallConnected, 1, 10000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallConnected, 1, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 3000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallConnected, 1, 10000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallConnected, 1, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 1, 3000));
 
 		// Conference may have already been created of call was paused before hence initial stats can lead to false
@@ -3677,8 +3749,10 @@ static void video_conference_by_merging_calls(void) {
 	pauline_call = linphone_core_invite_address_with_params(marie->lc, pauline->identity, params);
 	linphone_call_params_unref(params);
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingProgress, 1, 10000));
-	if (BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1, 10000))) {
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingProgress, 1, liblinphone_tester_sip_timeout));
+	if (BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1,
+	                                 liblinphone_tester_sip_timeout))) {
 		linphone_call_accept(linphone_core_get_current_call(pauline->lc));
 	} else goto end;
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1, 5000));
@@ -3690,8 +3764,10 @@ static void video_conference_by_merging_calls(void) {
 	laure_call = linphone_core_invite_address_with_params(marie->lc, laure->identity, params);
 	linphone_call_params_unref(params);
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingProgress, 2, 10000));
-	if (BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallIncomingReceived, 1, 10000))) {
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingProgress, 2, liblinphone_tester_sip_timeout));
+	if (BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallIncomingReceived, 1,
+	                                 liblinphone_tester_sip_timeout))) {
 		linphone_call_accept(linphone_core_get_current_call(laure->lc));
 	} else goto end;
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2, 5000));
@@ -3871,16 +3947,18 @@ static void simple_conference_from_scratch_no_answer(void) {
 		// Pauline immediately declines the call.
 		linphone_call_decline(pauline_call, LinphoneReasonDeclined);
 	}
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 1, 5000));
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, 1, 5000));
 
 	wait_for_list(lcs, NULL, 0, 1000);
 
 	lcs = bctbx_list_append(lcs, laure->lc);
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallIncomingReceived, 1, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallIncomingReceived, 1, liblinphone_tester_sip_timeout));
 	laure_call = linphone_core_get_current_call(laure->lc);
 	BC_ASSERT_PTR_NOT_NULL(laure_call);
 
@@ -3891,7 +3969,8 @@ static void simple_conference_from_scratch_no_answer(void) {
 
 		// Laure accepts.
 		linphone_call_accept(laure_call);
-		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 1, 10000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 1, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1, 5000));
 
 		wait_for_list(lcs, NULL, 0, 1000);
@@ -3900,7 +3979,7 @@ static void simple_conference_from_scratch_no_answer(void) {
 		// Terminate the call, simply.
 		linphone_call_terminate(laure_call);
 
-		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, 10000));
+		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 2, 5000));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, 2, 1000));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased, 1, 1000));
@@ -4138,9 +4217,9 @@ static void eject_from_3_participants_conference(LinphoneCoreManager *marie,
 		end_call(laure, marie);
 		end_call(pauline, marie);
 
-		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, 10000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 2, 10000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, 10000));
+		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
 
 		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased,
 		                             initial_laure_stat.number_of_LinphoneCallReleased + 1, 3000));
@@ -4330,13 +4409,13 @@ static void eject_from_4_participants_conference_call_terminated_one_by_one(Linp
 	linphone_call_terminate(marie_call_laure);
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd,
-	                             initial_pauline_stat.number_of_LinphoneCallEnd + 1, 10000));
+	                             initial_pauline_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallEnd,
-	                             initial_michelle_stat.number_of_LinphoneCallEnd + 1, 10000));
+	                             initial_michelle_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd,
-	                             initial_laure_stat.number_of_LinphoneCallEnd + 1, 10000));
+	                             initial_laure_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd,
-	                             initial_marie_stat.number_of_LinphoneCallEnd + 3, 10000));
+	                             initial_marie_stat.number_of_LinphoneCallEnd + 3, liblinphone_tester_sip_timeout));
 
 	// Wait for conferences to be terminated
 	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneConferenceStateTerminationPending,
@@ -4369,13 +4448,17 @@ static void eject_from_4_participants_conference_call_terminated_one_by_one(Linp
 	                             (initial_marie_stat.number_of_LinphoneConferenceStateDeleted + 1), 5000));
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneSubscriptionTerminated,
-	                             initial_michelle_stat.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             initial_michelle_stat.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneSubscriptionTerminated,
-	                             initial_pauline_stat.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             initial_pauline_stat.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionTerminated,
-	                             initial_laure_stat.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             initial_laure_stat.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneSubscriptionTerminated,
-	                             initial_marie_stat.number_of_LinphoneSubscriptionTerminated + 3, 10000));
+	                             initial_marie_stat.number_of_LinphoneSubscriptionTerminated + 3,
+	                             liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_PTR_NULL(linphone_core_get_conference(marie->lc));
 
@@ -4465,10 +4548,14 @@ static void eject_from_4_participants_conference_base(const LinphoneConferenceLa
 	add_calls_to_local_conference(lcs, marie, NULL, new_participants, FALSE);
 
 	/* Wait that the three participants are joined to the local conference, by checking the StreamsRunning states*/
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	LinphoneConference *l_conference = linphone_core_get_conference(marie->lc);
 	BC_ASSERT_PTR_NOT_NULL(l_conference);
@@ -4501,8 +4588,10 @@ static void eject_from_4_participants_conference_base(const LinphoneConferenceLa
 
 	BC_ASSERT_PTR_NULL(linphone_core_get_conference(marie->lc));
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, marie_call_no, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, marie_call_no, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, marie_call_no, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, marie_call_no, liblinphone_tester_sip_timeout));
 
 end:
 
@@ -4568,10 +4657,14 @@ static void participants_exit_conference_after_pausing(void) {
 	bctbx_list_free(new_participants);
 
 	// Wait that the three participants are joined to the local conference, by checking the StreamsRunning states
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	LinphoneConference *marie_conference = linphone_core_get_conference(marie->lc);
 	BC_ASSERT_PTR_NOT_NULL(marie_conference);
@@ -4623,11 +4716,11 @@ static void participants_exit_conference_after_pausing(void) {
 	// Pausing participant calls causes a NOTIFY to be sent to the participants to notify of the change in media
 	// capabilities
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallPausing,
-	                             laure_stats.number_of_LinphoneCallPausing + 1, 10000));
+	                             laure_stats.number_of_LinphoneCallPausing + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallPaused,
-	                             laure_stats.number_of_LinphoneCallPaused + 1, 10000));
+	                             laure_stats.number_of_LinphoneCallPaused + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPausedByRemote,
-	                             marie_stats.number_of_LinphoneCallPausedByRemote + 1, 10000));
+	                             marie_stats.number_of_LinphoneCallPausedByRemote + 1, liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_NotifyReceived,
 	                             (pauline_stats.number_of_NotifyReceived + 1), 5000));
@@ -4650,11 +4743,11 @@ static void participants_exit_conference_after_pausing(void) {
 	linphone_core_pause_call(pauline->lc, pauline_call_marie);
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallPausing,
-	                             pauline_stats.number_of_LinphoneCallPausing + 1, 10000));
+	                             pauline_stats.number_of_LinphoneCallPausing + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallPaused,
-	                             pauline_stats.number_of_LinphoneCallPaused + 1, 10000));
+	                             pauline_stats.number_of_LinphoneCallPaused + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallPausedByRemote,
-	                             marie_stats.number_of_LinphoneCallPausedByRemote + 2, 10000));
+	                             marie_stats.number_of_LinphoneCallPausedByRemote + 2, liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_TRUE(
 	    wait_for_list(lcs, &laure->stat.number_of_NotifyReceived, (laure_stats.number_of_NotifyReceived + 1), 5000));
@@ -4700,16 +4793,20 @@ static void participants_exit_conference_after_pausing(void) {
 	                             (michelle_stats.number_of_LinphoneConferenceStateDeleted + 1), 5000));
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneSubscriptionTerminated,
-	                             michelle_stats.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             michelle_stats.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneSubscriptionTerminated,
-	                             marie_stats.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             marie_stats.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 
 	linphone_core_terminate_all_calls(marie->lc);
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneSubscriptionTerminated,
-	                             pauline_stats.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             pauline_stats.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionTerminated,
-	                             laure_stats.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             laure_stats.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneConferenceStateTerminationPending,
 	                             (laure_stats.number_of_LinphoneConferenceStateTerminationPending + 1), 5000));
@@ -4733,24 +4830,27 @@ static void participants_exit_conference_after_pausing(void) {
 	                             (marie_stats.number_of_LinphoneConferenceStateDeleted + 1), 5000));
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneSubscriptionTerminated,
-	                             marie_stats.number_of_LinphoneSubscriptionTerminated + 3, 10000));
+	                             marie_stats.number_of_LinphoneSubscriptionTerminated + 3,
+	                             liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd,
-	                             marie_stats.number_of_LinphoneCallEnd + marie_call_no, 10000));
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, laure_stats.number_of_LinphoneCallEnd + 1, 10000));
+	                             marie_stats.number_of_LinphoneCallEnd + marie_call_no,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, laure_stats.number_of_LinphoneCallEnd + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd,
-	                             pauline_stats.number_of_LinphoneCallEnd + 1, 10000));
+	                             pauline_stats.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallEnd,
-	                             michelle_stats.number_of_LinphoneCallEnd + 1, 10000));
+	                             michelle_stats.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased,
-	                             marie_stats.number_of_LinphoneCallReleased + marie_call_no, 10000));
+	                             marie_stats.number_of_LinphoneCallReleased + marie_call_no,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased,
-	                             laure_stats.number_of_LinphoneCallReleased + 1, 10000));
+	                             laure_stats.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased,
-	                             pauline_stats.number_of_LinphoneCallReleased + 1, 10000));
+	                             pauline_stats.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallReleased,
-	                             michelle_stats.number_of_LinphoneCallReleased + 1, 10000));
+	                             michelle_stats.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_PTR_NULL(linphone_core_get_conference(marie->lc));
 	BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_core_get_calls(marie->lc)), 0, unsigned int, "%u");
@@ -4843,10 +4943,14 @@ static void add_participant_after_conference_started_base(bool_t pause_all_calls
 	bctbx_list_free(additional_participants);
 
 	// Wait that the three participants are joined to the local conference, by checking the StreamsRunning states
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	// If Laure's call was paused before creating the conference, local participant is not added
 	BC_ASSERT_FALSE(linphone_conference_is_in(l_conference) == pause_all_calls);
@@ -4973,10 +5077,14 @@ static void conference_with_last_call_paused(void) {
 	BC_ASSERT_EQUAL(linphone_conference_get_participant_count(l_conference), 3, int, "%d");
 
 	// Wait that the three participants are joined to the local conference, by checking the StreamsRunning states
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_FALSE(linphone_conference_is_in(l_conference));
 	BC_ASSERT_EQUAL(linphone_conference_get_participant_count(l_conference), 3, int, "%d");
@@ -5039,10 +5147,14 @@ static void add_all_calls_to_conference(void) {
 	linphone_core_add_all_to_conference(marie->lc);
 
 	// Wait that the three participants are joined to the local conference, by checking the StreamsRunning states
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	// SUBSCRIBEs
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionActive, 1, 5000));
@@ -5162,7 +5274,8 @@ static void add_call_not_accepted_to_conference_remote(void) {
 	BC_ASSERT_PTR_NOT_NULL(pauline_call_marie);
 	if (!pauline_call_marie) goto end;
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingInit, 1, 5000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallIncomingReceived, 2, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallIncomingReceived, 2, liblinphone_tester_sip_timeout));
 
 	marie_called_by_pauline = linphone_core_get_call_by_remote_address2(marie->lc, pauline->identity);
 	BC_ASSERT_PTR_NOT_NULL(marie_called_by_pauline);
@@ -5562,10 +5675,14 @@ static void remove_participant_from_video_conference_base(const LinphoneConferen
 	BC_ASSERT_PTR_NOT_NULL(current_conf_params);
 	BC_ASSERT_TRUE(linphone_conference_params_video_enabled(current_conf_params));
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	// Check that video is still on
 	negotiated_call_params = linphone_call_get_current_params(marie_call_laure);
@@ -5826,14 +5943,14 @@ static void conference_created_by_merging_video_calls_base(bool_t event_package_
 	BC_ASSERT_PTR_NOT_NULL(current_conf_params);
 	BC_ASSERT_TRUE(linphone_conference_params_video_enabled(current_conf_params) == enable_video);
 
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 1 : 0), 10000));
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 1 : 0), 10000));
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 1 : 0), 10000));
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 4 + ((enable_ice) ? 6 : 0), 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 1 : 0),
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 1 : 0),
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 1 : 0),
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 4 + ((enable_ice) ? 6 : 0),
+	                             liblinphone_tester_sip_timeout));
 
 	// Check that conference capabilities hasn't changed
 	current_conf_params = linphone_conference_get_current_params(l_conference);
@@ -6084,8 +6201,10 @@ static void ice_video_conference_one_participant(const LinphoneConferenceLayout
 	BC_ASSERT_PTR_NOT_NULL(current_conf_params);
 	BC_ASSERT_TRUE(linphone_conference_params_video_enabled(current_conf_params));
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 3, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 3, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 3, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 3, liblinphone_tester_sip_timeout));
 
 	// Check that conference capabilities hasn't changed
 	current_conf_params = linphone_conference_get_current_params(conf);
@@ -6349,14 +6468,14 @@ static void audio_calls_added_to_video_conference_base(const LinphoneConferenceL
 	BC_ASSERT_PTR_NOT_NULL(current_conf_params);
 	BC_ASSERT_TRUE(linphone_conference_params_video_enabled(current_conf_params));
 
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 2 : 0), 10000));
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 2 : 0), 10000));
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 2 : 0), 10000));
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6 + ((enable_ice) ? 6 : 0), 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 2 : 0),
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 2 : 0),
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2 + ((enable_ice) ? 2 : 0),
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6 + ((enable_ice) ? 6 : 0),
+	                             liblinphone_tester_sip_timeout));
 
 	// Check that conference capabilities hasn't changed
 	current_conf_params = linphone_conference_get_current_params(l_conference);
@@ -6472,9 +6591,12 @@ static void simple_participant_leaves_conference_base(bool_t remote_participant_
 	BC_ASSERT_TRUE(linphone_conference_is_in(l_conference));
 	BC_ASSERT_EQUAL(linphone_conference_get_participant_count(l_conference), 2, int, "%d");
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 4, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 4, liblinphone_tester_sip_timeout));
 
 	LinphoneConference *marie_conference = linphone_core_get_conference(marie->lc);
 	BC_ASSERT_PTR_NOT_NULL(marie_conference);
@@ -6692,9 +6814,12 @@ participant_leaves_conference_base(bool_t remote_participant_leaves, bool_t add_
 	BC_ASSERT_TRUE(linphone_conference_is_in(l_conference));
 	BC_ASSERT_EQUAL(linphone_conference_get_participant_count(l_conference), 2, int, "%d");
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 4, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 4, liblinphone_tester_sip_timeout));
 
 	LinphoneConference *marie_conference = linphone_core_get_conference(marie->lc);
 	BC_ASSERT_PTR_NOT_NULL(marie_conference);
@@ -6916,9 +7041,11 @@ participant_leaves_conference_base(bool_t remote_participant_leaves, bool_t add_
 
 		// Wait that Laure joins the conference
 		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning,
-		                             laure_stats.number_of_LinphoneCallStreamsRunning + 1, 10000));
+		                             laure_stats.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning,
-		                             marie_stats.number_of_LinphoneCallStreamsRunning + 1, 10000));
+		                             marie_stats.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
 	}
 
 	conf_parts_no = 2 + add_participant;
@@ -7101,10 +7228,14 @@ static void all_temporarely_leave_conference_base(bool_t local_enters_first) {
 	BC_ASSERT_TRUE(linphone_conference_is_in(l_conference));
 	BC_ASSERT_EQUAL(linphone_conference_get_participant_count(l_conference), 3, int, "%d");
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	int no_parts = (int)bctbx_list_size(participants);
 
@@ -7472,17 +7603,18 @@ static void focus_takes_call_after_conference_started_and_participants_leave(voi
 	BC_ASSERT_EQUAL(pauline_call_no, 1, unsigned int, "%u");
 	linphone_core_terminate_all_calls(marie->lc);
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd,
-	                             marie_stat.number_of_LinphoneCallEnd + marie_call_no, 10000));
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, laure_stat.number_of_LinphoneCallEnd + 1, 10000));
+	                             marie_stat.number_of_LinphoneCallEnd + marie_call_no, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, laure_stat.number_of_LinphoneCallEnd + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd,
-	                             pauline_stat.number_of_LinphoneCallEnd + 1, 10000));
+	                             pauline_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased,
-	                             marie_stat.number_of_LinphoneCallReleased + marie_call_no, 10000));
+	                             marie_stat.number_of_LinphoneCallReleased + marie_call_no,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased,
-	                             laure_stat.number_of_LinphoneCallReleased + 1, 10000));
+	                             laure_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallReleased,
-	                             pauline_stat.number_of_LinphoneCallReleased + 1, 10000));
+	                             pauline_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
 
 end:
 
@@ -7526,9 +7658,12 @@ static void remote_participant_leaves_and_conference_ends_base(bool_t local_ends
 	BC_ASSERT_TRUE(linphone_conference_is_in(l_conference));
 	BC_ASSERT_EQUAL(linphone_conference_get_participant_count(l_conference), 2, int, "%d");
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 4, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 4, liblinphone_tester_sip_timeout));
 
 	LinphoneConference *marie_conference = linphone_core_get_conference(marie->lc);
 	BC_ASSERT_PTR_NOT_NULL(marie_conference);
@@ -7607,13 +7742,15 @@ static void remote_participant_leaves_and_conference_ends_base(bool_t local_ends
 			pauline_stats = pauline->stat;
 			linphone_core_terminate_call(michelle->lc, michelle_called_by_marie);
 			BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd,
-			                             marie_stats.number_of_LinphoneCallEnd + 1, 10000));
+			                             marie_stats.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 			BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallEnd,
-			                             michelle_stats.number_of_LinphoneCallEnd + 1, 10000));
+			                             michelle_stats.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
 			BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased,
-			                             marie_stats.number_of_LinphoneCallReleased + 1, 10000));
+			                             marie_stats.number_of_LinphoneCallReleased + 1,
+			                             liblinphone_tester_sip_timeout));
 			BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallReleased,
-			                             michelle_stats.number_of_LinphoneCallReleased + 1, 10000));
+			                             michelle_stats.number_of_LinphoneCallReleased + 1,
+			                             liblinphone_tester_sip_timeout));
 
 			// Wait for conferences to be terminated
 			BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneConferenceStateTerminationPending,
@@ -7731,10 +7868,14 @@ static void participant_call_terminated_after_leaving_conference_base(bool_t loc
 	BC_ASSERT_TRUE(linphone_conference_is_in(l_conference));
 	BC_ASSERT_EQUAL(linphone_conference_get_participant_count(l_conference), 3, int, "%d");
 
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &chloe->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &chloe->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	LinphoneConference *marie_conference = linphone_core_get_conference(marie->lc);
 	BC_ASSERT_PTR_NOT_NULL(marie_conference);
@@ -7934,9 +8075,10 @@ static void participant_call_terminated_after_leaving_conference_base(bool_t loc
 
 	// Wait that Pauline joins the conference
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning,
-	                             pauline_stats.number_of_LinphoneCallStreamsRunning + 1, 10000));
+	                             pauline_stats.number_of_LinphoneCallStreamsRunning + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning,
-	                             marie_stats.number_of_LinphoneCallStreamsRunning + 1, 10000));
+	                             marie_stats.number_of_LinphoneCallStreamsRunning + 1, liblinphone_tester_sip_timeout));
 
 	for (bctbx_list_t *it = lcs; it; it = bctbx_list_next(it)) {
 		LinphoneCore *c = (LinphoneCore *)bctbx_list_get_data(it);
@@ -9250,11 +9392,14 @@ static void participants_take_call_after_conference_started_and_rejoins_conferen
 	BC_ASSERT_TRUE(wait_for(marie->lc, laure->lc, &marie->stat.number_of_LinphoneCallReleased,
 	                        marie_initial_stats.number_of_LinphoneCallReleased + 1));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionTerminated,
-	                             laure_initial_stats.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             laure_initial_stats.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &chloe->stat.number_of_LinphoneSubscriptionTerminated,
-	                             chloe_initial_stats.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             chloe_initial_stats.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneSubscriptionTerminated,
-	                             marie_initial_stats.number_of_LinphoneSubscriptionTerminated + 2, 10000));
+	                             marie_initial_stats.number_of_LinphoneSubscriptionTerminated + 2,
+	                             liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneConferenceStateTerminationPending,
 	                             (laure_initial_stats.number_of_LinphoneConferenceStateTerminationPending + 1), 5000));
@@ -9394,9 +9539,11 @@ static void participant_takes_call_after_conference_started_and_rejoins_conferen
 	wait_for_list(lcs, NULL, 0, 2000);
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionTerminated,
-	                             laure_initial_stats.number_of_LinphoneSubscriptionTerminated + 1, 10000));
+	                             laure_initial_stats.number_of_LinphoneSubscriptionTerminated + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneSubscriptionTerminated,
-	                             marie_initial_stats.number_of_LinphoneSubscriptionTerminated + 2, 10000));
+	                             marie_initial_stats.number_of_LinphoneSubscriptionTerminated + 2,
+	                             liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneConferenceStateTerminationPending,
 	                             (laure_initial_stats.number_of_LinphoneConferenceStateTerminationPending + 1), 5000));
@@ -9587,11 +9734,14 @@ static void toggle_video_settings_during_conference_base(bool_t automatically_vi
 		BC_ASSERT_EQUAL(linphone_conference_get_participant_count(conference), no_participants, int, "%d");
 
 		// Wait that the three participants have joined the local conference, by checking the StreamsRunning states
-		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
 		BC_ASSERT_TRUE(
-		    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2 * no_participants, 10000));
+		    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2 * no_participants,
+		                             liblinphone_tester_sip_timeout));
 
 		for (bctbx_list_t *it = lcs; it; it = bctbx_list_next(it)) {
 			LinphoneCore *c = (LinphoneCore *)bctbx_list_get_data(it);
@@ -9796,11 +9946,14 @@ static void simultaneous_toggle_video_settings_during_conference(void) {
 		BC_ASSERT_EQUAL(linphone_conference_get_participant_count(conference), no_participants, int, "%d");
 
 		// Wait that the three participants have joined the local conference, by checking the StreamsRunning states
-		BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-		BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
 		BC_ASSERT_TRUE(
-		    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2 * no_participants, 10000));
+		    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2 * no_participants,
+		                             liblinphone_tester_sip_timeout));
 
 		bool_t enable_video = FALSE;
 
@@ -9976,10 +10129,12 @@ static void update_conf_params_during_conference(void) {
     BC_ASSERT_EQUAL(linphone_conference_get_participant_count(marie_conference),3, int, "%d");
 
     // Wait that the three participants have joined the local conference, by checking the StreamsRunning states
-    BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-    BC_ASSERT_TRUE(wait_for_list(lcs,&michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-    BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-    BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+    BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning, 2,
+liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(lcs,&michelle->stat.number_of_LinphoneCallStreamsRunning,
+2, liblinphone_tester_sip_timeout));
+    BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning, 2,
+liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning, 6,
+liblinphone_tester_sip_timeout));
 
     // Enable video
     bool_t video_enabled = TRUE;
@@ -10189,13 +10344,14 @@ static void focus_takes_quick_call_after_conference_started_base(bool_t toggle_v
 	BC_ASSERT_EQUAL(laure_call_no, 1, unsigned int, "%u");
 	linphone_core_terminate_all_calls(marie->lc);
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd,
-	                             marie_stat.number_of_LinphoneCallEnd + marie_call_no, 10000));
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, laure_stat.number_of_LinphoneCallEnd + 1, 10000));
+	                             marie_stat.number_of_LinphoneCallEnd + marie_call_no, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallEnd, laure_stat.number_of_LinphoneCallEnd + 1,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased,
-	                             marie_stat.number_of_LinphoneCallReleased + marie_call_no, 10000));
+	                             marie_stat.number_of_LinphoneCallReleased + marie_call_no,
+	                             liblinphone_tester_sip_timeout));
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallReleased,
-	                             laure_stat.number_of_LinphoneCallReleased + 1, 10000));
+	                             laure_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
 
 end:
 
@@ -10274,10 +10430,14 @@ static void try_to_update_call_params_during_conference(void) {
 	add_calls_to_local_conference(lcs, marie, NULL, new_participants, TRUE);
 
 	// Wait that the three participants are joined to the local conference, by checking the StreamsRunning states
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	LinphoneConference *marie_conference = linphone_core_get_conference(marie->lc);
 	BC_ASSERT_PTR_NOT_NULL(marie_conference);
@@ -10431,10 +10591,14 @@ static void register_again_during_conference(void) {
 	BC_ASSERT_EQUAL(linphone_conference_get_participant_count(marie_conference), 3, int, "%d");
 
 	// Wait that the three participants are joined to the local conference, by checking the StreamsRunning states
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &michelle->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 6, liblinphone_tester_sip_timeout));
 
 	LinphoneProxyConfig *proxyConfig = linphone_core_get_default_proxy_config(laure->lc);
 	linphone_proxy_config_edit(proxyConfig);
@@ -10450,8 +10614,10 @@ static void register_again_during_conference(void) {
 	linphone_core_set_network_reachable(pauline->lc, FALSE);
 	linphone_core_set_network_reachable(laure->lc, FALSE);
 	linphone_core_set_network_reachable(marie->lc, FALSE);
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneSubscriptionTerminated, 1, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionTerminated, 1, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneSubscriptionTerminated, 1, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionTerminated, 1, liblinphone_tester_sip_timeout));
 
 	proxyConfig = linphone_core_get_default_proxy_config(laure->lc);
 	linphone_proxy_config_edit(proxyConfig);
@@ -10460,18 +10626,24 @@ static void register_again_during_conference(void) {
 
 	linphone_core_set_network_reachable(marie->lc, TRUE);
 	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneRegistrationOk,
-	                             initial_marie_stats.number_of_LinphoneRegistrationOk + 1, 10000));
+	                             initial_marie_stats.number_of_LinphoneRegistrationOk + 1,
+	                             liblinphone_tester_sip_timeout));
 	linphone_core_set_network_reachable(pauline->lc, TRUE);
 	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneRegistrationOk,
-	                             initial_pauline_stats.number_of_LinphoneRegistrationOk + 1, 10000));
+	                             initial_pauline_stats.number_of_LinphoneRegistrationOk + 1,
+	                             liblinphone_tester_sip_timeout));
 	linphone_core_set_network_reachable(laure->lc, TRUE);
 	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneRegistrationOk,
-	                             initial_laure_stats.number_of_LinphoneRegistrationOk + 1, 10000));
+	                             initial_laure_stats.number_of_LinphoneRegistrationOk + 1,
+	                             liblinphone_tester_sip_timeout));
 
 	// Wait for subscriptins to be resent
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneSubscriptionActive, 5, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneSubscriptionActive, 2, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionActive, 2, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneSubscriptionActive, 5, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &pauline->stat.number_of_LinphoneSubscriptionActive, 2, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionActive, 2, liblinphone_tester_sip_timeout));
 
 	BC_ASSERT_TRUE(linphone_conference_is_in(marie_conference));
 	BC_ASSERT_EQUAL(linphone_conference_get_participant_count(marie_conference), 3, int, "%d");
@@ -10527,10 +10699,11 @@ simple_conference_base2(LinphoneCoreManager *local_conf, bctbx_list_t *participa
 	for (bctbx_list_t *it = participants; it; it = bctbx_list_next(it)) {
 		LinphoneCoreManager *m = (LinphoneCoreManager *)bctbx_list_get_data(it);
 		/* Wait that all participants have joined the local conference, by checking the StreamsRunning states*/
-		BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneCallStreamsRunning, 2, 10000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(lcs, &m->stat.number_of_LinphoneCallStreamsRunning, 2, liblinphone_tester_sip_timeout));
 	}
-	BC_ASSERT_TRUE(
-	    wait_for_list(lcs, &local_conf->stat.number_of_LinphoneCallStreamsRunning, 2 * no_participants, 10000));
+	BC_ASSERT_TRUE(wait_for_list(lcs, &local_conf->stat.number_of_LinphoneCallStreamsRunning, 2 * no_participants,
+	                             liblinphone_tester_sip_timeout));
 
 	LinphoneConference *l_conference = linphone_core_get_conference(local_conf->lc);
 	BC_ASSERT_PTR_NOT_NULL(l_conference);
@@ -10578,7 +10751,8 @@ simple_conference_base2(LinphoneCoreManager *local_conf, bctbx_list_t *participa
 			                             5000));
 
 			BC_ASSERT_TRUE(wait_for_list(lcs, &local_conf->stat.number_of_LinphoneSubscriptionTerminated,
-			                             initial_conf_stats.number_of_LinphoneSubscriptionTerminated + idx + 1, 10000));
+			                             initial_conf_stats.number_of_LinphoneSubscriptionTerminated + idx + 1,
+			                             liblinphone_tester_sip_timeout));
 			BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneSubscriptionTerminated,
 			                             initial_participants_stats[idx].number_of_LinphoneSubscriptionTerminated + 1,
 			                             3000));
@@ -10596,14 +10770,17 @@ simple_conference_base2(LinphoneCoreManager *local_conf, bctbx_list_t *participa
 		}
 
 		BC_ASSERT_TRUE(wait_for_list(lcs, &local_conf->stat.number_of_LinphoneSubscriptionTerminated,
-		                             initial_conf_stats.number_of_LinphoneSubscriptionActive, 10000));
+		                             initial_conf_stats.number_of_LinphoneSubscriptionActive,
+		                             liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &local_conf->stat.number_of_LinphoneConferenceStateTerminationPending,
 		                             (initial_conf_stats.number_of_LinphoneConferenceStateTerminationPending + 1),
 		                             5000));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &local_conf->stat.number_of_LinphoneConferenceStateTerminated,
-		                             (initial_conf_stats.number_of_LinphoneConferenceStateTerminated + 1), 10000));
+		                             (initial_conf_stats.number_of_LinphoneConferenceStateTerminated + 1),
+		                             liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &local_conf->stat.number_of_LinphoneConferenceStateDeleted,
-		                             (initial_conf_stats.number_of_LinphoneConferenceStateDeleted + 1), 10000));
+		                             (initial_conf_stats.number_of_LinphoneConferenceStateDeleted + 1),
+		                             liblinphone_tester_sip_timeout));
 	}
 
 	BC_ASSERT_PTR_NULL(linphone_core_get_conference(local_conf->lc));
@@ -11043,17 +11220,17 @@ static void conference_with_calls_queued(LinphoneCoreManager *local_conf,
 static void conference_with_calls_queued_without_ice(void) {
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *michelle = create_mgr_for_conference("michelle_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(michelle->lc, 10000);
+	linphone_core_set_inc_timeout(michelle->lc, liblinphone_tester_sip_timeout);
 
 	bctbx_list_t *participants = NULL;
 	participants = bctbx_list_append(participants, michelle);
@@ -11076,7 +11253,7 @@ static void conference_with_calls_queued_with_ice(void) {
 	// ICE is enabled
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(marie->lc, mode)) {
 		linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(marie->lc, mode);
@@ -11084,7 +11261,7 @@ static void conference_with_calls_queued_with_ice(void) {
 
 	// ICE is enabled
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(pauline->lc, mode)) {
 		linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(pauline->lc, mode);
@@ -11093,7 +11270,7 @@ static void conference_with_calls_queued_with_ice(void) {
 	// ICE is enabled
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(laure->lc, mode)) {
 		linphone_core_set_firewall_policy(laure->lc, LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(laure->lc, mode);
@@ -11101,7 +11278,7 @@ static void conference_with_calls_queued_with_ice(void) {
 
 	// ICE is enabled
 	LinphoneCoreManager *chloe = create_mgr_for_conference("chloe_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(chloe->lc, 10000);
+	linphone_core_set_inc_timeout(chloe->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(chloe->lc, mode)) {
 		linphone_core_set_firewall_policy(chloe->lc, LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(chloe->lc, mode);
@@ -11125,17 +11302,17 @@ static void conference_with_calls_queued_with_ice(void) {
 static void conference_with_back_to_back_call_accept_without_ice(void) {
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *michelle = create_mgr_for_conference("michelle_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(michelle->lc, 10000);
+	linphone_core_set_inc_timeout(michelle->lc, liblinphone_tester_sip_timeout);
 
 	bctbx_list_t *participants = NULL;
 	participants = bctbx_list_append(participants, michelle);
@@ -11158,7 +11335,7 @@ static void conference_with_back_to_back_call_accept_with_ice(void) {
 	// ICE is enabled
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(marie->lc, mode)) {
 		linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(marie->lc, mode);
@@ -11166,7 +11343,7 @@ static void conference_with_back_to_back_call_accept_with_ice(void) {
 
 	// ICE is enabled
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(pauline->lc, mode)) {
 		linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(pauline->lc, mode);
@@ -11175,7 +11352,7 @@ static void conference_with_back_to_back_call_accept_with_ice(void) {
 	// ICE is enabled
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(laure->lc, mode)) {
 		linphone_core_set_firewall_policy(laure->lc, LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(laure->lc, mode);
@@ -11183,7 +11360,7 @@ static void conference_with_back_to_back_call_accept_with_ice(void) {
 
 	// ICE is enabled
 	LinphoneCoreManager *chloe = create_mgr_for_conference("chloe_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(chloe->lc, 10000);
+	linphone_core_set_inc_timeout(chloe->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(chloe->lc, mode)) {
 		linphone_core_set_firewall_policy(chloe->lc, LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(chloe->lc, mode);
@@ -11207,17 +11384,17 @@ static void conference_with_back_to_back_call_accept_with_ice(void) {
 static void conference_with_back_to_back_call_invite_accept_without_ice(void) {
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *michelle = create_mgr_for_conference("michelle_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(michelle->lc, 10000);
+	linphone_core_set_inc_timeout(michelle->lc, liblinphone_tester_sip_timeout);
 
 	bctbx_list_t *participants = NULL;
 	participants = bctbx_list_append(participants, michelle);
@@ -11241,7 +11418,7 @@ static void conference_with_back_to_back_call_invite_accept_with_ice(void) {
 	// ICE is enabled
 	LinphoneCoreManager* marie = create_mgr_for_conference( "marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc,TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(marie->lc,mode)) {
 		linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(marie->lc,mode);
@@ -11249,7 +11426,7 @@ static void conference_with_back_to_back_call_invite_accept_with_ice(void) {
 
 	// ICE is enabled
 	LinphoneCoreManager* pauline = create_mgr_for_conference( "pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(pauline->lc,mode)) {
 		linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(pauline->lc,mode);
@@ -11257,7 +11434,7 @@ static void conference_with_back_to_back_call_invite_accept_with_ice(void) {
 
 	// ICE is enabled
 	LinphoneCoreManager* laure = create_mgr_for_conference( liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(laure->lc,mode)) {
 		linphone_core_set_firewall_policy(laure->lc,LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(laure->lc,mode);
@@ -11265,7 +11442,7 @@ static void conference_with_back_to_back_call_invite_accept_with_ice(void) {
 
 	// ICE is enabled
 	LinphoneCoreManager* chloe = create_mgr_for_conference( "chloe_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(chloe->lc, 10000);
+	linphone_core_set_inc_timeout(chloe->lc, liblinphone_tester_sip_timeout);
 	if (linphone_core_media_encryption_supported(chloe->lc,mode)) {
 		linphone_core_set_firewall_policy(chloe->lc,LinphonePolicyUseIce);
 		linphone_core_set_media_encryption(chloe->lc,mode);
@@ -11290,17 +11467,17 @@ static void conference_with_back_to_back_call_invite_accept_with_ice(void) {
 static void back_to_back_conferences_same_core(void) {
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *michelle = create_mgr_for_conference("michelle_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(michelle->lc, 10000);
+	linphone_core_set_inc_timeout(michelle->lc, liblinphone_tester_sip_timeout);
 
 	bctbx_list_t *participants = NULL;
 	participants = bctbx_list_append(participants, michelle);
@@ -11329,17 +11506,17 @@ static void back_to_back_conferences_same_core(void) {
 static void back_to_back_conferences(void) {
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *michelle = create_mgr_for_conference("michelle_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(michelle->lc, 10000);
+	linphone_core_set_inc_timeout(michelle->lc, liblinphone_tester_sip_timeout);
 
 	bctbx_list_t *participants = NULL;
 	participants = bctbx_list_append(participants, michelle);
@@ -11368,17 +11545,17 @@ static void back_to_back_conferences(void) {
 static void try_to_create_second_conference_with_local_participant(void) {
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *chloe = create_mgr_for_conference("chloe_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(chloe->lc, 10000);
+	linphone_core_set_inc_timeout(chloe->lc, liblinphone_tester_sip_timeout);
 
 	bctbx_list_t *participants = NULL;
 	participants = bctbx_list_append(participants, laure);
@@ -11470,9 +11647,11 @@ static void try_to_create_second_conference_with_local_participant(void) {
 
 		// Wait for calls to be terminated
 		BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneCallEnd,
-		                             lcm_stats[idx].number_of_LinphoneCallEnd + no_calls, 10000));
+		                             lcm_stats[idx].number_of_LinphoneCallEnd + no_calls,
+		                             liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneCallReleased,
-		                             lcm_stats[idx].number_of_LinphoneCallReleased + no_calls, 10000));
+		                             lcm_stats[idx].number_of_LinphoneCallReleased + no_calls,
+		                             liblinphone_tester_sip_timeout));
 
 		// Wait for all conferences to be terminated
 		BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneConferenceStateTerminationPending,
@@ -11488,7 +11667,7 @@ static void try_to_create_second_conference_with_local_participant(void) {
 		if ((m != marie) && event_log_enabled) {
 			BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneSubscriptionTerminated,
 			                             lcm_stats[idx].number_of_LinphoneSubscriptionTerminated + no_conference,
-			                             10000));
+			                             liblinphone_tester_sip_timeout));
 		}
 
 		LinphoneConference *conference = linphone_core_get_conference(c);
@@ -11526,20 +11705,20 @@ static void try_to_create_second_conference_with_local_participant(void) {
 static void interleaved_conferences_base(bool_t add_participants_immediately_after_creation) {
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *michelle = create_mgr_for_conference("michelle_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(michelle->lc, 10000);
+	linphone_core_set_inc_timeout(michelle->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *chloe = create_mgr_for_conference("chloe_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(chloe->lc, 10000);
+	linphone_core_set_inc_timeout(chloe->lc, liblinphone_tester_sip_timeout);
 
 	bctbx_list_t *participants = NULL;
 	participants = bctbx_list_append(participants, michelle);
@@ -11645,9 +11824,11 @@ static void interleaved_conferences_base(bool_t add_participants_immediately_aft
 
 		// Wait for calls to be terminated
 		BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneCallEnd,
-		                             lcm_stats[idx].number_of_LinphoneCallEnd + no_calls, 10000));
+		                             lcm_stats[idx].number_of_LinphoneCallEnd + no_calls,
+		                             liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneCallReleased,
-		                             lcm_stats[idx].number_of_LinphoneCallReleased + no_calls, 10000));
+		                             lcm_stats[idx].number_of_LinphoneCallReleased + no_calls,
+		                             liblinphone_tester_sip_timeout));
 
 		// Wait for all conferences to be terminated
 		BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneConferenceStateTerminationPending,
@@ -11663,7 +11844,7 @@ static void interleaved_conferences_base(bool_t add_participants_immediately_aft
 		if ((m != marie) && event_log_enabled) {
 			BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneSubscriptionTerminated,
 			                             lcm_stats[idx].number_of_LinphoneSubscriptionTerminated + no_conference,
-			                             10000));
+			                             liblinphone_tester_sip_timeout));
 		}
 
 		LinphoneConference *conference = linphone_core_get_conference(c);
@@ -11717,20 +11898,20 @@ static void interleaved_conference_creation_with_quick_participant_addition(void
 static void multiple_conferences_in_server_mode(void) {
 	LinphoneCoreManager *marie = create_mgr_for_conference("marie_rc", TRUE, NULL);
 	linphone_core_enable_conference_server(marie->lc, TRUE);
-	linphone_core_set_inc_timeout(marie->lc, 10000);
+	linphone_core_set_inc_timeout(marie->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *pauline = create_mgr_for_conference("pauline_tcp_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(pauline->lc, 10000);
+	linphone_core_set_inc_timeout(pauline->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *laure =
 	    create_mgr_for_conference(liblinphone_tester_ipv6_available() ? "laure_tcp_rc" : "laure_rc_udp", TRUE, NULL);
-	linphone_core_set_inc_timeout(laure->lc, 10000);
+	linphone_core_set_inc_timeout(laure->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *michelle = create_mgr_for_conference("michelle_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(michelle->lc, 10000);
+	linphone_core_set_inc_timeout(michelle->lc, liblinphone_tester_sip_timeout);
 
 	LinphoneCoreManager *chloe = create_mgr_for_conference("chloe_rc", TRUE, NULL);
-	linphone_core_set_inc_timeout(chloe->lc, 10000);
+	linphone_core_set_inc_timeout(chloe->lc, liblinphone_tester_sip_timeout);
 
 	bctbx_list_t *participants = NULL;
 	participants = bctbx_list_append(participants, michelle);
@@ -12020,8 +12201,10 @@ static void conference_mix_created_by_merging_video_calls_base(LinphoneConferenc
 
 	int marie_calls = (int)bctbx_list_size(linphone_core_get_calls(marie->lc));
 	linphone_core_terminate_all_calls(marie->lc);
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, marie_calls, 10000));
-	BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, marie_calls, 10000));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, marie_calls, liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(
+	    wait_for_list(lcs, &marie->stat.number_of_LinphoneCallReleased, marie_calls, liblinphone_tester_sip_timeout));
 
 	if (conf) {
 		linphone_conference_unref(conf);
diff --git a/tester/group_chat_tester.c b/tester/group_chat_tester.c
index c9119af383..ba0a4de43e 100644
--- a/tester/group_chat_tester.c
+++ b/tester/group_chat_tester.c
@@ -1368,13 +1368,16 @@ static void group_chat_room_add_participant(void) {
 	coresList = bctbx_list_concat(coresList, tmpCoresList);
 	linphone_core_manager_start(pauline, TRUE);
 	paulineCr = linphone_core_search_chat_room(pauline->lc, NULL, NULL, paulineAddr, NULL);
+	BC_ASSERT_PTR_NOT_NULL(paulineCr);
 	linphone_address_unref(paulineAddr);
 
 	// Pauline adds Chloe to the chat room
 	participantsAddresses = NULL;
 	participantsAddresses =
 	    bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(chloe->lc)));
-	linphone_chat_room_add_participants(paulineCr, participantsAddresses);
+	if (paulineCr) {
+		linphone_chat_room_add_participants(paulineCr, participantsAddresses);
+	}
 	bctbx_list_free_with_data(participantsAddresses, (bctbx_list_free_func)linphone_address_unref);
 	participantsAddresses = NULL;
 
@@ -7945,7 +7948,7 @@ static void participant_removed_then_added(void) {
 	coresList = bctbx_list_concat(coresList, tmpCoresList);
 	linphone_core_manager_start(pauline1, TRUE);
 
-	// Check that the chat room has correctly created on Laure's side and that the participants are added
+	// Check that the chat room has correctly created on Pauline's side and that the participants are added
 	pauline1Cr =
 	    check_has_chat_room_client_side(coresList, pauline1, &initialPauline1Stats, confAddr, initialSubject, 2, FALSE);
 
diff --git a/tester/ics-tester.cpp b/tester/ics-tester.cpp
index bc6310c3a0..69aadc122f 100644
--- a/tester/ics-tester.cpp
+++ b/tester/ics-tester.cpp
@@ -25,14 +25,14 @@
 #include "chat/ics/ics.h"
 #include "chat/ics/parser/ics-parser.h"
 #include "conference/conference-info.h"
+#include "conference/participant-info.h"
 #include "content/content-type.h"
 #include "content/content.h"
 #include "core/core.h"
+#include "liblinphone_tester.h"
 #include "linphone/api/c-api.h"
 // TODO: Remove me later.
 #include "private.h"
-
-#include "liblinphone_tester.h"
 #include "tester_utils.h"
 
 // =============================================================================
@@ -125,15 +125,13 @@ static void parse_folded_example() {
 			const auto &participants = confInfo->getParticipants();
 			BC_ASSERT_EQUAL(participants.size(), 3, size_t, "%0zu");
 			for (const auto &participant : participants) {
-				const auto &address = participant.first;
-				const auto &params = participant.second;
+				const auto &address = participant->getAddress();
+				const auto &params = participant->getAllParameters();
 				size_t no_params = 0;
 				bool found = false;
 				if (*address == *Address::create("sip:jdoe@sip.example.org")) {
 					no_params = 2;
-					for (const auto &param : params) {
-						const auto &name = param.first;
-						const auto &value = param.second;
+					for (const auto &[name, value] : params) {
 						BC_ASSERT_TRUE((name.compare("RSVP") == 0) || (name.compare("X-PARAM") == 0));
 						if (name.compare("RSVP") == 0) {
 							BC_ASSERT_STRING_EQUAL(value.c_str(), "TRUE");
@@ -145,9 +143,7 @@ static void parse_folded_example() {
 					}
 				} else if (*address == *Address::create("sip:pwhite@sip.example.org")) {
 					no_params = 1;
-					for (const auto &param : params) {
-						const auto &name = param.first;
-						const auto &value = param.second;
+					for (const auto &[name, value] : params) {
 						BC_ASSERT_TRUE((name.compare("ROLE") == 0));
 						if (name.compare("ROLE") == 0) {
 							BC_ASSERT_STRING_EQUAL(value.c_str(), "CHAIR");
@@ -157,9 +153,7 @@ static void parse_folded_example() {
 				} else if (*address == *Address::create("sip:tmurphy@sip.example.org")) {
 					// no_params = 2;
 					no_params = 1;
-					for (const auto &param : params) {
-						const auto &name = param.first;
-						const auto &value = param.second;
+					for (const auto &[name, value] : params) {
 						BC_ASSERT_TRUE((name.compare("MEMBER") == 0) || (name.compare("X-PARAM") == 0));
 						if (name.compare("MEMBER") == 0) {
 							BC_ASSERT_STRING_EQUAL(value.c_str(), "mailto:devs@example.com");
@@ -369,13 +363,13 @@ static void send_conference_invitations(bool_t enable_encryption,
 			    marie->identity, linphone_conference_info_get_organizer(conf_info_from_original_content)));
 			BC_ASSERT_TRUE(linphone_address_weak_equal(
 			    conf_uri, linphone_conference_info_get_uri(conf_info_from_original_content)));
-			bctbx_list_t *participants = linphone_conference_info_get_participants(conf_info_from_original_content);
+			const bctbx_list_t *participants =
+			    linphone_conference_info_get_participants(conf_info_from_original_content);
 			if (add_participant_in_error) {
 				BC_ASSERT_EQUAL(bctbx_list_size(participants), 3, size_t, "%zu");
 			} else {
 				BC_ASSERT_EQUAL(bctbx_list_size(participants), 2, size_t, "%zu");
 			}
-			bctbx_list_free(participants);
 			BC_ASSERT_EQUAL(linphone_conference_info_get_duration(conf_info_from_original_content), 120, int, "%d");
 			BC_ASSERT_TRUE(linphone_conference_info_get_date_time(conf_info_from_original_content) == conf_time);
 			linphone_conference_info_unref(conf_info_from_original_content);
@@ -423,13 +417,12 @@ static void send_conference_invitations(bool_t enable_encryption,
 			                                           linphone_conference_info_get_organizer(conf_info_from_content)));
 			BC_ASSERT_TRUE(
 			    linphone_address_weak_equal(conf_uri, linphone_conference_info_get_uri(conf_info_from_content)));
-			bctbx_list_t *participants = linphone_conference_info_get_participants(conf_info_from_content);
+			const bctbx_list_t *participants = linphone_conference_info_get_participants(conf_info_from_content);
 			if (add_participant_in_error) {
 				BC_ASSERT_EQUAL(bctbx_list_size(participants), 3, size_t, "%zu");
 			} else {
 				BC_ASSERT_EQUAL(bctbx_list_size(participants), 2, size_t, "%zu");
 			}
-			bctbx_list_free(participants);
 			BC_ASSERT_EQUAL(linphone_conference_info_get_duration(conf_info_from_content), 120, int, "%d");
 			BC_ASSERT_TRUE(linphone_conference_info_get_date_time(conf_info_from_content) == conf_time);
 			linphone_conference_info_unref(conf_info_from_content);
diff --git a/tester/local_conference_edition_tester.cpp b/tester/local_conference_edition_tester.cpp
index 06d65eb17b..9ca0d07135 100644
--- a/tester/local_conference_edition_tester.cpp
+++ b/tester/local_conference_edition_tester.cpp
@@ -30,13 +30,16 @@ static void edit_simple_conference_base(bool_t from_organizer,
                                         bool_t join,
                                         bool_t enable_encryption,
                                         bool_t server_restart,
-                                        LinphoneConferenceSecurityLevel security_level) {
+                                        LinphoneConferenceSecurityLevel security_level,
+                                        bool_t role_changed) {
+
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
 		ClientConference marie("marie_rc", focus.getIdentity());
 		ClientConference pauline("pauline_rc", focus.getIdentity());
 		ClientConference laure("laure_tcp_rc", focus.getIdentity());
 		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference lise("lise_rc", focus.getIdentity());
 
 		LinphoneCoreManager *manager_editing = (from_organizer) ? marie.getCMgr() : laure.getCMgr();
 		linphone_core_enable_rtp_bundle(manager_editing->lc, enable_bundle_mode);
@@ -54,6 +57,7 @@ static void edit_simple_conference_base(bool_t from_organizer,
 		focus.registerAsParticipantDevice(pauline);
 		focus.registerAsParticipantDevice(laure);
 		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(lise);
 
 		setup_conference_info_cbs(marie.getCMgr());
 		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
@@ -82,6 +86,7 @@ static void edit_simple_conference_base(bool_t from_organizer,
 		coresList = bctbx_list_append(coresList, pauline.getLc());
 		coresList = bctbx_list_append(coresList, laure.getLc());
 		coresList = bctbx_list_append(coresList, michelle.getLc());
+		coresList = bctbx_list_append(coresList, lise.getLc());
 
 		std::list<LinphoneCoreManager *> invitedParticipants{pauline.getCMgr(), laure.getCMgr()};
 
@@ -91,7 +96,14 @@ static void edit_simple_conference_base(bool_t from_organizer,
 		const char *initialSubject = "Test characters: <S-F12><S-F11><S-F6> £$%§";
 		const char *description = "Testing characters";
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, invitedParticipants, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : invitedParticipants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -99,37 +111,227 @@ static void edit_simple_conference_base(bool_t from_organizer,
 		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
 		                             liblinphone_tester_sip_timeout));
 
-		const char *subject = "Test characters: <S-F12><S-F11><S-F6> £$%§ (+edits)";
-		const char *description2 = "Testing characters (+edits)";
-
-		stats manager_editing_stat = manager_editing->stat;
-		LinphoneAccount *editing_account = NULL;
-		if (use_default_account) {
-			editing_account = linphone_core_get_default_account(manager_editing->lc);
-		} else {
-			editing_account = linphone_core_lookup_known_account(manager_editing->lc, alternative_address);
-		}
-		BC_ASSERT_PTR_NOT_NULL(editing_account);
-		if (editing_account) {
-			LinphoneAccountParams *account_params =
-			    linphone_account_params_clone(linphone_account_get_params(editing_account));
-			linphone_account_params_enable_rtp_bundle(account_params, enable_bundle_mode);
-			linphone_account_set_params(editing_account, account_params);
-			linphone_account_params_unref(account_params);
-		}
+		char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
 
 		char *uid = NULL;
 		unsigned int sequence = 0;
-		LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
-		if (BC_ASSERT_PTR_NOT_NULL(info)) {
-			uid = ms_strdup(linphone_conference_info_get_ics_uid(info));
+		LinphoneConferenceInfo *conf_info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(conf_info);
+		if (conf_info) {
+			uid = ms_strdup(linphone_conference_info_get_ics_uid(conf_info));
 			BC_ASSERT_PTR_NOT_NULL(uid);
-			sequence = linphone_conference_info_get_ics_sequence(info);
-			linphone_conference_info_unref(info);
+			sequence = linphone_conference_info_get_ics_sequence(conf_info);
+
+			ms_message("%s is trying to update conference %s - adding %s", linphone_core_get_identity(marie.getLc()),
+			           conference_address_str, linphone_core_get_identity(lise.getLc()));
+
+			participants.push_back(lise.getCMgr());
+
+			stats focus_stat = focus.getStats();
+			stats marie_stat = marie.getStats();
+			linphone_conference_info_set_subject(conf_info, initialSubject);
+			linphone_conference_info_set_description(conf_info, description);
+			LinphoneParticipantInfo *lise_participant_info = linphone_participant_info_new(lise.getCMgr()->identity);
+			linphone_participant_info_set_role(lise_participant_info, LinphoneParticipantRoleListener);
+			linphone_conference_info_add_participant_2(conf_info, lise_participant_info);
+			linphone_participant_info_unref(lise_participant_info);
+
+			if (role_changed) {
+				LinphoneParticipantRole current_pauline_role = participantList[pauline.getCMgr()];
+				LinphoneParticipantRole new_pauline_role = (current_pauline_role == LinphoneParticipantRoleListener)
+				                                               ? LinphoneParticipantRoleSpeaker
+				                                               : LinphoneParticipantRoleListener;
+				ms_message("%s is trying to update conference %s - changing role of %s from %s to %s",
+				           linphone_core_get_identity(marie.getLc()), conference_address_str,
+				           linphone_core_get_identity(pauline.getLc()),
+				           linphone_participant_role_to_string(current_pauline_role),
+				           linphone_participant_role_to_string(new_pauline_role));
+				const LinphoneParticipantInfo *old_pauline_partipant_info =
+				    linphone_conference_info_find_participant(conf_info, pauline.getCMgr()->identity);
+				BC_ASSERT_PTR_NOT_NULL(old_pauline_partipant_info);
+				if (old_pauline_partipant_info) {
+					LinphoneParticipantInfo *pauline_participant_info =
+					    linphone_participant_info_clone(old_pauline_partipant_info);
+					linphone_participant_info_set_role(pauline_participant_info, new_pauline_role);
+					linphone_conference_info_update_participant(conf_info, pauline_participant_info);
+					linphone_participant_info_unref(pauline_participant_info);
+				}
+				participantList[pauline.getCMgr()] = new_pauline_role;
+			}
+
+			const auto ics_participant_number = 3;
+			const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+			BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number, size_t, "%zu");
+
+			std::list<stats> participant_stats;
+			for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), lise.getCMgr()}) {
+				participant_stats.push_back(mgr->stat);
+			}
+
+			LinphoneConferenceScheduler *conference_scheduler =
+			    linphone_core_create_conference_scheduler(marie.getLc());
+			LinphoneConferenceSchedulerCbs *cbs =
+			    linphone_factory_create_conference_scheduler_cbs(linphone_factory_get());
+			linphone_conference_scheduler_cbs_set_state_changed(cbs, conference_scheduler_state_changed);
+			linphone_conference_scheduler_cbs_set_invitations_sent(cbs, conference_scheduler_invitations_sent);
+			linphone_conference_scheduler_add_callbacks(conference_scheduler, cbs);
+			linphone_conference_scheduler_cbs_unref(cbs);
+			linphone_conference_scheduler_set_info(conference_scheduler, conf_info);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateUpdating,
+			                             marie_stat.number_of_ConferenceSchedulerStateUpdating + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateReady,
+			                             marie_stat.number_of_ConferenceSchedulerStateReady + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+			                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+			                             focus_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+			                             focus_stat.number_of_LinphoneCallReleased + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			LinphoneChatRoomParams *chat_room_params = linphone_core_create_default_chat_room_params(marie.getLc());
+			linphone_chat_room_params_set_backend(chat_room_params, LinphoneChatRoomBackendBasic);
+			linphone_conference_scheduler_send_invitations(conference_scheduler, chat_room_params);
+			linphone_chat_room_params_unref(chat_room_params);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerInvitationsSent,
+			                             marie_stat.number_of_ConferenceSchedulerInvitationsSent + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), lise.getCMgr()}) {
+				auto old_stats = participant_stats.front();
+				if ((mgr != focus.getCMgr()) && (mgr != marie.getCMgr())) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceived,
+					                             old_stats.number_of_LinphoneMessageReceived + 1,
+					                             liblinphone_tester_sip_timeout));
+					if (!linphone_core_conference_ics_in_message_body_enabled(marie.getLc())) {
+						BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceivedWithFile,
+						                             old_stats.number_of_LinphoneMessageReceivedWithFile + 1,
+						                             liblinphone_tester_sip_timeout));
+					}
+
+					BC_ASSERT_PTR_NOT_NULL(mgr->stat.last_received_chat_message);
+					if (mgr->stat.last_received_chat_message != NULL) {
+						const string expected = ContentType::Icalendar.getMediaType();
+						BC_ASSERT_STRING_EQUAL(
+						    linphone_chat_message_get_content_type(mgr->stat.last_received_chat_message),
+						    expected.c_str());
+					}
+
+					bctbx_list_t *participant_chat_room_participants =
+					    bctbx_list_append(NULL, marie.getCMgr()->identity);
+					LinphoneChatRoom *pcr = linphone_core_search_chat_room(mgr->lc, NULL, mgr->identity, NULL,
+					                                                       participant_chat_room_participants);
+					bctbx_list_free(participant_chat_room_participants);
+					BC_ASSERT_PTR_NOT_NULL(pcr);
+					bctbx_list_t *chat_room_participants = bctbx_list_append(NULL, mgr->identity);
+
+					LinphoneChatRoom *cr = linphone_core_search_chat_room(
+					    marie.getLc(), NULL, marie.getCMgr()->identity, NULL, chat_room_participants);
+					bctbx_list_free(chat_room_participants);
+					BC_ASSERT_PTR_NOT_NULL(cr);
+
+					BC_ASSERT_EQUAL((int)bctbx_list_size(linphone_core_get_chat_rooms(mgr->lc)), 1, int, "%d");
+
+					if (cr) {
+						LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
+						BC_ASSERT_PTR_NOT_NULL(msg);
+
+						const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
+						BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
+						LinphoneContent *original_content = (LinphoneContent *)bctbx_list_get_data(original_contents);
+						if (BC_ASSERT_PTR_NOT_NULL(original_content)) {
+							LinphoneConferenceInfo *conf_info_from_original_content =
+							    linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(),
+							                                                                   original_content);
+							if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) {
+								BC_ASSERT_TRUE(linphone_address_weak_equal(
+								    marie.getCMgr()->identity,
+								    linphone_conference_info_get_organizer(conf_info_from_original_content)));
+								BC_ASSERT_TRUE(linphone_address_weak_equal(
+								    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
+
+								const bctbx_list_t *ics_participants =
+								    linphone_conference_info_get_participants(conf_info_from_original_content);
+								BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number, size_t,
+								                "%zu");
+
+								if (start_time > 0) {
+									BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(
+									                    conf_info_from_original_content),
+									                (long long)start_time, long long, "%lld");
+									if (end_time > 0) {
+										const int duration_m =
+										    linphone_conference_info_get_duration(conf_info_from_original_content);
+										const int duration_s = duration_m * 60;
+										BC_ASSERT_EQUAL(duration_s, (int)(end_time - start_time), int, "%d");
+										BC_ASSERT_EQUAL(duration_m, duration, int, "%d");
+									}
+								}
+								if (initialSubject) {
+									BC_ASSERT_STRING_EQUAL(
+									    linphone_conference_info_get_subject(conf_info_from_original_content),
+									    initialSubject);
+								} else {
+									BC_ASSERT_PTR_NULL(
+									    linphone_conference_info_get_subject(conf_info_from_original_content));
+								}
+								if (description) {
+									BC_ASSERT_STRING_EQUAL(
+									    linphone_conference_info_get_description(conf_info_from_original_content),
+									    description);
+								} else {
+									BC_ASSERT_PTR_NULL(
+									    linphone_conference_info_get_description(conf_info_from_original_content));
+								}
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid);
+								const unsigned int ics_sequence =
+								    linphone_conference_info_get_ics_sequence(conf_info_from_original_content);
+								int exp_sequence = 0;
+								if (mgr == lise.getCMgr()) {
+									exp_sequence = 0;
+								} else {
+									exp_sequence = (sequence + 1);
+								}
+
+								BC_ASSERT_EQUAL(ics_sequence, exp_sequence, int, "%d");
+
+								LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
+
+								if (mgr == lise.getCMgr()) {
+									exp_state = LinphoneConferenceInfoStateNew;
+								} else {
+									exp_state = LinphoneConferenceInfoStateUpdated;
+								}
+								BC_ASSERT_EQUAL(
+								    (int)linphone_conference_info_get_state(conf_info_from_original_content),
+								    (int)exp_state, int, "%d");
+
+								linphone_conference_info_unref(conf_info_from_original_content);
+							}
+						}
+						linphone_chat_message_unref(msg);
+					}
+				}
+				participant_stats.pop_front();
+			}
+			linphone_conference_info_unref(conf_info);
+			linphone_conference_scheduler_unref(conference_scheduler);
 		}
+		ms_free(uid);
+		uid = NULL;
 
 		if (join) {
-			std::list<LinphoneCoreManager *> participants{pauline.getCMgr()};
 			std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr()};
 			std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr()};
 
@@ -190,14 +392,28 @@ static void edit_simple_conference_base(bool_t from_organizer,
 			                             focus_stat.number_of_participant_devices_joined + 2,
 			                             liblinphone_tester_sip_timeout));
 
-			wait_for_conference_streams({focus, marie, pauline, laure, michelle}, conferenceMgrs, focus.getCMgr(),
-			                            members, confAddr, TRUE);
+			std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+			for (const auto &member : members) {
+				try {
+					const auto &participantInfo = participantList.at(member);
+					memberList.insert(std::make_pair(member, participantInfo));
+				} catch (std::out_of_range &) {
+					if (member == marie.getCMgr()) {
+						memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+					} else {
+						ms_fatal("Unable to find active participant %s in the participant list",
+						         linphone_core_get_identity(member->lc));
+					}
+				}
+			}
+			wait_for_conference_streams({focus, marie, pauline, laure, michelle, lise}, conferenceMgrs, focus.getCMgr(),
+			                            memberList, confAddr, TRUE);
 
 			LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 			BC_ASSERT_PTR_NOT_NULL(fconference);
 
 			// wait bit more to detect side effect if any
-			CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] {
+			CoreManagerAssert({focus, marie, pauline, laure, michelle, lise}).waitUntil(chrono::seconds(2), [] {
 				return false;
 			});
 
@@ -328,17 +544,42 @@ static void edit_simple_conference_base(bool_t from_organizer,
 			coresList = bctbx_list_append(coresList, focus.getLc());
 		}
 
+		const char *subject = "Test characters: <S-F12><S-F11><S-F6> £$%§ (+edits)";
+		const char *description2 = "Testing characters (+edits)";
+
+		stats manager_editing_stat = manager_editing->stat;
+		LinphoneAccount *editing_account = NULL;
+		if (use_default_account) {
+			editing_account = linphone_core_get_default_account(manager_editing->lc);
+		} else {
+			editing_account = linphone_core_lookup_known_account(manager_editing->lc, alternative_address);
+		}
+		BC_ASSERT_PTR_NOT_NULL(editing_account);
+		if (editing_account) {
+			LinphoneAccountParams *account_params =
+			    linphone_account_params_clone(linphone_account_get_params(editing_account));
+			linphone_account_params_enable_rtp_bundle(account_params, enable_bundle_mode);
+			linphone_account_set_params(editing_account, account_params);
+			linphone_account_params_unref(account_params);
+		}
+
+		LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
+		if (BC_ASSERT_PTR_NOT_NULL(info)) {
+			uid = ms_strdup(linphone_conference_info_get_ics_uid(info));
+			BC_ASSERT_PTR_NOT_NULL(uid);
+			sequence = linphone_conference_info_get_ics_sequence(info);
+			linphone_conference_info_unref(info);
+		}
+
 		bool_t add = TRUE;
 		for (int attempt = 0; attempt < 3; attempt++) {
-			char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
 			ms_message("%s is trying to update conference %s - attempt %0d - %s %s",
 			           linphone_core_get_identity(manager_editing->lc), conference_address_str, attempt,
 			           (add) ? "adding" : "removing", linphone_core_get_identity(michelle.getLc()));
-			ms_free(conference_address_str);
 
 			stats focus_stat = focus.getStats();
 
-			std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
+			std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr(), lise.getCMgr()};
 			LinphoneConferenceInfo *conf_info =
 			    linphone_core_find_conference_information_from_uri(manager_editing->lc, confAddr);
 			BC_ASSERT_PTR_NOT_NULL(conf_info);
@@ -352,14 +593,13 @@ static void edit_simple_conference_base(bool_t from_organizer,
 					linphone_conference_info_remove_participant(conf_info, michelle.getCMgr()->identity);
 				}
 
-				const auto ics_participant_number = ((add) ? 3 : 2) + ((join) ? 1 : 0);
-				bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+				const auto ics_participant_number = ((add) ? 4 : 3) + ((join) ? 1 : 0);
+				const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
 				BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number, size_t, "%zu");
-				bctbx_list_free(ics_participants);
 
 				std::list<stats> participant_stats;
-				for (auto mgr :
-				     {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+				for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(),
+				                 michelle.getCMgr(), lise.getCMgr()}) {
 					participant_stats.push_back(mgr->stat);
 				}
 
@@ -408,8 +648,8 @@ static void edit_simple_conference_base(bool_t from_organizer,
 					                             manager_editing_stat.number_of_ConferenceSchedulerInvitationsSent + 1,
 					                             liblinphone_tester_sip_timeout));
 
-					for (auto mgr :
-					     {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+					for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(),
+					                 michelle.getCMgr(), lise.getCMgr()}) {
 						auto old_stats = participant_stats.front();
 						if ((mgr != focus.getCMgr()) && (mgr != manager_editing)) {
 							BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceived,
@@ -443,12 +683,21 @@ static void edit_simple_conference_base(bool_t from_organizer,
 							bctbx_list_free(chat_room_participants);
 							BC_ASSERT_PTR_NOT_NULL(cr);
 
+							int number_chat_rooms = 0;
+							if (mgr == marie.getCMgr()) {
+								number_chat_rooms = 3;
+							} else if (from_organizer || (mgr == michelle.getCMgr())) {
+								number_chat_rooms = 1;
+							} else {
+								number_chat_rooms = 2;
+							}
+
 							BC_ASSERT_EQUAL((int)bctbx_list_size(linphone_core_get_chat_rooms(mgr->lc)),
-							                (from_organizer || (mgr == michelle.getCMgr())) ? 1 : 2, int, "%d");
+							                number_chat_rooms, int, "%d");
 
 							if (cr) {
 								LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
-								linphone_chat_room_unref(cr);
+								BC_ASSERT_PTR_NOT_NULL(msg);
 
 								const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
 								BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
@@ -466,11 +715,10 @@ static void edit_simple_conference_base(bool_t from_organizer,
 										    confAddr,
 										    linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-										bctbx_list_t *ics_participants =
+										const bctbx_list_t *ics_participants =
 										    linphone_conference_info_get_participants(conf_info_from_original_content);
 										BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number,
 										                size_t, "%zu");
-										bctbx_list_free(ics_participants);
 
 										if (start_time > 0) {
 											BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(
@@ -511,6 +759,8 @@ static void edit_simple_conference_base(bool_t from_organizer,
 											} else {
 												exp_sequence = 1;
 											}
+										} else if (mgr == lise.getCMgr()) {
+											exp_sequence = (attempt + 1);
 										} else {
 											exp_sequence = (sequence + attempt + 1);
 										}
@@ -518,7 +768,6 @@ static void edit_simple_conference_base(bool_t from_organizer,
 										BC_ASSERT_EQUAL(ics_sequence, exp_sequence, int, "%d");
 
 										LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
-
 										if (mgr == michelle.getCMgr()) {
 											if (add) {
 												exp_state = LinphoneConferenceInfoStateNew;
@@ -548,8 +797,8 @@ static void edit_simple_conference_base(bool_t from_organizer,
 				}
 				linphone_conference_scheduler_unref(conference_scheduler);
 
-				for (auto mgr :
-				     {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+				for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(),
+				                 michelle.getCMgr(), lise.getCMgr()}) {
 					LinphoneConferenceInfo *info =
 					    linphone_core_find_conference_information_from_uri(mgr->lc, confAddr);
 					if (!use_default_account && (mgr == michelle.getCMgr())) {
@@ -574,10 +823,9 @@ static void edit_simple_conference_base(bool_t from_organizer,
 
 						unsigned int exp_sequence = 0;
 						LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
-						if ((mgr == focus.getCMgr()) || !use_default_account) {
+						if (mgr == focus.getCMgr()) {
 							exp_sequence = 0;
-							exp_state = use_default_account ? LinphoneConferenceInfoStateUpdated
-							                                : LinphoneConferenceInfoStateNew;
+							exp_state = LinphoneConferenceInfoStateUpdated;
 						} else {
 							if (mgr == michelle.getCMgr()) {
 								if (add) {
@@ -585,6 +833,9 @@ static void edit_simple_conference_base(bool_t from_organizer,
 								} else {
 									exp_state = LinphoneConferenceInfoStateCancelled;
 								}
+							} else if (mgr == lise.getCMgr()) {
+								exp_state = use_default_account ? LinphoneConferenceInfoStateUpdated
+								                                : LinphoneConferenceInfoStateNew;
 							} else {
 								exp_state = LinphoneConferenceInfoStateUpdated;
 							}
@@ -594,14 +845,17 @@ static void edit_simple_conference_base(bool_t from_organizer,
 								} else {
 									exp_sequence = 1;
 								}
+							} else if (mgr == lise.getCMgr()) {
+								exp_sequence = use_default_account ? (attempt + 1) : 0;
 							} else {
-								exp_sequence = (sequence + attempt + 1);
+								exp_sequence = use_default_account ? (sequence + attempt + 1) : 1;
 							}
 						}
 						check_conference_info(mgr, confAddr, marie.getCMgr(),
-						                      ((use_default_account && add) ? 3 : 2) + ((join) ? 1 : 0), start_time,
-						                      duration, exp_subject, exp_description, exp_sequence, exp_state,
-						                      security_level);
+						                      ((use_default_account && add) ? 4 : 3) +
+						                          ((join || (mgr == focus.getCMgr())) ? 1 : 0),
+						                      start_time, duration, exp_subject, exp_description, exp_sequence,
+						                      exp_state, security_level);
 
 						if (mgr != focus.getCMgr()) {
 							for (auto &p : participants) {
@@ -609,10 +863,14 @@ static void edit_simple_conference_base(bool_t from_organizer,
 								// If not using the default account (which was used to create the conference), the
 								// conference scheduler errors out and Michelle is not added
 								if ((use_default_account) || (p != michelle.getCMgr())) {
-									if ((!use_default_account) || (p == michelle.getCMgr())) {
+									if (!use_default_account) {
+										exp_participant_sequence = (p == lise.getCMgr()) ? 0 : 1;
+									} else if (p == michelle.getCMgr()) {
 										exp_participant_sequence = 0;
-									} else {
+									} else if (p == lise.getCMgr()) {
 										exp_participant_sequence = attempt + 1;
+									} else {
+										exp_participant_sequence = attempt + 2;
 									}
 									linphone_conference_info_check_participant(info, p->identity,
 									                                           exp_participant_sequence);
@@ -620,9 +878,9 @@ static void edit_simple_conference_base(bool_t from_organizer,
 							}
 							int exp_organizer_sequence = 0;
 							if (use_default_account) {
-								exp_organizer_sequence = attempt + 1;
+								exp_organizer_sequence = attempt + 2;
 							} else {
-								exp_organizer_sequence = 0;
+								exp_organizer_sequence = 1;
 							}
 							linphone_conference_info_check_organizer(info, exp_organizer_sequence);
 						}
@@ -636,6 +894,7 @@ static void edit_simple_conference_base(bool_t from_organizer,
 			add = !add;
 		}
 		ms_free(uid);
+		ms_free(conference_address_str);
 		linphone_address_unref(alternative_address);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
@@ -643,26 +902,30 @@ static void edit_simple_conference_base(bool_t from_organizer,
 }
 
 static void organizer_edits_simple_conference(void) {
-	edit_simple_conference_base(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, LinphoneConferenceSecurityLevelNone);
+	edit_simple_conference_base(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, LinphoneConferenceSecurityLevelNone, FALSE);
 }
 static void organizer_edits_simple_conference_using_different_account(void) {
-	edit_simple_conference_base(TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, LinphoneConferenceSecurityLevelNone);
+	edit_simple_conference_base(TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, LinphoneConferenceSecurityLevelNone, FALSE);
 }
 
 static void organizer_edits_simple_conference_while_active(void) {
-	edit_simple_conference_base(TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, LinphoneConferenceSecurityLevelNone);
+	edit_simple_conference_base(TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, LinphoneConferenceSecurityLevelNone, FALSE);
 }
 
 static void participant_edits_simple_conference(void) {
-	edit_simple_conference_base(FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, LinphoneConferenceSecurityLevelNone);
+	edit_simple_conference_base(FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, LinphoneConferenceSecurityLevelNone, FALSE);
 }
 
 static void participant_edits_simple_conference_using_different_account(void) {
-	edit_simple_conference_base(FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, LinphoneConferenceSecurityLevelNone);
+	edit_simple_conference_base(FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, LinphoneConferenceSecurityLevelNone, FALSE);
 }
 
 static void organizer_edits_simple_conference_with_server_restart(void) {
-	edit_simple_conference_base(TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, LinphoneConferenceSecurityLevelNone);
+	edit_simple_conference_base(TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, LinphoneConferenceSecurityLevelNone, FALSE);
+}
+
+static void conference_edition_with_participant_role_changed(void) {
+	edit_simple_conference_base(TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, LinphoneConferenceSecurityLevelNone, TRUE);
 }
 
 static void conference_edition_with_simultaneous_participant_add_remove_base(bool_t codec_mismatch) {
@@ -722,7 +985,14 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 		const char *description = "Testing characters";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -761,9 +1031,8 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 		linphone_conference_info_add_participant(conf_info, michelle.getCMgr()->identity);
 		linphone_conference_info_remove_participant(conf_info, laure.getCMgr()->identity);
 
-		bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+		const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
 		BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participants.size(), size_t, "%zu");
-		bctbx_list_free(ics_participants);
 
 		std::list<stats> participant_stats;
 		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
@@ -843,7 +1112,7 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 
 				if (cr) {
 					LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
-					linphone_chat_room_unref(cr);
+					BC_ASSERT_PTR_NOT_NULL(msg);
 
 					const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
 					BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
@@ -859,10 +1128,9 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 							BC_ASSERT_TRUE(linphone_address_weak_equal(
 							    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-							bctbx_list_t *ics_participants =
+							const bctbx_list_t *ics_participants =
 							    linphone_conference_info_get_participants(conf_info_from_original_content);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participants.size(), size_t, "%zu");
-							bctbx_list_free(ics_participants);
 
 							if (start_time > 0) {
 								BC_ASSERT_EQUAL(
@@ -998,7 +1266,14 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 		const char *description = "Testing characters";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -1106,7 +1381,7 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 
 				if (cr) {
 					LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
-					linphone_chat_room_unref(cr);
+					BC_ASSERT_PTR_NOT_NULL(msg);
 
 					const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
 					BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
@@ -1122,10 +1397,9 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 							BC_ASSERT_TRUE(linphone_address_weak_equal(
 							    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-							bctbx_list_t *ics_participants =
+							const bctbx_list_t *ics_participants =
 							    linphone_conference_info_get_participants(conf_info_from_original_content);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 3, size_t, "%zu");
-							bctbx_list_free(ics_participants);
 
 							if (start_time > 0) {
 								BC_ASSERT_EQUAL(
@@ -1219,9 +1493,8 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 		linphone_conference_info_set_subject(conf_info, subject);
 		linphone_conference_info_set_description(conf_info, description2);
 
-		bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+		const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
 		BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 3, size_t, "%zu");
-		bctbx_list_free(ics_participants);
 
 		conference_scheduler = linphone_core_create_conference_scheduler(marie.getLc());
 		linphone_conference_scheduler_set_account(conference_scheduler, editing_account);
@@ -1304,7 +1577,7 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 
 				if (cr) {
 					LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
-					linphone_chat_room_unref(cr);
+					BC_ASSERT_PTR_NOT_NULL(msg);
 
 					const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
 					BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
@@ -1320,10 +1593,9 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 							BC_ASSERT_TRUE(linphone_address_weak_equal(
 							    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-							bctbx_list_t *ics_participants =
+							const bctbx_list_t *ics_participants =
 							    linphone_conference_info_get_participants(conf_info_from_original_content);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 0, size_t, "%zu");
-							bctbx_list_free(ics_participants);
 
 							if (start_time > 0) {
 								BC_ASSERT_EQUAL(
@@ -1432,6 +1704,8 @@ static test_t local_conference_conference_edition_tests[] = {
     TEST_NO_TAG("Conference cancelled through edit", LinphoneTest::conference_cancelled_through_edit),
     TEST_NO_TAG("Conference edition with simultanoues participant added removed",
                 LinphoneTest::conference_edition_with_simultaneous_participant_add_remove),
+    TEST_NO_TAG("Conference edition with participant role changed",
+                LinphoneTest::conference_edition_with_participant_role_changed),
     TEST_NO_TAG("Conference edition with organizer codec mismatch",
                 LinphoneTest::conference_edition_with_organizer_codec_mismatch),
     TEST_NO_TAG("Create conference with server restart (conference cancelled)",
diff --git a/tester/local_conference_tester.cpp b/tester/local_conference_tester.cpp
new file mode 100644
index 0000000000..10243dc51c
--- /dev/null
+++ b/tester/local_conference_tester.cpp
@@ -0,0 +1,17485 @@
+/*
+ * copyright (c) 2010-2022 belledonne communications sarl.
+ *
+ * This file is part of Liblinphone
+ * (see https://gitlab.linphone.org/BC/public/liblinphone).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <map>
+
+#include "bctoolbox/crypto.h"
+#include "bctoolbox/ownership.hh"
+#include <bctoolbox/defs.h>
+
+#include "address/address.h"
+#include "bctoolbox/crypto.h"
+#include "c-wrapper/c-wrapper.h"
+#include "chat/chat-room/chat-room.h"
+#include "chat/chat-room/server-group-chat-room-p.h"
+#include "conference/participant.h"
+#include "core/core.h"
+#include "liblinphone_tester++.h"
+#include "liblinphone_tester.h"
+#include "linphone/api/c-chat-room-params.h"
+#include "linphone/api/c-chat-room.h"
+#include "linphone/api/c-participant-info.h"
+#include "linphone/api/c-types.h"
+#include "linphone/core.h"
+#include "linphone/wrapper_utils.h"
+#include "shared_tester_functions.h"
+#include "tester_utils.h"
+
+#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
+#pragma GCC diagnostic push
+#endif
+#ifdef _MSC_VER
+#pragma warning(disable : 4996)
+#endif
+
+using namespace LinphonePrivate;
+using namespace std;
+using namespace Linphone::Tester;
+using namespace ownership;
+
+void setup_conference_info_cbs(LinphoneCoreManager *mgr) {
+	// Needed to send the ICS
+	linphone_core_set_file_transfer_server(mgr->lc, file_transfer_url);
+}
+
+namespace LinphoneTest {
+
+class BcAssert {
+public:
+	void addCustomIterate(const std::function<void()> &iterate) {
+		mIterateFuncs.push_back(iterate);
+	}
+	bool waitUntil(std::chrono::duration<double> timeout, const std::function<bool()> &condition) {
+		auto start = std::chrono::steady_clock::now();
+
+		bool_t result;
+		while (!(result = condition()) && (std::chrono::steady_clock::now() - start < timeout)) {
+			for (const std::function<void()> &iterate : mIterateFuncs) {
+				iterate();
+			}
+			ms_usleep(100);
+		}
+		return result;
+	}
+	bool wait(const std::function<bool()> &condition) {
+		return waitUntil(std::chrono::seconds(10), condition);
+	}
+
+private:
+	std::list<std::function<void()>> mIterateFuncs;
+};
+
+class CoreAssert : public BcAssert {
+public:
+	CoreAssert(std::initializer_list<std::shared_ptr<Core>> cores) {
+		for (shared_ptr<Core> core : cores) {
+			addCustomIterate([core] { linphone_core_iterate(L_GET_C_BACK_PTR(core)); });
+		}
+	}
+};
+
+class ClientConference;
+
+class ConfCoreManager : public CoreManager {
+public:
+	ConfCoreManager(std::string rc) : CoreManager(rc.c_str()) {
+		mMgr->user_info = this;
+	}
+
+	ConfCoreManager(std::string rc, const std::function<void()> &preStart)
+	    : CoreManager(owned(linphone_core_manager_create(rc.c_str()))), mPreStart(preStart) {
+		mMgr->user_info = this;
+		mPreStart();
+		start(true);
+	}
+
+	void reStart(bool check_for_proxies = true) {
+		linphone_core_manager_reinit(mMgr.get());
+		mPreStart();
+		start(check_for_proxies);
+	}
+
+	void configureCoreForConference(const Address &factoryUri) {
+		_configure_core_for_conference(mMgr.get(), factoryUri.toC());
+	}
+	void setupMgrForConference(const char *conferenceVersion = nullptr) {
+		setup_mgr_for_conference(mMgr.get(), conferenceVersion);
+	}
+	BorrowedMut<LinphoneChatRoom> searchChatRoom(const LinphoneAddress *localAddr,
+	                                             const LinphoneAddress *remoteAddr,
+	                                             const bctbx_list_t *participants = nullptr,
+	                                             const LinphoneChatRoomParams *params = nullptr) {
+		return borrowed_mut(linphone_core_search_chat_room(mMgr->lc, params, localAddr, remoteAddr, participants));
+	}
+	LinphoneProxyConfig *getDefaultProxyConfig() const {
+		return linphone_core_get_default_proxy_config(mMgr->lc);
+	}
+	stats &getStats() const {
+		return mMgr->stat;
+	}
+	LinphoneCoreManager *getCMgr() {
+		return mMgr.get();
+	};
+	BorrowedMut<LinphoneCore> getLc() const {
+		return borrowed_mut(mMgr->lc);
+	};
+
+private:
+	const std::function<void()> mPreStart = [] { return; };
+};
+
+class CoreManagerAssert : public BcAssert {
+public:
+	CoreManagerAssert(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs) : BcAssert() {
+		for (CoreManager &coreMgr : coreMgrs) {
+			addCustomIterate([&coreMgr] { coreMgr.iterate(); });
+		}
+	}
+
+	CoreManagerAssert(std::list<std::reference_wrapper<CoreManager>> coreMgrs) : BcAssert() {
+		for (CoreManager &coreMgr : coreMgrs) {
+			addCustomIterate([&coreMgr] { coreMgr.iterate(); });
+		}
+	}
+};
+class Focus;
+
+/*Core manager acting as a client*/
+class ClientConference : public ConfCoreManager {
+public:
+	ClientConference(std::string rc, Address factoryUri, bool encrypted = false)
+	    : ConfCoreManager(rc,
+	                      [this, factoryUri, encrypted] {
+		                      configureCoreForConference(factoryUri);
+		                      _configure_core_for_audio_video_conference(mMgr.get(), factoryUri.toC());
+		                      setupMgrForConference();
+		                      LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
+		                      linphone_core_cbs_set_chat_room_state_changed(cbs, core_chat_room_state_changed);
+		                      linphone_core_cbs_set_chat_room_subject_changed(cbs, core_chat_room_subject_changed);
+		                      linphone_core_add_callbacks(getLc(), cbs);
+		                      linphone_core_cbs_unref(cbs);
+		                      if (encrypted) {
+			                      set_lime_server_and_curve(25519, mMgr.get());
+		                      }
+	                      }),
+	      mFocus(nullptr) {
+	}
+
+	void deleteChatRoomSync(AbstractChatRoom &chatroom) {
+		linphone_core_delete_chat_room(getLc(), L_GET_C_BACK_PTR(&chatroom));
+		CoreManagerAssert({*mFocus, *this}).wait([&chatroom] {
+			return chatroom.getState() == ChatRoom::State::Deleted;
+		});
+	}
+
+	~ClientConference() {
+		for (auto chatRoom : getCore().getChatRooms()) {
+			deleteChatRoomSync(*chatRoom);
+		}
+		if (mMgr->user_info) {
+			ms_free(mMgr->user_info);
+		}
+	}
+
+	static LinphoneChatMessage *sendTextMsg(LinphoneChatRoom *cr, const std::string text) {
+		LinphoneChatMessage *msg = nullptr;
+		if (cr && !text.empty()) {
+			lInfo() << " Chat room " << L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceId()
+			        << " is sending message with text " << text;
+			msg = linphone_chat_room_create_message_from_utf8(cr, text.c_str());
+			BC_ASSERT_PTR_NOT_NULL(msg);
+			LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg);
+			linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
+			linphone_chat_message_send(msg);
+		}
+		return msg;
+	}
+
+	friend Focus;
+
+protected:
+	void setFocus(BorrowedMut<CoreManager> myFocus) {
+		mFocus = myFocus;
+	}
+
+private:
+	BorrowedMut<CoreManager> mFocus;
+};
+
+/* Core manager acting as a focus*/
+class Focus : public ConfCoreManager {
+public:
+	Focus(std::string rc) : ConfCoreManager(rc, [this] { linphone_core_enable_conference_server(getLc(), TRUE); }) {
+		configureFocus();
+	}
+	~Focus() {
+		CoreManagerAssert({*this}).waitUntil(chrono::seconds(1), [] { return false; });
+	}
+
+	void registerAsParticipantDevice(ClientConference &otherMgr) {
+		const LinphoneAddress *cAddr = linphone_proxy_config_get_contact(otherMgr.getDefaultProxyConfig());
+		Address participantDevice = Address::toCpp(const_cast<LinphoneAddress *>(cAddr))->getUri();
+		Address participant = participantDevice.getUriWithoutGruu();
+		mParticipantDevices.insert({participant, participantDevice});
+		// to allow client conference to delete chatroom in its destructor
+		otherMgr.setFocus(borrowed_mut(this));
+	}
+
+	void subscribeParticipantDevice(const LinphoneAddress *conferenceAddress,
+	                                const LinphoneAddress *participantDevice) {
+		auto cr = searchChatRoom(conferenceAddress, conferenceAddress);
+		BC_ASSERT_PTR_NOT_NULL(cr);
+		//	CALL_CHAT_ROOM_CBS(cr, ParticipantRegistrationSubscriptionRequested,
+		// participant_registration_subscription_requested, cr, participantDevice)
+		_linphone_chat_room_notify_participant_registration_subscription_requested(cr, participantDevice);
+	}
+
+	void notifyParticipantDeviceRegistration(const LinphoneAddress *conferenceAddress,
+	                                         const LinphoneAddress *participantDevice) {
+		auto cr = searchChatRoom(conferenceAddress, conferenceAddress);
+		BC_ASSERT_PTR_NOT_NULL(cr);
+		linphone_chat_room_notify_participant_device_registration(cr, participantDevice);
+	}
+
+	void reStart(bool check_for_proxies = TRUE) {
+		ConfCoreManager::reStart(check_for_proxies);
+		configureFocus();
+	}
+
+private:
+	static void server_core_chat_room_conference_address_generation(LinphoneChatRoom *cr) {
+		Focus *focus =
+		    (Focus *)(((LinphoneCoreManager *)linphone_core_get_user_data(linphone_chat_room_get_core(cr)))->user_info);
+		char config_id[6];
+		belle_sip_random_token(config_id, sizeof(config_id));
+		LinphoneAddress *conference_address =
+		    linphone_address_clone(linphone_proxy_config_get_contact(focus->getDefaultProxyConfig()));
+		linphone_address_set_uri_param(conference_address, "conf-id", config_id);
+		linphone_chat_room_set_conference_address(cr, conference_address);
+		linphone_address_unref(conference_address);
+	}
+
+	static void
+	server_core_chat_room_state_changed(LinphoneCore *core, LinphoneChatRoom *cr, LinphoneChatRoomState state) {
+		Focus *focus = (Focus *)(((LinphoneCoreManager *)linphone_core_get_user_data(core))->user_info);
+		switch (state) {
+			case LinphoneChatRoomStateInstantiated: {
+				LinphoneChatRoomCbs *cbs = linphone_factory_create_chat_room_cbs(linphone_factory_get());
+				linphone_chat_room_cbs_set_participant_registration_subscription_requested(
+				    cbs, chat_room_participant_registration_subscription_requested);
+				linphone_chat_room_cbs_set_conference_address_generation(
+				    cbs, server_core_chat_room_conference_address_generation);
+				setup_chat_room_callbacks(cbs);
+				linphone_chat_room_add_callbacks(cr, cbs);
+				linphone_chat_room_cbs_set_user_data(cbs, focus);
+				linphone_chat_room_cbs_unref(cbs);
+				break;
+			}
+			default:
+				break;
+		}
+	}
+
+	static void chat_room_participant_registration_subscription_requested(LinphoneChatRoom *cr,
+	                                                                      const LinphoneAddress *participantAddr) {
+		BC_ASSERT_PTR_NOT_NULL(participantAddr);
+		if (participantAddr) {
+			Address participant = Address::toCpp(const_cast<LinphoneAddress *>(participantAddr))->getUri();
+			BC_ASSERT_TRUE(participant.isValid());
+			if (participant.isValid()) {
+				Focus *focus =
+				    (Focus *)(linphone_chat_room_cbs_get_user_data(linphone_chat_room_get_current_callbacks(cr)));
+				bctbx_list_t *devices = NULL;
+				auto participantRange = focus->mParticipantDevices.equal_range(participant);
+				for (auto participantIt = participantRange.first; participantIt != participantRange.second;
+				     participantIt++) {
+					LinphoneAddress *deviceAddr = linphone_address_new(participantIt->second.toString().c_str());
+					LinphoneParticipantDeviceIdentity *identity =
+					    linphone_factory_create_participant_device_identity(linphone_factory_get(), deviceAddr, "");
+					linphone_participant_device_identity_set_capability_descriptor(
+					    identity, linphone_core_get_linphone_specs(linphone_chat_room_get_core(cr)));
+					devices = bctbx_list_append(devices, identity);
+					linphone_address_unref(deviceAddr);
+				}
+				linphone_chat_room_set_participant_devices(cr, participant.toC(), devices);
+				bctbx_list_free_with_data(devices, (bctbx_list_free_func)belle_sip_object_unref);
+			}
+		}
+	}
+
+	void configureFocus() {
+		LinphoneCoreCbs *cbs = linphone_core_get_first_callbacks(getLc());
+		linphone_config_set_int(linphone_core_get_config(getLc()), "misc", "hide_empty_chat_rooms", 0);
+		linphone_config_set_int(linphone_core_get_config(getLc()), "sip", "reject_duplicated_calls", 0);
+		linphone_config_set_int(linphone_core_get_config(getLc()), "misc", "hide_chat_rooms_from_removed_proxies", 0);
+		linphone_core_enable_rtp_bundle(getLc(), TRUE);
+
+		LinphoneAccount *account = linphone_core_get_default_account(getLc());
+		const LinphoneAccountParams *account_params = linphone_account_get_params(account);
+		LinphoneAccountParams *new_account_params = linphone_account_params_clone(account_params);
+		linphone_account_params_enable_rtp_bundle(new_account_params, TRUE);
+		linphone_account_params_set_conference_factory_uri(new_account_params, getIdentity().toString().c_str());
+		linphone_account_set_params(account, new_account_params);
+		linphone_account_params_unref(new_account_params);
+		BC_ASSERT_TRUE(linphone_account_params_rtp_bundle_enabled(linphone_account_get_params(account)));
+
+		linphone_core_cbs_set_subscription_state_changed(cbs, linphone_subscription_state_change);
+		linphone_core_cbs_set_chat_room_state_changed(cbs, server_core_chat_room_state_changed);
+		//		linphone_core_cbs_set_refer_received(cbs, linphone_conference_server_refer_received);
+	}
+
+	std::multimap<Address, Address> mParticipantDevices;
+};
+
+void sendEphemeralMessageInAdminMode(Focus &focus,
+                                     ClientConference &sender,
+                                     ClientConference &recipient,
+                                     LinphoneChatRoom *senderCr,
+                                     LinphoneChatRoom *recipientCr,
+                                     const std::string basicText,
+                                     const int noMsg) {
+
+	bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+	coresList = bctbx_list_append(coresList, sender.getLc());
+	coresList = bctbx_list_append(coresList, recipient.getLc());
+
+	bctbx_list_t *senderHistory = linphone_chat_room_get_history(senderCr, 0);
+	auto initialSenderMessages = (int)bctbx_list_size(senderHistory);
+	bctbx_list_free_with_data(senderHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+
+	bctbx_list_t *recipientHistory = linphone_chat_room_get_history(recipientCr, 0);
+	auto initialRecipientMessages = (int)bctbx_list_size(recipientHistory);
+	bctbx_list_free_with_data(recipientHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+
+	int initialUnreadMessages = linphone_chat_room_get_unread_messages_count(recipientCr);
+
+	auto sender_stat = sender.getStats();
+	auto recipient_stat = recipient.getStats();
+
+	std::list<LinphoneChatMessage *> messages;
+	// Marie sends messages
+	for (int i = 0; i < noMsg; i++) {
+		const std::string text = basicText + std::to_string(i);
+		messages.push_back(_send_message_ephemeral(senderCr, text.c_str(), TRUE));
+	}
+
+	senderHistory = linphone_chat_room_get_history(senderCr, 0);
+	BC_ASSERT_EQUAL((int)bctbx_list_size(senderHistory), (noMsg + initialSenderMessages), int, "%i");
+	set_ephemeral_cbs(senderHistory);
+
+	BC_ASSERT_TRUE(wait_for_list(coresList, &recipient.getStats().number_of_LinphoneMessageReceived,
+	                             recipient_stat.number_of_LinphoneMessageReceived + noMsg, 11000));
+
+	// Check that the message has been delivered to Pauline
+	for (const auto &msg : messages) {
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, sender, recipient}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+	}
+
+	BC_ASSERT_TRUE(CoreManagerAssert({focus, sender, recipient}).wait([&, recipientCr] {
+		return linphone_chat_room_get_unread_messages_count(recipientCr) == (noMsg + initialUnreadMessages);
+	}));
+
+	recipientHistory = linphone_chat_room_get_history(recipientCr, 0);
+	BC_ASSERT_EQUAL((int)bctbx_list_size(recipientHistory), (noMsg + initialRecipientMessages), int, "%i");
+	set_ephemeral_cbs(recipientHistory);
+
+	BC_ASSERT_TRUE(wait_for_list(coresList, &sender.getStats().number_of_LinphoneMessageDeliveredToUser,
+	                             sender_stat.number_of_LinphoneMessageDeliveredToUser + noMsg,
+	                             liblinphone_tester_sip_timeout));
+
+	// Pauline marks the message as read, check that the state is now displayed on Marie's side
+	linphone_chat_room_mark_as_read(recipientCr);
+	BC_ASSERT_TRUE(wait_for_list(coresList, &sender.getStats().number_of_LinphoneMessageDisplayed,
+	                             sender_stat.number_of_LinphoneMessageDisplayed + noMsg,
+	                             liblinphone_tester_sip_timeout));
+
+	BC_ASSERT_TRUE(wait_for_list(coresList, &sender.getStats().number_of_LinphoneChatRoomEphemeralTimerStarted,
+	                             sender_stat.number_of_LinphoneChatRoomEphemeralTimerStarted + noMsg,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(coresList, &recipient.getStats().number_of_LinphoneChatRoomEphemeralTimerStarted,
+	                             recipient_stat.number_of_LinphoneChatRoomEphemeralTimerStarted + noMsg,
+	                             liblinphone_tester_sip_timeout));
+
+	BC_ASSERT_TRUE(wait_for_list(coresList, &sender.getStats().number_of_LinphoneMessageEphemeralTimerStarted,
+	                             sender_stat.number_of_LinphoneMessageEphemeralTimerStarted + noMsg,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(coresList, &recipient.getStats().number_of_LinphoneMessageEphemeralTimerStarted,
+	                             recipient_stat.number_of_LinphoneMessageEphemeralTimerStarted + noMsg,
+	                             liblinphone_tester_sip_timeout));
+
+	BC_ASSERT_TRUE(wait_for_list(coresList, &sender.getStats().number_of_LinphoneChatRoomEphemeralDeleted,
+	                             sender_stat.number_of_LinphoneChatRoomEphemeralDeleted + noMsg, 15000));
+	BC_ASSERT_TRUE(wait_for_list(coresList, &recipient.getStats().number_of_LinphoneChatRoomEphemeralDeleted,
+	                             recipient_stat.number_of_LinphoneChatRoomEphemeralDeleted + noMsg, 15000));
+
+	BC_ASSERT_TRUE(wait_for_list(coresList, &sender.getStats().number_of_LinphoneMessageEphemeralDeleted,
+	                             sender_stat.number_of_LinphoneMessageEphemeralDeleted + noMsg, 15000));
+	BC_ASSERT_TRUE(wait_for_list(coresList, &recipient.getStats().number_of_LinphoneMessageEphemeralDeleted,
+	                             recipient_stat.number_of_LinphoneMessageEphemeralDeleted + noMsg, 15000));
+
+	bctbx_list_free_with_data(recipientHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+	bctbx_list_free_with_data(senderHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+
+	// wait bit more to detect side effect if any
+	CoreManagerAssert({focus, sender, recipient}).waitUntil(chrono::seconds(2), [] { return false; });
+
+	recipientHistory = linphone_chat_room_get_history(recipientCr, 0);
+	BC_ASSERT_EQUAL((int)bctbx_list_size(recipientHistory), initialRecipientMessages, int, "%i");
+	senderHistory = linphone_chat_room_get_history(senderCr, 0);
+	BC_ASSERT_EQUAL((int)bctbx_list_size(senderHistory), initialSenderMessages, int, "%i");
+
+	for (auto &msg : messages) {
+		linphone_chat_message_unref(msg);
+	}
+
+	bctbx_list_free_with_data(recipientHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+	bctbx_list_free_with_data(senderHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+	bctbx_list_free(coresList);
+}
+
+bool checkChatroom(Focus &focus, const ConfCoreManager &core, const time_t baseJoiningTime) {
+	const auto &chatRooms = core.getCore().getChatRooms();
+	if (chatRooms.size() < 1) {
+		return false;
+	}
+
+	for (const auto &chatRoom : chatRooms) {
+		auto participants = chatRoom->getParticipants();
+		if (focus.getLc() != core.getLc()) {
+			participants.push_back(chatRoom->getMe());
+		}
+		for (const auto &participant : participants) {
+			for (const auto &device : participant->getDevices()) {
+				if (device->getState() != ParticipantDevice::State::Present) {
+					return false;
+				}
+				if (linphone_participant_device_is_in_conference(device->toC()) == FALSE) {
+					return false;
+				}
+				if ((baseJoiningTime >= 0) &&
+				    (linphone_participant_device_get_time_of_joining(device->toC()) >= baseJoiningTime)) {
+					return false;
+				}
+			}
+		}
+	}
+	return true;
+}
+
+static void group_chat_room_creation_server(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+
+		Address paulineAddr = pauline.getIdentity();
+		Address laureAddr = laure.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(laureAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+		stats initialPaulineStats = pauline.getStats();
+		stats initialLaureStats = laure.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues @work";
+		LinphoneChatRoom *marieCr =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
+		                                 initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(
+		    coresList, pauline.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 2, FALSE);
+		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure.getCMgr(), &initialLaureStats,
+		                                                                 confAddr, initialSubject, 2, FALSE);
+
+		// Marie now changes the subject
+		const char *newSubject = "Let's go drink a beer #party";
+		linphone_chat_room_set_subject(marieCr, newSubject);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_subject_changed,
+		                             initialMarieStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed,
+		                             initialPaulineStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_subject_changed,
+		                             initialLaureStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(marieCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(paulineCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(laureCr), newSubject);
+
+		// Bring Laure offline and remove her from the chat room
+		// As Laure is offline, she is not notified of the removal
+		linphone_core_set_network_reachable(laure.getLc(), FALSE);
+		BC_ASSERT_FALSE(linphone_core_is_network_reachable(laure.getLc()));
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(std::chrono::seconds(1), [] { return false; });
+		LinphoneParticipant *laureParticipant = linphone_chat_room_find_participant(marieCr, laureAddr.toC());
+		BC_ASSERT_PTR_NOT_NULL(laureParticipant);
+		linphone_chat_room_remove_participant(marieCr, laureParticipant);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+		                             initialMarieStats.number_of_participants_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_removed,
+		                             initialPaulineStats.number_of_participants_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Check that Laure's conference is not destroyed
+		BC_ASSERT_EQUAL(laure.getStats().number_of_LinphoneConferenceStateTerminated,
+		                initialLaureStats.number_of_LinphoneConferenceStateTerminated, int, "%d");
+
+		coresList = bctbx_list_remove(coresList, focus.getLc());
+		// Restart flexisip
+		focus.reStart();
+		coresList = bctbx_list_append(coresList, focus.getLc());
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+
+			BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(L_GET_C_BACK_PTR(chatRoom)), 3, int, "%d");
+		}
+
+		BC_ASSERT_FALSE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateTerminated,
+		                              initialLaureStats.number_of_LinphoneConferenceStateTerminated + 1, 3000));
+
+		// Laure comes back online and its chatroom is expected to be deleted
+		linphone_core_set_network_reachable(laure.getLc(), TRUE);
+		LinphoneAddress *laureDeviceAddress = linphone_address_clone(
+		    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(laure.getLc())));
+		// Notify chat room that a participant has registered
+		focus.notifyParticipantDeviceRegistration(linphone_chat_room_get_conference_address(marieCr),
+		                                          laureDeviceAddress);
+		linphone_address_unref(laureDeviceAddress);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             initialLaureStats.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(L_GET_C_BACK_PTR(chatRoom)), 3, int, "%d");
+		}
+
+		linphone_chat_room_leave(paulineCr);
+	}
+}
+
+static void group_chat_room_server_deletion(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+		stats initialPaulineStats = pauline.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues #together";
+		LinphoneChatRoom *marieCr =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
+		                                 initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(
+		    coresList, pauline.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 1, FALSE);
+
+		/*BC_ASSERT_TRUE(*/ CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}) /*)*/;
+
+		LinphoneChatMessage *msg = linphone_chat_room_create_message_from_utf8(marieCr, "message blabla");
+		linphone_chat_message_send(msg);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// Clean db from chat room
+		linphone_chat_message_unref(msg);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_server_deletion_with_rmt_lst_event_handler(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+		stats initialPaulineStats = pauline.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		LinphoneChatRoom *marieCr =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
+		                                 initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(
+		    coresList, pauline.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 1, FALSE);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		LinphoneChatMessage *msg = linphone_chat_room_create_message_from_utf8(marieCr, "message blabla");
+		linphone_chat_message_send(msg);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+
+		// now with simulate foregound/backgroud switch to get a remote event handler list instead of a simple remote
+		// event handler
+		linphone_core_enter_background(pauline.getLc());
+		linphone_config_set_bool(linphone_core_get_config(pauline.getLc()), "misc",
+		                         "conference_event_package_force_full_state", TRUE);
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(std::chrono::seconds(1), [] { return false; });
+
+		unsigned int paulineCrNo = (unsigned int)bctbx_list_size(linphone_core_get_chat_rooms(pauline.getLc()));
+		coresList = bctbx_list_remove(coresList, pauline.getLc());
+		pauline.reStart();
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+
+		// Wait for chat rooms to be recovered from the main DB
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateCreated,
+		                             paulineCrNo, liblinphone_tester_sip_timeout));
+		char *paulineDeviceIdentity = linphone_core_get_device_identity(pauline.getLc());
+		LinphoneAddress *paulineLocalAddr = linphone_address_new(paulineDeviceIdentity);
+		bctbx_free(paulineDeviceIdentity);
+		paulineCr = pauline.searchChatRoom(paulineLocalAddr, confAddr);
+		linphone_address_unref(paulineLocalAddr);
+		BC_ASSERT_PTR_NOT_NULL(paulineCr);
+
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(std::chrono::seconds(1), [] { return false; });
+
+		CoreManagerAssert({focus, marie}).waitUntil(std::chrono::seconds(2), [] { return false; });
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		linphone_chat_message_unref(msg);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_server_admin_managed_messages_base(bool_t encrypted) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		linphone_core_set_default_ephemeral_lifetime(marie.getLc(), 25);
+
+		// Enable IMDN
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		stats chloe_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		const LinphoneChatRoomEphemeralMode adminMode = LinphoneChatRoomEphemeralModeAdminManaged;
+		LinphoneChatRoomParams *params = linphone_core_create_default_chat_room_params(marie.getLc());
+
+		linphone_chat_room_params_enable_group(params, FALSE);
+		linphone_chat_room_params_enable_encryption(params, FALSE);
+		linphone_chat_room_params_set_ephemeral_mode(params, adminMode);
+		linphone_chat_room_params_set_ephemeral_lifetime(params, 5);
+		linphone_chat_room_params_set_backend(params, LinphoneChatRoomBackendFlexisipChat);
+
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_params(
+		    coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject, params);
+		linphone_chat_room_params_unref(params);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 1, FALSE);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 5, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 5, int, "%d");
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		chloe_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+
+		constexpr int noMsg = 10;
+		sendEphemeralMessageInAdminMode(focus, marie, pauline, marieCr, paulineCr, "Hello ", noMsg);
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_server_admin_managed_messages_unencrypted(void) {
+	group_chat_room_server_admin_managed_messages_base(FALSE);
+}
+
+static void group_chat_room_server_admin_managed_messages_ephemeral_enabled_after_creation(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		// Enable IMDN
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		stats chloe_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		const LinphoneChatRoomEphemeralMode adminMode = LinphoneChatRoomEphemeralModeAdminManaged;
+		LinphoneChatRoomParams *params = linphone_core_create_default_chat_room_params(marie.getLc());
+
+		linphone_chat_room_params_enable_group(params, FALSE);
+		linphone_chat_room_params_enable_encryption(params, FALSE);
+		linphone_chat_room_params_set_ephemeral_mode(params, adminMode);
+		linphone_chat_room_params_set_ephemeral_lifetime(params, 0);
+		linphone_chat_room_params_set_backend(params, LinphoneChatRoomBackendFlexisipChat);
+
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_params(
+		    coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject, params);
+		linphone_chat_room_params_unref(params);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		LinphoneAddress *confAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr));
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 1, FALSE);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(paulineCr));
+
+		pauline_stat = pauline.getStats();
+		linphone_chat_room_set_ephemeral_lifetime(marieCr, 10);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_NotifyReceived,
+		                             pauline_stat.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(50), [&pauline] {
+			for (auto chatRoom : pauline.getCore().getChatRooms()) {
+				if (!chatRoom->ephemeralEnabled() || (chatRoom->getEphemeralLifetime() != 10)) {
+					return false;
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 10, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 10, int, "%d");
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		chloe_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+
+		constexpr int noMsg = 10;
+		sendEphemeralMessageInAdminMode(focus, marie, pauline, marieCr, paulineCr, "Hello ", noMsg);
+
+		coresList = bctbx_list_remove(coresList, marie.getLc());
+		marie.reStart();
+		marie.setupMgrForConference();
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+
+		// Retrieve chat room
+		LinphoneAddress *marieDeviceAddr =
+		    linphone_address_clone(linphone_proxy_config_get_contact(marie.getDefaultProxyConfig()));
+		marieCr = marie.searchChatRoom(marieDeviceAddr, confAddr);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+
+		// Wait for chat rooms to be recovered from the main DB
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		if (marieCr) {
+			BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 10, int, "%d");
+
+			marie_stat = marie.getStats();
+			pauline_stat = pauline.getStats();
+
+			linphone_chat_room_set_ephemeral_lifetime(marieCr, 5);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+			                             marie_stat.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 5, int, "%d");
+
+			sendEphemeralMessageInAdminMode(focus, marie, pauline, marieCr, paulineCr, "Back online ", noMsg);
+		}
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		linphone_address_unref(marieDeviceAddr);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_server_admin_managed_messages_ephemeral_disabled_after_creation(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		// Enable IMDN
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+
+		linphone_core_set_default_ephemeral_lifetime(marie.getLc(), 1);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		stats chloe_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		const LinphoneChatRoomEphemeralMode adminMode = LinphoneChatRoomEphemeralModeAdminManaged;
+		LinphoneChatRoom *marieCr = create_chat_room_client_side(
+		    coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject, FALSE, adminMode);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		LinphoneAddress *confAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr));
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 1, FALSE);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 1, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 1, int, "%d");
+
+		pauline_stat = pauline.getStats();
+		linphone_chat_room_set_ephemeral_lifetime(marieCr, 0);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneChatRoomEphemeralMessageDisabled,
+		                             pauline_stat.number_of_LinphoneChatRoomEphemeralMessageDisabled + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(50), [&pauline] {
+			for (auto chatRoom : pauline.getCore().getChatRooms()) {
+				if (chatRoom->ephemeralEnabled()) {
+					return false;
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(paulineCr));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		chloe_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+
+		constexpr int noMsg = 10;
+		LinphoneChatMessage *message[noMsg];
+		// Marie sends messages
+		for (int i = 0; i < noMsg; i++) {
+			const std::string text = std::string("Hello ") + std::to_string(i);
+			message[i] = _send_message_ephemeral(marieCr, text.c_str(), TRUE);
+		}
+
+		bctbx_list_t *marieHistory = linphone_chat_room_get_history(marieCr, 0);
+		BC_ASSERT_EQUAL((int)bctbx_list_size(marieHistory), noMsg, int, "%i");
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+		                             pauline_stat.number_of_LinphoneMessageReceived + noMsg, 11000));
+
+		// Check that the message has been delivered to Pauline
+		for (int i = 0; i < noMsg; i++) {
+			const auto msg = message[i];
+			BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([msg] {
+				return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+			}));
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&, paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == noMsg;
+		}));
+
+		bctbx_list_t *paulineHistory = linphone_chat_room_get_history(paulineCr, 0);
+		BC_ASSERT_EQUAL((int)bctbx_list_size(paulineHistory), noMsg, int, "%i");
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDeliveredToUser,
+		                             marie_stat.number_of_LinphoneMessageDeliveredToUser + noMsg,
+		                             liblinphone_tester_sip_timeout));
+
+		// Pauline marks the message as read, check that the state is now displayed on Marie's side
+		linphone_chat_room_mark_as_read(paulineCr);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDisplayed,
+		                             marie_stat.number_of_LinphoneMessageDisplayed + noMsg,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		bctbx_list_free_with_data(paulineHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+		bctbx_list_free_with_data(marieHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+		paulineHistory = linphone_chat_room_get_history(paulineCr, 0);
+		BC_ASSERT_EQUAL((int)bctbx_list_size(paulineHistory), noMsg, int, "%i");
+		marieHistory = linphone_chat_room_get_history(marieCr, 0);
+		BC_ASSERT_EQUAL((int)bctbx_list_size(marieHistory), noMsg, int, "%i");
+
+		bctbx_list_free_with_data(paulineHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+		bctbx_list_free_with_data(marieHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+
+		for (int i = 0; i < noMsg; i++) {
+			linphone_chat_message_unref(message[i]);
+		}
+
+		coresList = bctbx_list_remove(coresList, marie.getLc());
+		marie.reStart();
+		marie.setupMgrForConference();
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+
+		// Retrieve chat room
+		LinphoneAddress *marieDeviceAddr =
+		    linphone_address_clone(linphone_proxy_config_get_contact(marie.getDefaultProxyConfig()));
+		marieCr = marie.searchChatRoom(marieDeviceAddr, confAddr);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+
+		// Wait for chat rooms to be recovered from the main DB
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		if (marieCr) {
+			BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(marieCr));
+
+			marie_stat = marie.getStats();
+			pauline_stat = pauline.getStats();
+
+			linphone_chat_room_set_ephemeral_lifetime(marieCr, 5);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+			                             marie_stat.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(
+			    coresList, &pauline.getStats().number_of_LinphoneChatRoomEphemeralMessageEnabled,
+			    pauline_stat.number_of_LinphoneChatRoomEphemeralMessageEnabled + 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(
+			    coresList, &pauline.getStats().number_of_LinphoneChatRoomEphemeralLifetimeChanged,
+			    pauline_stat.number_of_LinphoneChatRoomEphemeralLifetimeChanged + 1, liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 5, int, "%d");
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+			BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 5, int, "%d");
+
+			sendEphemeralMessageInAdminMode(focus, marie, pauline, marieCr, paulineCr, "Back online ", noMsg);
+		}
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		linphone_address_unref(marieDeviceAddr);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_update(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+
+		linphone_core_set_default_ephemeral_lifetime(marie.getLc(), 5);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		// Enable IMDN
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		const LinphoneChatRoomEphemeralMode adminMode = LinphoneChatRoomEphemeralModeAdminManaged;
+		LinphoneChatRoom *marieCr = create_chat_room_client_side(
+		    coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject, FALSE, adminMode);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		LinphoneAddress *confAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr));
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 1, FALSE);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 5, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 5, int, "%d");
+
+		coresList = bctbx_list_remove(coresList, marie.getLc());
+		marie.reStart();
+		marie.setupMgrForConference();
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+
+		// Retrieve chat room
+		LinphoneAddress *marieDeviceAddr =
+		    linphone_address_clone(linphone_proxy_config_get_contact(marie.getDefaultProxyConfig()));
+		marieCr = marie.searchChatRoom(marieDeviceAddr, confAddr);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+
+		// Wait for chat rooms to be recovered from the main DB
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		if (marieCr) {
+			BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 5, int, "%d");
+
+			marie_stat = marie.getStats();
+			pauline_stat = pauline.getStats();
+			linphone_chat_room_set_ephemeral_lifetime(marieCr, 10);
+
+			BC_ASSERT_TRUE(wait_for_list(
+			    coresList, &pauline.getStats().number_of_LinphoneChatRoomEphemeralLifetimeChanged,
+			    pauline_stat.number_of_LinphoneChatRoomEphemeralLifetimeChanged + 1, liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+			BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 10, int, "%d");
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+			BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+			BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 10, int, "%d");
+
+			constexpr int noMsg = 10;
+			sendEphemeralMessageInAdminMode(focus, marie, pauline, marieCr, paulineCr, "Hello ", noMsg);
+		}
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		linphone_address_unref(marieDeviceAddr);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_toggle_using_different_methods(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		// Enable IMDN
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+
+		linphone_core_set_default_ephemeral_lifetime(marie.getLc(), 5);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		stats chloe_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues";
+		const LinphoneChatRoomEphemeralMode adminMode = LinphoneChatRoomEphemeralModeAdminManaged;
+		LinphoneChatRoom *marieCr = create_chat_room_client_side(
+		    coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject, FALSE, adminMode);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 1, FALSE);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 5, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 5, int, "%d");
+
+		pauline_stat = pauline.getStats();
+		linphone_chat_room_set_ephemeral_lifetime(marieCr, 10);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneChatRoomEphemeralLifetimeChanged,
+		                             pauline_stat.number_of_LinphoneChatRoomEphemeralLifetimeChanged + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 10, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 10, int, "%d");
+
+		chloe_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+
+		constexpr int noMsg = 10;
+		sendEphemeralMessageInAdminMode(focus, marie, pauline, marieCr, paulineCr, "Hello ", noMsg);
+
+		pauline_stat = pauline.getStats();
+		// Disable ephemeral
+		linphone_chat_room_set_ephemeral_lifetime(marieCr, 0);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneChatRoomEphemeralMessageDisabled,
+		                             pauline_stat.number_of_LinphoneChatRoomEphemeralMessageDisabled + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 0, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 0, int, "%d");
+
+		chloe_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+
+		LinphoneChatMessage *non_ephemeral_message;
+		// Marie sends messages
+		const std::string non_ephemeral_text = std::string("Not an ephemeral message");
+		non_ephemeral_message = _send_message_ephemeral(marieCr, non_ephemeral_text.c_str(), TRUE);
+
+		auto marieHistory = linphone_chat_room_get_history(marieCr, 0);
+		BC_ASSERT_EQUAL((int)bctbx_list_size(marieHistory), 1, int, "%i");
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+		                             pauline_stat.number_of_LinphoneMessageReceived + 1, 11000));
+
+		// Check that the message has been delivered to Pauline
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([non_ephemeral_message] {
+			return (linphone_chat_message_get_state(non_ephemeral_message) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&, paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+
+		auto paulineHistory = linphone_chat_room_get_history(paulineCr, 0);
+		BC_ASSERT_EQUAL((int)bctbx_list_size(paulineHistory), 1, int, "%i");
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDeliveredToUser,
+		                             marie_stat.number_of_LinphoneMessageDeliveredToUser + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Pauline marks the message as read, check that the state is now displayed on Marie's side
+		linphone_chat_room_mark_as_read(paulineCr);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDisplayed,
+		                             marie_stat.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		bctbx_list_free_with_data(paulineHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+		bctbx_list_free_with_data(marieHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+
+		pauline_stat = pauline.getStats();
+		linphone_chat_room_enable_ephemeral(marieCr, TRUE);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneChatRoomEphemeralMessageEnabled,
+		                             pauline_stat.number_of_LinphoneChatRoomEphemeralMessageEnabled + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr),
+		                linphone_core_get_default_ephemeral_lifetime(marie.getLc()), int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr),
+		                linphone_core_get_default_ephemeral_lifetime(marie.getLc()), int, "%d");
+
+		chloe_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+
+		constexpr int noShortMsg = 10;
+		sendEphemeralMessageInAdminMode(focus, marie, pauline, marieCr, paulineCr, "Test ephemeral message #",
+		                                noShortMsg);
+
+		linphone_chat_message_unref(non_ephemeral_message);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_bulk_notify_to_participant(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(michelle);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+		stats initialPaulineStats = pauline.getStats();
+		stats initialMichelleStats = michelle.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		LinphoneChatRoom *marieCr =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
+		                                 initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(
+		    coresList, pauline.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 2, FALSE);
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &initialMichelleStats, confAddr, initialSubject, 2, FALSE);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialPaulineStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelleStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Marie now changes the subject
+		const char *newSubject = "Let's go drink a beer";
+		linphone_chat_room_set_subject(marieCr, newSubject);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_subject_changed,
+		                             initialMarieStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed,
+		                             initialPaulineStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_subject_changed,
+		                             initialMichelleStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(marieCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(paulineCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(michelleCr), newSubject);
+
+		// Pauline goes offline
+		linphone_core_set_network_reachable(pauline.getLc(), FALSE);
+
+		// Adding Laure
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		focus.registerAsParticipantDevice(laure);
+
+		initialMarieStats = marie.getStats();
+		initialPaulineStats = pauline.getStats();
+		initialMichelleStats = michelle.getStats();
+		stats initialLaureStats = laure.getStats();
+
+		Address laureAddr = laure.getIdentity();
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(laureAddr.toC()));
+		linphone_chat_room_add_participants(marieCr, participantsAddresses);
+
+		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure.getCMgr(), &initialLaureStats,
+		                                                                 confAddr, newSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(laureCr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreationPending,
+		                             initialLaureStats.number_of_LinphoneConferenceStateCreationPending + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialLaureStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneChatRoomConferenceJoined,
+		                             initialLaureStats.number_of_LinphoneChatRoomConferenceJoined + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_added,
+		                             initialMarieStats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added,
+		                              initialPaulineStats.number_of_participants_added + 1, 3000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_added,
+		                             initialMichelleStats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_added,
+		                             initialMarieStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+		                              initialPaulineStats.number_of_participant_devices_added + 1, 3000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_added,
+		                             initialMichelleStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 3, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 3, int, "%d");
+
+		// Wait a little bit to detect side effects
+		CoreManagerAssert({focus, marie, laure, pauline, michelle}).waitUntil(std::chrono::seconds(2), [] {
+			return false;
+		});
+
+		initialMarieStats = marie.getStats();
+		initialPaulineStats = pauline.getStats();
+		initialMichelleStats = michelle.getStats();
+		initialLaureStats = laure.getStats();
+
+		// Marie now changes the subject again
+		const char *newSubject2 = "Seriously, ladies... Tonight we go out";
+		linphone_chat_room_set_subject(marieCr, newSubject2);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_subject_changed,
+		                             initialMarieStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed,
+		                              initialPaulineStats.number_of_subject_changed + 1, 3000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_subject_changed,
+		                             initialLaureStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_subject_changed,
+		                             initialMichelleStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(marieCr), newSubject2);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(paulineCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(michelleCr), newSubject2);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(laureCr), newSubject2);
+
+		initialMarieStats = marie.getStats();
+		initialPaulineStats = pauline.getStats();
+		initialMichelleStats = michelle.getStats();
+		initialLaureStats = laure.getStats();
+
+		char *laureDeviceIdentity = linphone_core_get_device_identity(laure.getLc());
+		LinphoneAddress *laureLocalAddr = linphone_address_new(laureDeviceIdentity);
+		BC_ASSERT_PTR_NOT_NULL(laureLocalAddr);
+		bctbx_free(laureDeviceIdentity);
+
+		// Focus deletes Laure's device
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			std::shared_ptr<Participant> participant =
+			    chatRoom->findParticipant(Address::toCpp(laureLocalAddr)->getSharedFromThis());
+			BC_ASSERT_PTR_NOT_NULL(participant);
+			if (participant) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				// Do not use laureLocalAddr because it has a GRUU
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// Marie removes Laure from the chat room
+		LinphoneParticipant *laureParticipant = linphone_chat_room_find_participant(marieCr, laureLocalAddr);
+		BC_ASSERT_PTR_NOT_NULL(laureParticipant);
+		linphone_chat_room_remove_participant(marieCr, laureParticipant);
+
+		linphone_address_unref(laureLocalAddr);
+
+		BC_ASSERT_FALSE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateTerminated,
+		                              initialLaureStats.number_of_LinphoneConferenceStateTerminated + 1, 3000));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+		                             initialMarieStats.number_of_participant_devices_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_removed,
+		                              initialPaulineStats.number_of_participant_devices_removed + 1, 3000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_removed,
+		                             initialMichelleStats.number_of_participant_devices_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+		                             initialMarieStats.number_of_participants_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_participants_removed,
+		                              initialPaulineStats.number_of_participants_removed + 1, 3000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_removed,
+		                             initialMichelleStats.number_of_participants_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d");
+
+		// Wait a little bit to detect side effects
+		CoreManagerAssert({focus, marie, pauline, michelle}).waitUntil(std::chrono::seconds(2), [] { return false; });
+
+		initialPaulineStats = pauline.getStats();
+		// Pauline comes up online
+		linphone_core_set_network_reachable(pauline.getLc(), TRUE);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneRegistrationOk,
+		                             initialPaulineStats.number_of_LinphoneRegistrationOk + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Check that Pauline receives the backlog of events occurred while she was offline
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added,
+		                             initialPaulineStats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+		                             initialPaulineStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed,
+		                             initialPaulineStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_removed,
+		                             initialPaulineStats.number_of_participant_devices_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_removed,
+		                             initialPaulineStats.number_of_participants_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d");
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(paulineCr), newSubject2);
+
+		CoreManagerAssert({focus, marie, pauline, michelle}).waitUntil(std::chrono::seconds(1), [] { return false; });
+
+		CoreManagerAssert({focus, marie}).waitUntil(std::chrono::seconds(2), [] { return false; });
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_with_client_restart_base(bool encrypted) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), encrypted);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), encrypted);
+		ClientConference berthe("berthe_rc", focus.getIdentity(), encrypted);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(berthe);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		coresList = bctbx_list_append(coresList, berthe.getLc());
+		bctbx_list_t *participantsAddresses = NULL;
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+		Address bertheAddr = berthe.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(bertheAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+		stats initialMichelleStats = michelle.getStats();
+		stats initialBertheStats = berthe.getStats();
+		stats initialLaureStats = laure.getStats();
+
+		if (encrypted) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialMarieStats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialMichelleStats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialBertheStats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialLaureStats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(berthe.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(laure.getLc()));
+		}
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_expected_number_of_participants(
+		    coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses, initialSubject, 2, encrypted,
+		    LinphoneChatRoomEphemeralModeDeviceManaged);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Michelle's side and that the participants are added
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &initialMichelleStats, confAddr, initialSubject, 2, FALSE);
+
+		LinphoneChatRoom *bertheCr = check_creation_chat_room_client_side(
+		    coresList, berthe.getCMgr(), &initialBertheStats, confAddr, initialSubject, 2, FALSE);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, laure, berthe}).wait([&focus] {
+			for (const auto &chatRoom : focus.getCore().getChatRooms()) {
+				for (const auto &participant : chatRoom->getParticipants()) {
+					for (const auto &device : participant->getDevices()) {
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+					}
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelleStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialBertheStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Marie now changes the subject
+		const char *newSubject = "Let's go drink a beer";
+		linphone_chat_room_set_subject(marieCr, newSubject);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_subject_changed,
+		                             initialMarieStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_subject_changed,
+		                             initialMichelleStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_subject_changed,
+		                             initialBertheStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(marieCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(michelleCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(bertheCr), newSubject);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(bertheCr), 2, int, "%d");
+
+		const std::initializer_list<std::reference_wrapper<ConfCoreManager>> cores2{focus, marie, michelle, berthe};
+		for (const ConfCoreManager &core : cores2) {
+			BC_ASSERT_TRUE(
+			    CoreManagerAssert({focus, marie, michelle, berthe, laure})
+			        .waitUntil(chrono::seconds(10), [&focus, &core] { return checkChatroom(focus, core, -1); }));
+		};
+
+		ClientConference michelle2("michelle_rc", focus.getIdentity(), encrypted);
+		stats initialMichelle2Stats = michelle2.getStats();
+		coresList = bctbx_list_append(coresList, michelle2.getLc());
+		if (encrypted) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialMichelle2Stats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle2.getLc()));
+		}
+
+		focus.registerAsParticipantDevice(michelle2);
+
+		LinphoneAddress *michelle2Contact = linphone_address_clone(
+		    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(michelle2.getLc())));
+		ms_message("%s is adding device %s", linphone_core_get_identity(focus.getLc()),
+		           linphone_address_as_string(michelle2Contact));
+		focus.registerAsParticipantDevice(michelle2);
+
+		// Notify chat room that a participant has registered
+		bctbx_list_t *devices = NULL;
+		const LinphoneAddress *deviceAddr = linphone_proxy_config_get_contact(michelle.getDefaultProxyConfig());
+		LinphoneParticipantDeviceIdentity *identity =
+		    linphone_factory_create_participant_device_identity(linphone_factory_get(), deviceAddr, "");
+		linphone_participant_device_identity_set_capability_descriptor(
+		    identity, linphone_core_get_linphone_specs(michelle.getLc()));
+		devices = bctbx_list_append(devices, identity);
+
+		deviceAddr = linphone_proxy_config_get_contact(michelle2.getDefaultProxyConfig());
+		identity = linphone_factory_create_participant_device_identity(linphone_factory_get(), deviceAddr, "");
+		linphone_participant_device_identity_set_capability_descriptor(
+		    identity, linphone_core_get_linphone_specs(michelle2.getLc()));
+		devices = bctbx_list_append(devices, identity);
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), michelle.getCMgr()->identity,
+			                                           devices);
+		}
+		bctbx_list_free_with_data(devices, (bctbx_list_free_func)belle_sip_object_unref);
+
+		LinphoneChatRoom *michelle2Cr = check_creation_chat_room_client_side(
+		    coresList, michelle2.getCMgr(), &initialMichelle2Stats, confAddr, newSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(michelle2Cr);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelle2Stats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		const std::initializer_list<std::reference_wrapper<ConfCoreManager>> cores3{focus, marie, michelle, michelle2,
+		                                                                            berthe};
+		for (const ConfCoreManager &core : cores3) {
+			BC_ASSERT_TRUE(
+			    CoreManagerAssert({focus, marie, michelle, michelle2, berthe, laure})
+			        .waitUntil(chrono::seconds(10), [&focus, &core] { return checkChatroom(focus, core, -1); }));
+		};
+
+		initialMarieStats = marie.getStats();
+		initialMichelleStats = michelle.getStats();
+		initialBertheStats = berthe.getStats();
+		initialLaureStats = laure.getStats();
+
+		Address laureAddr = laure.getIdentity();
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(laureAddr.toC()));
+		ms_message("%s is adding participant %s", linphone_core_get_identity(focus.getLc()),
+		           linphone_core_get_identity(laure.getLc()));
+		linphone_chat_room_add_participants(marieCr, participantsAddresses);
+
+		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure.getCMgr(), &initialLaureStats,
+		                                                                 confAddr, newSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(laureCr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreationPending,
+		                             initialLaureStats.number_of_LinphoneConferenceStateCreationPending + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialLaureStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneChatRoomConferenceJoined,
+		                             initialLaureStats.number_of_LinphoneChatRoomConferenceJoined + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_added,
+		                             initialMarieStats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_participants_added,
+		                             initialBertheStats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_added,
+		                             initialMichelleStats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_participants_added,
+		                             initialMichelle2Stats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_added,
+		                             initialMarieStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_participant_devices_added,
+		                             initialBertheStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_added,
+		                             initialMichelleStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_participant_devices_added,
+		                             initialMichelle2Stats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 3, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(bertheCr), 3, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 3, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelle2Cr), 3, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(laureCr), 3, int, "%d");
+
+		const std::initializer_list<std::reference_wrapper<ConfCoreManager>> cores{focus,     marie, michelle,
+		                                                                           michelle2, laure, berthe};
+		for (const ConfCoreManager &core : cores) {
+			BC_ASSERT_TRUE(
+			    CoreManagerAssert({focus, marie, michelle, michelle2, laure, berthe})
+			        .waitUntil(chrono::seconds(10), [&focus, &core] { return checkChatroom(focus, core, -1); }));
+			for (auto chatRoom : core.getCore().getChatRooms()) {
+				BC_ASSERT_EQUAL(chatRoom->getParticipants().size(), ((focus.getLc() == core.getLc())) ? 4 : 3, size_t,
+				                "%zu");
+				BC_ASSERT_STRING_EQUAL(chatRoom->getSubject().c_str(), newSubject);
+			}
+		};
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, michelle, michelle2}).waitUntil(chrono::seconds(1), [] { return false; });
+
+		time_t participantAddedTime = ms_time(nullptr);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, michelle, michelle2}).waitUntil(chrono::seconds(10), [] { return false; });
+
+		ms_message("%s is restarting its core", linphone_core_get_identity(focus.getLc()));
+		coresList = bctbx_list_remove(coresList, focus.getLc());
+		// Restart flexisip
+		focus.reStart();
+		coresList = bctbx_list_append(coresList, focus.getLc());
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(L_GET_C_BACK_PTR(chatRoom)), 4, int, "%d");
+		}
+
+		ms_message("%s is restarting its core", linphone_address_as_string(michelle2Contact));
+		coresList = bctbx_list_remove(coresList, michelle2.getLc());
+		// Restart michelle
+		michelle2.reStart();
+		michelle2.setupMgrForConference();
+		coresList = bctbx_list_append(coresList, michelle2.getLc());
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated, 1,
+		                             liblinphone_tester_sip_timeout));
+		LinphoneAddress *michelleDeviceAddr =
+		    linphone_address_clone(linphone_proxy_config_get_contact(michelle2.getDefaultProxyConfig()));
+		michelle2Cr = michelle2.searchChatRoom(michelleDeviceAddr, confAddr);
+		BC_ASSERT_PTR_NOT_NULL(michelle2Cr);
+		for (const ConfCoreManager &core : cores) {
+			BC_ASSERT_TRUE(checkChatroom(focus, core, participantAddedTime));
+			for (auto chatRoom : core.getCore().getChatRooms()) {
+				BC_ASSERT_EQUAL(chatRoom->getParticipants().size(), ((focus.getLc() == core.getLc())) ? 4 : 3, size_t,
+				                "%zu");
+				BC_ASSERT_STRING_EQUAL(chatRoom->getSubject().c_str(), newSubject);
+			}
+		}
+
+		LinphoneChatMessage *msg = linphone_chat_room_create_message_from_utf8(michelle2Cr, "back with you");
+		linphone_chat_message_send(msg);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2}).wait([marieCr] {
+			return linphone_chat_room_get_unread_messages_count(marieCr) == 1;
+		}));
+		linphone_chat_message_unref(msg);
+		msg = NULL;
+
+		msg = linphone_chat_room_create_message_from_utf8(marieCr, "welcome back");
+		linphone_chat_message_send(msg);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2}).wait([michelleCr] {
+			return linphone_chat_room_get_unread_messages_count(michelleCr) == 1;
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2}).wait([michelle2Cr] {
+			return linphone_chat_room_get_unread_messages_count(michelle2Cr) == 1;
+		}));
+		linphone_chat_message_unref(msg);
+		msg = NULL;
+
+		msg = linphone_chat_room_create_message_from_utf8(michelleCr, "message blabla");
+		linphone_chat_message_send(msg);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2}).wait([marieCr] {
+			return linphone_chat_room_get_unread_messages_count(marieCr) == 2;
+		}));
+		linphone_chat_message_unref(msg);
+
+		CoreManagerAssert({focus, marie}).waitUntil(std::chrono::seconds(1), [] { return false; });
+
+		CoreManagerAssert({focus, marie}).waitUntil(std::chrono::seconds(2), [] { return false; });
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, michelle, michelle2}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		linphone_address_unref(michelle2Contact);
+		linphone_address_unref(michelleDeviceAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_with_client_restart(void) {
+	group_chat_room_with_client_restart_base(false);
+}
+
+static void secure_group_chat_room_with_client_restart(void) {
+	group_chat_room_with_client_restart_base(true);
+}
+
+static void group_chat_room_with_client_removed_added(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(pauline);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		bctbx_list_t *participantsAddresses = NULL;
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+		Address paulineAddr = pauline.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(paulineAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+		stats initialMichelleStats = michelle.getStats();
+		stats initialPaulineStats = pauline.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_expected_number_of_participants(
+		    coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses, initialSubject, 2, FALSE,
+		    LinphoneChatRoomEphemeralModeDeviceManaged);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Michelle's side and that the participants are added
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &initialMichelleStats, confAddr, initialSubject, 2, FALSE);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(
+		    coresList, pauline.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 2, FALSE);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelleStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Marie now changes the subject
+		const char *newSubject = "Let's go drink a beer";
+		linphone_chat_room_set_subject(marieCr, newSubject);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_subject_changed,
+		                             initialMarieStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_subject_changed,
+		                             initialMichelleStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed,
+		                             initialPaulineStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(marieCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(paulineCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(michelleCr), newSubject);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 2, int, "%d");
+
+		initialMarieStats = marie.getStats();
+		initialMichelleStats = michelle.getStats();
+		initialPaulineStats = pauline.getStats();
+
+		ClientConference michelle2("michelle_rc", focus.getIdentity());
+		stats initialMichelle2Stats = michelle2.getStats();
+		coresList = bctbx_list_append(coresList, michelle2.getLc());
+		focus.registerAsParticipantDevice(michelle2);
+		// Notify chat room that a participant has registered
+
+		bctbx_list_t *devices = NULL;
+		const LinphoneAddress *deviceAddr = linphone_proxy_config_get_contact(michelle.getDefaultProxyConfig());
+		LinphoneParticipantDeviceIdentity *identity =
+		    linphone_factory_create_participant_device_identity(linphone_factory_get(), deviceAddr, "");
+		linphone_participant_device_identity_set_capability_descriptor(
+		    identity, linphone_core_get_linphone_specs(michelle.getLc()));
+		devices = bctbx_list_append(devices, identity);
+
+		deviceAddr = linphone_proxy_config_get_contact(michelle2.getDefaultProxyConfig());
+		identity = linphone_factory_create_participant_device_identity(linphone_factory_get(), deviceAddr, "");
+		linphone_participant_device_identity_set_capability_descriptor(
+		    identity, linphone_core_get_linphone_specs(michelle2.getLc()));
+		devices = bctbx_list_append(devices, identity);
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), michelle.getCMgr()->identity,
+			                                           devices);
+		}
+		bctbx_list_free_with_data(devices, (bctbx_list_free_func)belle_sip_object_unref);
+
+		LinphoneChatRoom *michelle2Cr = check_creation_chat_room_client_side(
+		    coresList, michelle2.getCMgr(), &initialMichelle2Stats, confAddr, newSubject, 2, FALSE);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelle2Stats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(L_GET_C_BACK_PTR(chatRoom)), 3, int, "%d");
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_added,
+		                             initialMarieStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+		                             initialPaulineStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_added,
+		                             initialMichelleStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneAddress *michelle2Contact =
+		    linphone_address_clone(linphone_proxy_config_get_contact(michelle2.getDefaultProxyConfig()));
+		ms_message("%s is restarting its core", linphone_address_as_string(michelle2Contact));
+		linphone_address_unref(michelle2Contact);
+		coresList = bctbx_list_remove(coresList, michelle2.getLc());
+		// Restart flexisip
+		michelle2.reStart();
+		michelle2.setupMgrForConference();
+		coresList = bctbx_list_append(coresList, michelle2.getLc());
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated, 1,
+		                             liblinphone_tester_sip_timeout));
+		LinphoneAddress *michelleDeviceAddr =
+		    linphone_address_clone(linphone_proxy_config_get_contact(michelle2.getDefaultProxyConfig()));
+		michelle2Cr = michelle2.searchChatRoom(michelleDeviceAddr, confAddr);
+		BC_ASSERT_PTR_NOT_NULL(michelle2Cr);
+
+		if (michelle2Cr) {
+			BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelle2Cr), 2, int, "%d");
+			BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(michelle2Cr), newSubject);
+		}
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 2, int, "%d");
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(marieCr), newSubject);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 2, int, "%d");
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(michelleCr), newSubject);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d");
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(paulineCr), newSubject);
+
+		linphone_core_delete_chat_room(michelle2.getLc(), michelle2Cr);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateDeleted,
+		                             initialMichelle2Stats.number_of_LinphoneConferenceStateDeleted + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+		                             initialMarieStats.number_of_participant_devices_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_removed,
+		                             initialPaulineStats.number_of_participant_devices_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		initialMarieStats = marie.getStats();
+		initialMichelleStats = michelle.getStats();
+		initialPaulineStats = pauline.getStats();
+
+		Address michelle2Addr = michelle2.getIdentity();
+		linphone_chat_room_add_participant(marieCr, linphone_address_ref(michelle2Addr.toC()));
+
+		michelle2Cr = check_creation_chat_room_client_side(coresList, michelle2.getCMgr(), &initialMichelle2Stats,
+		                                                   confAddr, newSubject, 2, FALSE);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelle2Stats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_added,
+		                             initialMarieStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+		                             initialPaulineStats.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneChatMessage *msg = linphone_chat_room_create_message_from_utf8(marieCr, "message blabla");
+		linphone_chat_message_send(msg);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2}).wait([michelleCr] {
+			return linphone_chat_room_get_unread_messages_count(michelleCr) == 1;
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2}).wait([michelle2Cr] {
+			return linphone_chat_room_get_unread_messages_count(michelle2Cr) == 1;
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2}).wait([paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+		linphone_chat_message_unref(msg);
+
+		CoreManagerAssert({focus, marie, pauline, michelle, michelle2}).waitUntil(std::chrono::seconds(3), [] {
+			return false;
+		});
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, michelle, michelle2}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		linphone_address_unref(michelleDeviceAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void
+group_chat_room_with_client_idmn_after_restart_base(bool_t encrypted, bool_t add_participant, bool_t stop_core) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle2("michelle_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), encrypted);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(michelle2);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(pauline);
+
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(laure.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(michelle.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(michelle2.getLc()));
+
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+		stats laure_stat = laure.getStats();
+		stats michelle_stat = michelle.getStats();
+		stats michelle2_stat = michelle2.getStats();
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		coresList = bctbx_list_append(coresList, michelle2.getLc());
+
+		if (encrypted) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_X3dhUserCreationSuccess,
+			                             marie_stat.number_of_X3dhUserCreationSuccess + 1, x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_X3dhUserCreationSuccess,
+			                             laure_stat.number_of_X3dhUserCreationSuccess + 1, x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_X3dhUserCreationSuccess,
+			                             pauline_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_X3dhUserCreationSuccess,
+			                             michelle_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_X3dhUserCreationSuccess,
+			                             michelle2_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(pauline.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(laure.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle2.getLc()));
+		}
+
+		bctbx_list_t *participantsAddresses = NULL;
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+		Address michelle2Addr = michelle2.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelle2Addr.toC()));
+		Address laureAddr = laure.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(laureAddr.toC()));
+		Address paulineAddr = pauline.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(paulineAddr.toC()));
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_expected_number_of_participants(
+		    coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject, 3, encrypted,
+		    LinphoneChatRoomEphemeralModeDeviceManaged);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+		char *conference_address = linphone_address_as_string(confAddr);
+
+		// Check that the chat room is correctly created on Michelle's side and that the participants are added
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &michelle_stat, confAddr, initialSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(michelleCr);
+		LinphoneChatRoom *michelle2Cr = check_creation_chat_room_client_side(
+		    coresList, michelle2.getCMgr(), &michelle2_stat, confAddr, initialSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(michelle2Cr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(paulineCr);
+
+		// Check that the chat room is correctly created on Laure's side and that the participants are added
+		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure.getCMgr(), &laure_stat,
+		                                                                 confAddr, initialSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(laureCr);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+		                             michelle_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
+		                             michelle2_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreated,
+		                             laure_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateCreated,
+		                             pauline_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure}).waitUntil(chrono::seconds(5), [] {
+			return false;
+		});
+
+		ms_message("%s goes offline", linphone_core_get_identity(laure.getLc()));
+		linphone_core_set_network_reachable(laure.getLc(), FALSE);
+
+		ClientConference berthe("berthe_rc", focus.getIdentity(), encrypted);
+		focus.registerAsParticipantDevice(berthe);
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(berthe.getLc()));
+		stats berthe_stat = berthe.getStats();
+		coresList = bctbx_list_append(coresList, berthe.getLc());
+
+		if (encrypted) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_X3dhUserCreationSuccess,
+			                             berthe_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(berthe.getLc()));
+		}
+
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+		laure_stat = laure.getStats();
+		michelle_stat = michelle.getStats();
+		michelle2_stat = michelle2.getStats();
+		LinphoneChatRoom *bertheCr = NULL;
+		if (add_participant) {
+			Address bertheAddr = berthe.getIdentity();
+			ms_message("%s adds %s to chatroom %s", linphone_core_get_identity(marie.getLc()),
+			           linphone_core_get_identity(berthe.getLc()), conference_address);
+			linphone_chat_room_add_participant(marieCr, bertheAddr.toC());
+			bertheCr = check_creation_chat_room_client_side(coresList, berthe.getCMgr(), &berthe_stat, confAddr,
+			                                                initialSubject, 4, FALSE);
+			BC_ASSERT_PTR_NOT_NULL(bertheCr);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added,
+			                             pauline_stat.number_of_participants_added + 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+			                             pauline_stat.number_of_participant_devices_added + 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_added,
+			                             michelle_stat.number_of_participants_added + 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_added,
+			                             michelle_stat.number_of_participant_devices_added + 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_participants_added,
+			                             michelle2_stat.number_of_participants_added + 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_participant_devices_added,
+			                             michelle2_stat.number_of_participant_devices_added + 1, 5000));
+		}
+
+		std::string msg_text = "message pauline blabla";
+		LinphoneChatMessage *msg = ClientConference::sendTextMsg(paulineCr, msg_text);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2, berthe, laure, pauline}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, michelle, michelle2, berthe, laure, pauline}).wait([marieCr] {
+			return linphone_chat_room_get_unread_messages_count(marieCr) == 1;
+		}));
+		LinphoneChatMessage *marieLastMsg = marie.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marieLastMsg);
+		if (marieLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(marieLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(
+		    CoreManagerAssert({focus, marie, michelle, michelle2, berthe, laure, pauline}).wait([michelleCr] {
+			    return linphone_chat_room_get_unread_messages_count(michelleCr) == 1;
+		    }));
+		LinphoneChatMessage *michelleLastMsg = michelle.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(michelleLastMsg);
+		if (michelleLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelleLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(
+		    CoreManagerAssert({focus, marie, michelle, michelle2, berthe, laure, pauline}).wait([michelle2Cr] {
+			    return linphone_chat_room_get_unread_messages_count(michelle2Cr) == 1;
+		    }));
+		LinphoneChatMessage *michelle2LastMsg = michelle2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(michelle2LastMsg);
+		if (michelle2LastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelle2LastMsg), msg_text.c_str());
+		}
+
+		if (bertheCr) {
+			BC_ASSERT_TRUE(
+			    CoreManagerAssert({focus, marie, michelle, michelle2, berthe, laure, pauline}).wait([bertheCr] {
+				    return linphone_chat_room_get_unread_messages_count(bertheCr) == 1;
+			    }));
+			LinphoneChatMessage *bertheLastMsg = berthe.getStats().last_received_chat_message;
+			BC_ASSERT_PTR_NOT_NULL(bertheLastMsg);
+			if (bertheLastMsg) {
+				BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(bertheLastMsg), msg_text.c_str());
+			}
+		}
+
+		linphone_chat_room_mark_as_read(michelleCr);
+		linphone_chat_room_mark_as_read(michelle2Cr);
+		if (bertheCr) {
+			linphone_chat_room_mark_as_read(bertheCr);
+		}
+		linphone_chat_room_mark_as_read(marieCr);
+		linphone_chat_room_mark_as_read(paulineCr);
+
+		for (const auto client : {marie.getCMgr(), michelle.getCMgr(), michelle2.getCMgr(), berthe.getCMgr(),
+		                          laure.getCMgr(), pauline.getCMgr()}) {
+			BC_ASSERT_TRUE(
+			    CoreManagerAssert({focus, marie, michelle, michelle2, berthe, laure, pauline})
+			        .wait([client, &berthe, &laure, &pauline, &add_participant, &msg] {
+				        bool ret = false;
+				        LinphoneChatMessage *lastMsg =
+				            (client->lc == pauline.getLc()) ? msg : client->stat.last_received_chat_message;
+				        if ((client->lc == laure.getLc()) || (!add_participant && (client->lc == berthe.getLc()))) {
+					        ret = (lastMsg == nullptr);
+				        } else {
+					        ret = (lastMsg != nullptr);
+					        if (lastMsg) {
+						        bctbx_list_t *displayed_list = linphone_chat_message_get_participants_by_imdn_state(
+						            lastMsg, LinphoneChatMessageStateDisplayed);
+						        const size_t expected_displayed_number =
+						            ((client->lc == pauline.getLc()) ? 2 : 1) + (add_participant ? 1 : 0);
+						        ret &= (bctbx_list_size(displayed_list) == expected_displayed_number);
+						        bctbx_list_free_with_data(displayed_list,
+						                                  (bctbx_list_free_func)linphone_participant_imdn_state_unref);
+					        }
+				        }
+				        return ret;
+			        }));
+		}
+
+		ms_message("%s comes back online", linphone_core_get_identity(laure.getLc()));
+		linphone_core_set_network_reachable(laure.getLc(), TRUE);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneMessageReceived,
+		                             laure_stat.number_of_LinphoneMessageReceived + 1, liblinphone_tester_sip_timeout));
+		LinphoneAddress *laureDeviceAddr = linphone_address_clone(
+		    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(laure.getLc())));
+		laureCr = linphone_core_search_chat_room(laure.getLc(), NULL, laureDeviceAddr, confAddr, NULL);
+		BC_ASSERT_PTR_NOT_NULL(laureCr);
+		char *uuid = NULL;
+		if (linphone_config_get_string(linphone_core_get_config(laure.getLc()), "misc", "uuid", NULL)) {
+			uuid =
+			    bctbx_strdup(linphone_config_get_string(linphone_core_get_config(laure.getLc()), "misc", "uuid", NULL));
+		}
+		if (laureCr) {
+			BC_ASSERT_TRUE(
+			    CoreManagerAssert({focus, marie, michelle, michelle2, berthe, laure, pauline}).wait([laureCr] {
+				    return linphone_chat_room_get_unread_messages_count(laureCr) == 1;
+			    }));
+			linphone_chat_room_mark_as_read(laureCr);
+			if (stop_core) {
+				ms_message("%s stops its core", linphone_core_get_identity(laure.getLc()));
+				coresList = bctbx_list_remove(coresList, laure.getLc());
+				linphone_core_manager_stop(laure.getCMgr());
+			}
+		}
+		linphone_address_unref(laureDeviceAddr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageDisplayed,
+		                             pauline_stat.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		if (stop_core) {
+			linphone_core_manager_configure(laure.getCMgr());
+			// Make sure gruu is preserved
+			linphone_config_set_string(linphone_core_get_config(laure.getLc()), "misc", "uuid", uuid);
+			ms_message("%s starts its core", linphone_core_get_identity(laure.getLc()));
+			linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(laure.getLc()));
+			linphone_core_manager_start(laure.getCMgr(), TRUE);
+			coresList = bctbx_list_append(coresList, laure.getLc());
+		}
+
+		if (uuid) {
+			bctbx_free(uuid);
+		}
+
+		for (const auto client : {marie.getCMgr(), michelle.getCMgr(), michelle2.getCMgr(), berthe.getCMgr(),
+		                          laure.getCMgr(), pauline.getCMgr()}) {
+			BC_ASSERT_TRUE(
+			    CoreManagerAssert({focus, marie, michelle, michelle2, berthe, laure, pauline})
+			        .wait([client, &berthe, &pauline, &add_participant, &confAddr, &stop_core] {
+				        const LinphoneAddress *deviceAddr =
+				            linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(client->lc));
+				        LinphoneChatRoom *cr =
+				            linphone_core_search_chat_room(client->lc, NULL, deviceAddr, confAddr, NULL);
+				        LinphoneChatMessage *lastMsg = cr ? linphone_chat_room_get_last_message_in_history(cr) : NULL;
+				        bool ret = false;
+				        if (!add_participant && (client->lc == berthe.getLc())) {
+					        ret = (lastMsg == nullptr);
+				        } else {
+					        ret = (lastMsg != nullptr);
+					        if (lastMsg) {
+						        bctbx_list_t *displayed_list = linphone_chat_message_get_participants_by_imdn_state(
+						            lastMsg, LinphoneChatMessageStateDisplayed);
+						        size_t expected_displayed_number = 0;
+						        if (client->lc == berthe.getLc()) {
+							        expected_displayed_number = 2 + (stop_core ? 0 : 1);
+						        } else {
+							        expected_displayed_number =
+							            ((client->lc == pauline.getLc()) ? 3 : 2) + (add_participant ? 1 : 0);
+						        }
+						        ret &= (bctbx_list_size(displayed_list) == expected_displayed_number);
+						        bctbx_list_free_with_data(displayed_list,
+						                                  (bctbx_list_free_func)linphone_participant_imdn_state_unref);
+					        }
+				        }
+				        return ret;
+			        }));
+		}
+
+		linphone_chat_message_unref(msg);
+		msg = nullptr;
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, berthe, laure}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, michelle, michelle2, berthe, laure})
+		    .waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		ms_free(conference_address);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_with_client_idmn_after_restart(void) {
+	group_chat_room_with_client_idmn_after_restart_base(FALSE, TRUE, FALSE);
+}
+
+static void secure_group_chat_room_with_client_idmn_sent_after_restart(void) {
+	group_chat_room_with_client_idmn_after_restart_base(TRUE, FALSE, FALSE);
+}
+
+static void secure_group_chat_room_with_client_idmn_sent_after_restart_and_participant_added(void) {
+	group_chat_room_with_client_idmn_after_restart_base(TRUE, TRUE, FALSE);
+}
+
+static void secure_group_chat_room_with_client_idmn_sent_after_restart_and_participant_added_and_core_stopped(void) {
+	group_chat_room_with_client_idmn_after_restart_base(TRUE, TRUE, TRUE);
+}
+
+static void group_chat_room_with_client_deletes_chatroom_after_restart(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		bool encrypted = false;
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), encrypted);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(pauline);
+
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+		stats laure_stat = laure.getStats();
+		stats michelle_stat = michelle.getStats();
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+
+		bctbx_list_t *participantsAddresses = NULL;
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+		Address laureAddr = laure.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(laureAddr.toC()));
+		Address paulineAddr = pauline.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(paulineAddr.toC()));
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_expected_number_of_participants(
+		    coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject, 3, encrypted,
+		    LinphoneChatRoomEphemeralModeDeviceManaged);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+		char *conference_address = linphone_address_as_string(confAddr);
+
+		// Check that the chat room is correctly created on Michelle's side and that the participants are added
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &michelle_stat, confAddr, initialSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(michelleCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(paulineCr);
+
+		// Check that the chat room is correctly created on Laure's side and that the participants are added
+		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure.getCMgr(), &laure_stat,
+		                                                                 confAddr, initialSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(laureCr);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, laure}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+		                             michelle_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreated,
+		                             laure_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateCreated,
+		                             pauline_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, michelle, laure}).waitUntil(chrono::seconds(5), [] { return false; });
+
+		ms_message("%s reinitializes its core", linphone_core_get_identity(laure.getLc()));
+		coresList = bctbx_list_remove(coresList, laure.getLc());
+		linphone_core_manager_reinit(laure.getCMgr());
+
+		stats focus_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+		laure_stat = laure.getStats();
+		michelle_stat = michelle.getStats();
+
+		ms_message("%s starts again its core", linphone_core_get_identity(laure.getLc()));
+		linphone_core_manager_start(laure.getCMgr(), TRUE);
+		setup_mgr_for_conference(laure.getCMgr(), NULL);
+		coresList = bctbx_list_append(coresList, laure.getLc());
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneRegistrationOk,
+		                             laure_stat.number_of_LinphoneRegistrationOk + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneSubscriptionActive,
+		                             laure_stat.number_of_LinphoneSubscriptionActive + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, laure}).wait([&laure] {
+			if (laure.getCore().getChatRooms().size() < 1) {
+				return false;
+			}
+			for (auto chatRoom : laure.getCore().getChatRooms()) {
+				if (chatRoom->getState() != ChatRoom::State::Created) {
+					return false;
+				}
+			}
+			return true;
+		}));
+
+		const LinphoneAddress *laureDeviceAddr =
+		    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(laure.getLc()));
+		laureCr = linphone_core_search_chat_room(laure.getLc(), NULL, laureDeviceAddr, confAddr, NULL);
+		BC_ASSERT_PTR_NOT_NULL(laureCr);
+
+		if (laureCr) {
+			linphone_core_delete_chat_room(laure.getLc(), laureCr);
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, laure}).wait([&laure] {
+			return (laure.getCore().getChatRooms().size() == 0);
+		}));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                             focus_stat.number_of_participants_removed + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+		                             marie_stat.number_of_participants_removed + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_removed,
+		                             pauline_stat.number_of_participants_removed + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_removed,
+		                             michelle_stat.number_of_participants_removed + 1, liblinphone_tester_sip_timeout));
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, laure}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, michelle, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		ms_free(conference_address);
+		bctbx_list_free(coresList);
+	}
+}
+static void chat_room_participant_added_sip_error(LinphoneChatRoom *cr,
+                                                  BCTBX_UNUSED(const LinphoneEventLog *event_log)) {
+	if (bctbx_list_size(linphone_chat_room_get_participants(cr)) == 2) {
+		LinphoneCoreManager *initiator = (LinphoneCoreManager *)linphone_chat_room_get_user_data(cr);
+		ms_message("Turning off network for core %s", linphone_core_get_identity(initiator->lc));
+		linphone_core_set_network_reachable(initiator->lc, FALSE);
+	}
+}
+
+static void
+server_core_chat_room_state_changed_sip_error(LinphoneCore *core, LinphoneChatRoom *cr, LinphoneChatRoomState state) {
+	Focus *focus = (Focus *)(((LinphoneCoreManager *)linphone_core_get_user_data(core))->user_info);
+	switch (state) {
+		case LinphoneChatRoomStateInstantiated: {
+			LinphoneChatRoomCbs *cbs = linphone_factory_create_chat_room_cbs(linphone_factory_get());
+			linphone_chat_room_cbs_set_participant_added(cbs, chat_room_participant_added_sip_error);
+			linphone_chat_room_add_callbacks(cr, cbs);
+			linphone_chat_room_cbs_set_user_data(cbs, focus);
+			linphone_chat_room_cbs_unref(cbs);
+			break;
+		}
+		default:
+			break;
+	}
+}
+
+static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscribe_error, bool encrypted) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), encrypted);
+		ClientConference berthe("berthe_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle2("michelle_rc", focus.getIdentity(), encrypted);
+
+		stats initialFocusStats = focus.getStats();
+		stats initialMarieStats = marie.getStats();
+		stats initialMichelleStats = michelle.getStats();
+		stats initialMichelle2Stats = michelle2.getStats();
+		stats initialLaureStats = laure.getStats();
+		stats initialBertheStats = berthe.getStats();
+		stats initialPaulineStats = pauline.getStats();
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		coresList = bctbx_list_append(coresList, michelle2.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		coresList = bctbx_list_append(coresList, berthe.getLc());
+
+		if (encrypted) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialMarieStats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialPaulineStats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialMichelleStats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialMichelle2Stats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialLaureStats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_X3dhUserCreationSuccess,
+			                             initialBertheStats.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(pauline.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(laure.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle2.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(berthe.getLc()));
+		}
+
+		linphone_core_set_network_reachable(marie.getLc(), FALSE);
+		linphone_core_set_network_reachable(berthe.getLc(), FALSE);
+
+		char *spec = bctbx_strdup_printf("groupchat/1.1");
+		linphone_core_remove_linphone_spec(marie.getLc(), "groupchat");
+		linphone_core_add_linphone_spec(marie.getLc(), spec);
+		linphone_core_remove_linphone_spec(berthe.getLc(), "groupchat");
+		linphone_core_add_linphone_spec(berthe.getLc(), spec);
+		bctbx_free(spec);
+
+		linphone_core_set_network_reachable(marie.getLc(), TRUE);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneRegistrationOk,
+		                             initialMarieStats.number_of_LinphoneRegistrationOk + 1,
+		                             liblinphone_tester_sip_timeout));
+		linphone_core_set_network_reachable(berthe.getLc(), TRUE);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneRegistrationOk,
+		                             initialBertheStats.number_of_LinphoneRegistrationOk + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		initialMarieStats = marie.getStats();
+		initialBertheStats = berthe.getStats();
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(michelle2);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(berthe);
+
+		if (invite_error) {
+			LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
+			linphone_core_cbs_set_chat_room_state_changed(cbs, server_core_chat_room_state_changed_sip_error);
+			linphone_core_add_callbacks(focus.getLc(), cbs);
+		}
+
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(michelle.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(michelle2.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(laure.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(berthe.getLc()));
+
+		bctbx_list_t *participantsAddresses = NULL;
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+		Address michelle2Addr = michelle2.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelle2Addr.toC()));
+		Address bertheAddr = berthe.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(bertheAddr.toC()));
+		Address paulineAddr = pauline.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(paulineAddr.toC()));
+
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		int participantsAddressesSize = (int)bctbx_list_size(participantsAddresses);
+		LinphoneChatRoomParams *params = linphone_core_create_default_chat_room_params(marie.getLc());
+
+		linphone_chat_room_params_enable_encryption(params, encrypted);
+		linphone_chat_room_params_set_ephemeral_mode(params, LinphoneChatRoomEphemeralModeDeviceManaged);
+		linphone_chat_room_params_set_backend(params, LinphoneChatRoomBackendFlexisipChat);
+		linphone_chat_room_params_enable_group(params, participantsAddressesSize > 1 ? TRUE : FALSE);
+		// Marie creates a new group chat room
+		LinphoneChatRoom *marieCr =
+		    linphone_core_create_chat_room_2(marie.getLc(), params, initialSubject, participantsAddresses);
+		linphone_chat_room_params_unref(params);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 1;
+		}));
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			linphone_chat_room_set_user_data(L_GET_C_BACK_PTR(chatRoom), marie.getCMgr());
+		}
+
+		if (invite_error) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
+			                             initialMichelle2Stats.number_of_LinphoneConferenceStateCreated + 1,
+			                             liblinphone_tester_sip_timeout));
+			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(michelle2.getLc()),
+			           linphone_address_as_string(linphone_proxy_config_get_contact(
+			               linphone_core_get_default_proxy_config(michelle2.getLc()))));
+			linphone_core_set_network_reachable(michelle2.getLc(), FALSE);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneConferenceStateCreated,
+			                             initialBertheStats.number_of_LinphoneConferenceStateCreated + 1,
+			                             liblinphone_tester_sip_timeout));
+			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(berthe.getLc()),
+			           linphone_address_as_string(
+			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(berthe.getLc()))));
+			linphone_core_set_network_reachable(berthe.getLc(), FALSE);
+		} else if (subscribe_error) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+			                             initialMarieStats.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(marie.getLc()),
+			           linphone_address_as_string(
+			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(marie.getLc()))));
+			linphone_core_set_network_reachable(marie.getLc(), FALSE);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneSubscriptionActive,
+			                             initialMichelle2Stats.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(michelle2.getLc()),
+			           linphone_address_as_string(linphone_proxy_config_get_contact(
+			               linphone_core_get_default_proxy_config(michelle2.getLc()))));
+			linphone_core_set_network_reachable(michelle2.getLc(), FALSE);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionActive,
+			                             initialBertheStats.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(berthe.getLc()),
+			           linphone_address_as_string(
+			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(berthe.getLc()))));
+			linphone_core_set_network_reachable(berthe.getLc(), FALSE);
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             initialFocusStats.number_of_participants_added + 4, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             initialFocusStats.number_of_participant_devices_added + 5, 5000));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe})
+		    .waitUntil(chrono::seconds(60), [] { return false; });
+
+		check_create_chat_room_client_side(coresList, marie.getCMgr(), marieCr, &initialMarieStats,
+		                                   participantsAddresses, initialSubject, 2);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+		// Check that the chat room is correctly created on Pauline's and Michelle's side and that the participants are
+		// added
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &initialMichelleStats, confAddr, initialSubject, 3, FALSE);
+		LinphoneChatRoom *michelle2Cr = check_creation_chat_room_client_side(
+		    coresList, michelle2.getCMgr(), &initialMichelle2Stats, confAddr, initialSubject, 3, FALSE);
+		LinphoneChatRoom *bertheCr = check_creation_chat_room_client_side(
+		    coresList, berthe.getCMgr(), &initialBertheStats, confAddr, initialSubject, 3, FALSE);
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(
+		    coresList, pauline.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 3, FALSE);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelleStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelle2Stats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialBertheStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialPaulineStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		std::string msg_text = "message michelle blabla";
+		LinphoneChatMessage *msg = ClientConference::sendTextMsg(michelleCr, msg_text);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([msg] {
+			return (msg && (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered));
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+		LinphoneChatMessage *paulineLastMsg = pauline.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(paulineLastMsg);
+		if (paulineLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(paulineLastMsg), msg_text.c_str());
+		}
+		linphone_chat_room_mark_as_read(paulineCr);
+
+		BC_ASSERT_FALSE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneMessageDisplayed,
+		                              initialMichelleStats.number_of_LinphoneMessageDisplayed + 1, 3000));
+
+		if (invite_error || subscribe_error) {
+			ms_message("Enabling network of core %s (contact %s)", linphone_core_get_identity(marie.getLc()),
+			           linphone_address_as_string(
+			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(marie.getLc()))));
+			linphone_core_set_network_reachable(marie.getLc(), TRUE);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneRegistrationOk,
+			                             initialMarieStats.number_of_LinphoneRegistrationOk + 1,
+			                             liblinphone_tester_sip_timeout));
+			marieCr = check_creation_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, confAddr,
+			                                               initialSubject, 3, TRUE);
+		}
+
+		focus.registerAsParticipantDevice(laure);
+		Address laureAddr = laure.getIdentity();
+		linphone_chat_room_add_participant(marieCr, linphone_address_ref(laureAddr.toC()));
+		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(
+		    coresList, laure.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 4, FALSE);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             initialFocusStats.number_of_participants_added + 4, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             initialFocusStats.number_of_participant_devices_added + 5, 5000));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([marieCr] {
+			return linphone_chat_room_get_unread_messages_count(marieCr) == 1;
+		}));
+		LinphoneChatMessage *marieLastMsg = marie.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marieLastMsg);
+		if (marieLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(marieLastMsg), msg_text.c_str());
+		}
+
+		msg_text = "message laure blabla";
+		LinphoneChatMessage *msg2 = ClientConference::sendTextMsg(laureCr, msg_text);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([msg2] {
+			return (linphone_chat_message_get_state(msg2) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+		paulineLastMsg = pauline.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(paulineLastMsg);
+		if (paulineLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(paulineLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([marieCr] {
+			return linphone_chat_room_get_unread_messages_count(marieCr) == 2;
+		}));
+		marieLastMsg = marie.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marieLastMsg);
+		if (marieLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(marieLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(
+		    CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([michelleCr] {
+			    return linphone_chat_room_get_unread_messages_count(michelleCr) == 1;
+		    }));
+		LinphoneChatMessage *michelleLastMsg = michelle.getStats().last_received_chat_message;
+		if (michelleLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelleLastMsg), msg_text.c_str());
+		}
+
+		linphone_chat_room_mark_as_read(paulineCr);
+		linphone_chat_room_mark_as_read(marieCr);
+		linphone_chat_room_mark_as_read(michelleCr);
+
+		BC_ASSERT_FALSE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneMessageDisplayed,
+		                              initialLaureStats.number_of_LinphoneMessageDisplayed + 1, 3000));
+
+		if (invite_error || subscribe_error) {
+			ms_message("Enabling network of core %s (contact %s)", linphone_core_get_identity(michelle2.getLc()),
+			           linphone_address_as_string(linphone_proxy_config_get_contact(
+			               linphone_core_get_default_proxy_config(michelle2.getLc()))));
+
+			linphone_core_set_network_reachable(michelle2.getLc(), TRUE);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneRegistrationOk,
+			                             initialMichelle2Stats.number_of_LinphoneRegistrationOk + 1,
+			                             liblinphone_tester_sip_timeout));
+			michelle2Cr = check_creation_chat_room_client_side(coresList, michelle2.getCMgr(), &initialMichelle2Stats,
+			                                                   confAddr, initialSubject, 4, FALSE);
+
+			ms_message("Enabling network of core %s (contact %s)", linphone_core_get_identity(berthe.getLc()),
+			           linphone_address_as_string(
+			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(berthe.getLc()))));
+			linphone_core_set_network_reachable(berthe.getLc(), TRUE);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneRegistrationOk,
+			                             initialBertheStats.number_of_LinphoneRegistrationOk + 1,
+			                             liblinphone_tester_sip_timeout));
+			bertheCr = check_creation_chat_room_client_side(coresList, berthe.getCMgr(), &initialBertheStats, confAddr,
+			                                                initialSubject, 4, FALSE);
+		}
+
+		LinphoneChatMessage *michelle2LastMsg = NULL;
+		if (!invite_error) {
+
+			BC_ASSERT_TRUE(
+			    CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([michelle2Cr] {
+				    return linphone_chat_room_get_history_size(michelle2Cr) == 2;
+			    }));
+			michelle2LastMsg = michelle2.getStats().last_received_chat_message;
+			BC_ASSERT_PTR_NOT_NULL(michelle2LastMsg);
+			if (michelle2LastMsg) {
+				BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelle2LastMsg), msg_text.c_str());
+			}
+			linphone_chat_room_mark_as_read(michelle2Cr);
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([bertheCr] {
+			return linphone_chat_room_get_history_size(bertheCr) == 2;
+		}));
+
+		LinphoneChatMessage *bertheLastMsg = berthe.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(bertheLastMsg);
+		if (bertheLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(bertheLastMsg), msg_text.c_str());
+		}
+		linphone_chat_room_mark_as_read(bertheCr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneMessageDisplayed,
+		                             initialMichelleStats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneMessageDisplayed,
+		                             initialLaureStats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		linphone_chat_message_unref(msg);
+		msg = nullptr;
+		linphone_chat_message_unref(msg2);
+		msg2 = nullptr;
+
+		// Marie now changes the subject
+		const char *newSubject = "Let's go drink a beer";
+		linphone_chat_room_set_subject(marieCr, newSubject);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_subject_changed,
+		                             initialMarieStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_subject_changed,
+		                             initialMichelleStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_subject_changed,
+		                             initialMichelle2Stats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed,
+		                             initialPaulineStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_subject_changed,
+		                             initialLaureStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_subject_changed,
+		                             initialBertheStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(marieCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(michelleCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(michelle2Cr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(paulineCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(laureCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(bertheCr), newSubject);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 4, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 4, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelle2Cr), 4, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 4, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(laureCr), 4, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(bertheCr), 4, int, "%d");
+
+		/*
+		        LinphoneAddress *michelle2Contact =
+		   linphone_address_clone(linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(michelle2.getLc())));
+		        ms_message("%s is restarting its core", linphone_address_as_string(michelle2Contact));
+		        linphone_address_unref(michelle2Contact);
+		        initialFocusStats = focus.getStats();
+		        coresList = bctbx_list_remove(coresList, michelle2.getLc());
+		        //Restart michelle
+		        michelle2.reStart();
+		        setup_mgr_for_conference(michelle2.getCMgr(), NULL);
+		        coresList = bctbx_list_append(coresList, michelle2.getLc());
+
+		        BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneRegistrationOk, 1,
+		   liblinphone_tester_sip_timeout)); if (encrypted) {
+		            BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle2.getLc()));
+		        }
+		        BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
+		   1, liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList,
+		   &michelle2.getStats().number_of_LinphoneSubscriptionActive, 1, liblinphone_tester_sip_timeout));
+		        BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		   initialFocusStats.number_of_LinphoneSubscriptionActive + 1, liblinphone_tester_sip_timeout)); LinphoneAddress
+		   *michelle2DeviceAddr =
+		   linphone_address_clone(linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(michelle2.getLc())));
+		        michelle2Cr = linphone_core_search_chat_room(michelle2.getLc(), NULL, michelle2DeviceAddr, confAddr,
+		   NULL); linphone_address_unref(michelle2DeviceAddr); BC_ASSERT_PTR_NOT_NULL(michelle2Cr);
+		*/
+
+		msg_text = "message marie blabla";
+		msg = ClientConference::sendTextMsg(marieCr, msg_text);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+		paulineLastMsg = pauline.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(paulineLastMsg);
+		if (paulineLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(paulineLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([laureCr] {
+			return linphone_chat_room_get_unread_messages_count(laureCr) == 1;
+		}));
+		LinphoneChatMessage *laureLastMsg = laure.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(laureLastMsg);
+		if (laureLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(laureLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(
+		    CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([michelleCr] {
+			    return linphone_chat_room_get_unread_messages_count(michelleCr) == 1;
+		    }));
+		michelleLastMsg = michelle.getStats().last_received_chat_message;
+		if (michelleLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelleLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(
+		    CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([michelle2Cr] {
+			    return linphone_chat_room_get_unread_messages_count(michelle2Cr) == 1;
+		    }));
+		michelle2LastMsg = michelle2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(michelle2LastMsg);
+		if (michelle2LastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelle2LastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([bertheCr] {
+			return linphone_chat_room_get_unread_messages_count(bertheCr) == 1;
+		}));
+		bertheLastMsg = berthe.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(bertheLastMsg);
+		if (bertheLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(bertheLastMsg), msg_text.c_str());
+		}
+
+		linphone_chat_room_mark_as_read(michelleCr);
+		linphone_chat_room_mark_as_read(michelle2Cr);
+		linphone_chat_room_mark_as_read(paulineCr);
+		linphone_chat_room_mark_as_read(laureCr);
+		linphone_chat_room_mark_as_read(bertheCr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDisplayed,
+		                             initialMarieStats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		linphone_chat_message_unref(msg);
+		msg = nullptr;
+
+		msg_text = "message michelle2 blabla";
+		msg = ClientConference::sendTextMsg(michelle2Cr, msg_text);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+		paulineLastMsg = pauline.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(paulineLastMsg);
+		if (paulineLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(paulineLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([bertheCr] {
+			return linphone_chat_room_get_unread_messages_count(bertheCr) == 1;
+		}));
+		bertheLastMsg = berthe.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(bertheLastMsg);
+		if (bertheLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(bertheLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([laureCr] {
+			return linphone_chat_room_get_unread_messages_count(laureCr) == 1;
+		}));
+		laureLastMsg = laure.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(laureLastMsg);
+		if (laureLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(laureLastMsg), msg_text.c_str());
+		}
+
+		michelleLastMsg = michelle.getStats().last_received_chat_message;
+		if (michelleLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelleLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([marieCr] {
+			return linphone_chat_room_get_unread_messages_count(marieCr) == 1;
+		}));
+		marieLastMsg = marie.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marieLastMsg);
+		if (marieLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(marieLastMsg), msg_text.c_str());
+		}
+
+		linphone_chat_room_mark_as_read(michelleCr);
+		linphone_chat_room_mark_as_read(marieCr);
+		linphone_chat_room_mark_as_read(paulineCr);
+		linphone_chat_room_mark_as_read(laureCr);
+		linphone_chat_room_mark_as_read(bertheCr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneMessageDisplayed,
+		                             initialMichelle2Stats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		linphone_chat_message_unref(msg);
+		msg = nullptr;
+
+		msg_text = "message pauline blabla";
+		msg = ClientConference::sendTextMsg(paulineCr, msg_text);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(
+		    CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([michelleCr] {
+			    return linphone_chat_room_get_unread_messages_count(michelleCr) == 1;
+		    }));
+		michelleLastMsg = michelle.getStats().last_received_chat_message;
+		if (michelleLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelleLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([bertheCr] {
+			return linphone_chat_room_get_unread_messages_count(bertheCr) == 1;
+		}));
+		bertheLastMsg = berthe.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(bertheLastMsg);
+		if (bertheLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(bertheLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([marieCr] {
+			return linphone_chat_room_get_unread_messages_count(marieCr) == 1;
+		}));
+		marieLastMsg = marie.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marieLastMsg);
+		if (marieLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(marieLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([laureCr] {
+			return linphone_chat_room_get_unread_messages_count(laureCr) == 1;
+		}));
+		laureLastMsg = laure.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(laureLastMsg);
+		if (laureLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(laureLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(
+		    CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([michelle2Cr] {
+			    return linphone_chat_room_get_unread_messages_count(michelle2Cr) == 1;
+		    }));
+		michelle2LastMsg = michelle2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(michelle2LastMsg);
+		if (michelle2LastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelle2LastMsg), msg_text.c_str());
+		}
+
+		linphone_chat_room_mark_as_read(michelleCr);
+		linphone_chat_room_mark_as_read(michelle2Cr);
+		linphone_chat_room_mark_as_read(marieCr);
+		linphone_chat_room_mark_as_read(laureCr);
+		linphone_chat_room_mark_as_read(bertheCr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageDisplayed,
+		                             initialPaulineStats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		linphone_chat_message_unref(msg);
+		msg = nullptr;
+
+		CoreManagerAssert({focus, marie}).waitUntil(std::chrono::seconds(1), [] { return false; });
+
+		CoreManagerAssert({focus, marie}).waitUntil(std::chrono::seconds(2), [] { return false; });
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe})
+		    .waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		LinphoneProxyConfig *config = linphone_core_get_default_proxy_config(focus.getLc());
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_with_invite_error(void) {
+	group_chat_room_with_sip_errors_base(true, false, false);
+}
+
+static void group_chat_room_with_subscribe_error(void) {
+	group_chat_room_with_sip_errors_base(false, true, false);
+}
+
+static void secure_group_chat_room_with_invite_error(void) {
+	group_chat_room_with_sip_errors_base(true, false, true);
+}
+
+static void secure_group_chat_room_with_subscribe_error(void) {
+	group_chat_room_with_sip_errors_base(false, true, true);
+}
+
+static void secure_group_chat_room_with_chat_room_deleted_before_server_restart(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity(), true);
+		ClientConference marie2("marie_rc", focus.getIdentity(), true);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), true);
+		ClientConference michelle2("michelle_rc", focus.getIdentity(), true);
+
+		stats initialFocusStats = focus.getStats();
+		stats initialMarieStats = marie.getStats();
+		stats initialMarie2Stats = marie2.getStats();
+		stats initialMichelleStats = michelle.getStats();
+		stats initialMichelle2Stats = michelle2.getStats();
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, marie2.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		coresList = bctbx_list_append(coresList, michelle2.getLc());
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_X3dhUserCreationSuccess,
+		                             initialMarieStats.number_of_X3dhUserCreationSuccess + 1,
+		                             x3dhServer_creationTimeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie2.getStats().number_of_X3dhUserCreationSuccess,
+		                             initialMarie2Stats.number_of_X3dhUserCreationSuccess + 1,
+		                             x3dhServer_creationTimeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_X3dhUserCreationSuccess,
+		                             initialMichelleStats.number_of_X3dhUserCreationSuccess + 1,
+		                             x3dhServer_creationTimeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_X3dhUserCreationSuccess,
+		                             initialMichelle2Stats.number_of_X3dhUserCreationSuccess + 1,
+		                             x3dhServer_creationTimeout));
+
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie.getLc()));
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie2.getLc()));
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle.getLc()));
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle2.getLc()));
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(marie2);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(michelle2);
+
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie2.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(michelle.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(michelle2.getLc()));
+
+		bctbx_list_t *participantsAddresses = NULL;
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+		Address michelle2Addr = michelle2.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelle2Addr.toC()));
+
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+
+		LinphoneChatRoomParams *params = linphone_core_create_default_chat_room_params(marie.getLc());
+		linphone_chat_room_params_enable_encryption(params, TRUE);
+		linphone_chat_room_params_set_ephemeral_mode(params, LinphoneChatRoomEphemeralModeDeviceManaged);
+		linphone_chat_room_params_set_backend(params, LinphoneChatRoomBackendFlexisipChat);
+		linphone_chat_room_params_enable_group(params, FALSE);
+		LinphoneChatRoom *marieCr =
+		    linphone_core_create_chat_room_2(marie.getLc(), params, initialSubject, participantsAddresses);
+		linphone_chat_room_params_unref(params);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 1;
+		}));
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			linphone_chat_room_set_user_data(L_GET_C_BACK_PTR(chatRoom), marie.getCMgr());
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             initialFocusStats.number_of_participants_added + 1, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             initialFocusStats.number_of_participant_devices_added + 2, 5000));
+
+		check_create_chat_room_client_side(coresList, marie.getCMgr(), marieCr, &initialMarieStats,
+		                                   participantsAddresses, initialSubject, 1);
+
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+		// Check that the chat room is correctly created on Pauline's and Michelle's side and that the participants are
+		// added
+		LinphoneChatRoom *marie2Cr = check_creation_chat_room_client_side(
+		    coresList, marie2.getCMgr(), &initialMarie2Stats, confAddr, initialSubject, 1, FALSE);
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &initialMichelleStats, confAddr, initialSubject, 1, FALSE);
+		LinphoneChatRoom *michelle2Cr = check_creation_chat_room_client_side(
+		    coresList, michelle2.getCMgr(), &initialMichelle2Stats, confAddr, initialSubject, 1, FALSE);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelleStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelle2Stats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMarieStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie2.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMarie2Stats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Send a few messages
+		std::string msg_text = "message marie2 blabla";
+		LinphoneChatMessage *msg = ClientConference::sendTextMsg(marie2Cr, msg_text);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([michelleCr] {
+			return linphone_chat_room_get_unread_messages_count(michelleCr) == 1;
+		}));
+		LinphoneChatMessage *michelleLastMsg = michelle.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(michelleLastMsg);
+		if (michelleLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelleLastMsg), msg_text.c_str());
+		}
+		linphone_chat_room_mark_as_read(michelleCr);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([michelle2Cr] {
+			return linphone_chat_room_get_unread_messages_count(michelle2Cr) == 1;
+		}));
+		LinphoneChatMessage *michelle2LastMsg = michelle2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(michelle2LastMsg);
+		if (michelle2LastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelle2LastMsg), msg_text.c_str());
+		}
+		linphone_chat_room_mark_as_read(michelle2Cr);
+		linphone_chat_room_mark_as_read(marieCr);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie2.getStats().number_of_LinphoneMessageDisplayed,
+		                             initialMarie2Stats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		linphone_chat_message_unref(msg);
+		msg = nullptr;
+
+		msg_text = "message marie blabla";
+		msg = ClientConference::sendTextMsg(marieCr, msg_text);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([michelleCr] {
+			return linphone_chat_room_get_unread_messages_count(michelleCr) == 1;
+		}));
+		michelleLastMsg = michelle.getStats().last_received_chat_message;
+		if (michelleLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelleLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([michelle2Cr] {
+			return linphone_chat_room_get_unread_messages_count(michelle2Cr) == 1;
+		}));
+		michelle2LastMsg = michelle2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(michelle2LastMsg);
+		if (michelle2LastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(michelle2LastMsg), msg_text.c_str());
+		}
+
+		linphone_chat_room_mark_as_read(marie2Cr);
+		linphone_chat_room_mark_as_read(michelleCr);
+		linphone_chat_room_mark_as_read(michelle2Cr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDisplayed,
+		                             initialMarieStats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		linphone_chat_message_unref(msg);
+		msg = nullptr;
+
+		msg_text = "message michelle2 blabla";
+		msg = ClientConference::sendTextMsg(michelle2Cr, msg_text);
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([marieCr] {
+			return linphone_chat_room_get_unread_messages_count(marieCr) == 1;
+		}));
+		LinphoneChatMessage *marieLastMsg = marie.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marieLastMsg);
+		if (marieLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(marieLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([marie2Cr] {
+			return linphone_chat_room_get_unread_messages_count(marie2Cr) == 1;
+		}));
+		LinphoneChatMessage *marie2LastMsg = marie2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marie2LastMsg);
+		if (marie2LastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(marie2LastMsg), msg_text.c_str());
+		}
+
+		linphone_chat_room_mark_as_read(michelleCr);
+		linphone_chat_room_mark_as_read(marieCr);
+		linphone_chat_room_mark_as_read(marie2Cr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneMessageDisplayed,
+		                             initialMichelle2Stats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		linphone_chat_message_unref(msg);
+		msg = nullptr;
+
+		// Marie deletes the chat room
+		char *confAddrStr = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
+		ms_message("%s deletes chat room %s", linphone_core_get_identity(marie.getLc()), confAddrStr);
+		ms_free(confAddrStr);
+
+		linphone_core_manager_delete_chat_room(marie.getCMgr(), marieCr, coresList);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             initialMarieStats.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             initialMichelleStats.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             initialMichelle2Stats.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).waitUntil(chrono::seconds(5), [] {
+			return false;
+		});
+
+		ms_message("%s is restarting its core", linphone_core_get_identity(focus.getLc()));
+		coresList = bctbx_list_remove(coresList, focus.getLc());
+		// Restart flexisip
+		focus.reStart();
+		coresList = bctbx_list_append(coresList, focus.getLc());
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).waitUntil(chrono::seconds(5), [] {
+			return false;
+		});
+
+		msg_text = "Cou cou Marieeee.....";
+		msg = ClientConference::sendTextMsg(michelle2Cr, msg_text);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMarieStats.number_of_LinphoneConferenceStateCreated + 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelleStats.number_of_LinphoneConferenceStateCreated + 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelle2Stats.number_of_LinphoneConferenceStateCreated + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		confAddr = linphone_chat_room_get_conference_address(michelle2Cr);
+		marieCr = check_creation_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, confAddr,
+		                                               initialSubject, 1, FALSE);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([marieCr] {
+			return linphone_chat_room_get_unread_messages_count(marieCr) == 1;
+		}));
+		marieLastMsg = marie.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marieLastMsg);
+		if (marieLastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(marieLastMsg), msg_text.c_str());
+		}
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([marie2Cr] {
+			return linphone_chat_room_get_unread_messages_count(marie2Cr) == 1;
+		}));
+		marie2LastMsg = marie2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marie2LastMsg);
+		if (marie2LastMsg) {
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(marie2LastMsg), msg_text.c_str());
+		}
+
+		linphone_chat_room_mark_as_read(michelleCr);
+		linphone_chat_room_mark_as_read(marieCr);
+		linphone_chat_room_mark_as_read(marie2Cr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneMessageDisplayed,
+		                             initialMichelle2Stats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, marie2, michelle, michelle2}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		// to avoid creation attempt of a new chatroom
+		LinphoneProxyConfig *config = linphone_core_get_default_proxy_config(focus.getLc());
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_add_participant_with_invalid_address(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(michelle);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+		Address invalidAddr = Address();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(invalidAddr.toC()));
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+		stats initialPaulineStats = pauline.getStats();
+		stats initialMichelleStats = michelle.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues";
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_expected_number_of_participants(
+		    coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses, initialSubject, 2, FALSE,
+		    LinphoneChatRoomEphemeralModeDeviceManaged);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(
+		    coresList, pauline.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 2, FALSE);
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &initialMichelleStats, confAddr, initialSubject, 2, FALSE);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialPaulineStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialMichelleStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Marie now changes the subject
+		const char *newSubject = "Let's go drink a beer";
+		linphone_chat_room_set_subject(marieCr, newSubject);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_subject_changed,
+		                             initialMarieStats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed,
+		                             initialPaulineStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_subject_changed,
+		                             initialMichelleStats.number_of_subject_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(marieCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(paulineCr), newSubject);
+		BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(michelleCr), newSubject);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 2, int, "%d");
+
+		initialMarieStats = marie.getStats();
+		initialPaulineStats = pauline.getStats();
+		initialMichelleStats = michelle.getStats();
+
+		linphone_chat_room_add_participant(marieCr, linphone_address_ref(invalidAddr.toC()));
+
+		BC_ASSERT_FALSE(wait_for_list(coresList, &marie.getStats().number_of_participants_added,
+		                              initialMarieStats.number_of_participants_added + 1, 5000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_added,
+		                              initialMarieStats.number_of_participant_devices_added + 1, 1000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_joined,
+		                              initialMarieStats.number_of_participant_devices_joined + 1, 1000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added,
+		                              initialPaulineStats.number_of_participants_added + 1, 1000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+		                              initialPaulineStats.number_of_participant_devices_added + 1, 1000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_joined,
+		                              initialPaulineStats.number_of_participant_devices_joined + 1, 1000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &michelle.getStats().number_of_participants_added,
+		                              initialMichelleStats.number_of_participants_added + 1, 1000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_added,
+		                              initialMichelleStats.number_of_participant_devices_added + 1, 1000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_joined,
+		                              initialMichelleStats.number_of_participant_devices_joined + 1, 1000));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 2, int, "%d");
+
+		CoreManagerAssert({focus, marie, pauline, michelle}).waitUntil(std::chrono::seconds(1), [] { return false; });
+
+		CoreManagerAssert({focus, marie}).waitUntil(std::chrono::seconds(2), [] { return false; });
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		linphone_address_unref(invalidAddr.toC());
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_with_only_participant_with_invalid_address(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		Address invalidAddr = Address();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(invalidAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues";
+
+		LinphoneChatRoomParams *chatRoomParams = linphone_core_create_default_chat_room_params(marie.getLc());
+		linphone_chat_room_params_enable_encryption(chatRoomParams, FALSE);
+		linphone_chat_room_params_set_backend(chatRoomParams, LinphoneChatRoomBackendFlexisipChat);
+		linphone_chat_room_params_enable_group(chatRoomParams, TRUE);
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_expected_number_of_participants(
+		    coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses, initialSubject, 0, FALSE,
+		    LinphoneChatRoomEphemeralModeDeviceManaged);
+		linphone_chat_room_params_unref(chatRoomParams);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+
+		// Check that the chat room has not been created
+		BC_ASSERT_FALSE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+		                              initialMarieStats.number_of_LinphoneConferenceStateCreated + 1, 3000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneChatRoomConferenceJoined,
+		                              initialMarieStats.number_of_LinphoneChatRoomConferenceJoined + 1, 1000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreationFailed,
+		                             initialMarieStats.number_of_LinphoneConferenceStateCreationFailed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void one_to_one_chatroom_exhumed_while_offline(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+		stats initialPaulineStats = pauline.getStats();
+
+		// Marie creates a new one to one chat room
+		const char *initialSubject = "one to one with Pauline";
+		LinphoneChatRoom *marieCr =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
+		                                 initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		LinphoneAddress *confAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr));
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(
+		    coresList, pauline.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 1, FALSE);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialPaulineStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Pauline goes offline
+		linphone_core_set_network_reachable(pauline.getLc(), FALSE);
+
+		LinphoneChatMessage *marieMsg1 = linphone_chat_room_create_message_from_utf8(marieCr, "Long live the C++ !");
+		linphone_chat_message_send(marieMsg1);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageSent,
+		                             initialMarieStats.number_of_LinphoneMessageSent + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+		                              initialPaulineStats.number_of_LinphoneMessageReceived + 1, 3000));
+		linphone_chat_message_unref(marieMsg1);
+
+		int marieMsgs = linphone_chat_room_get_history_size(marieCr);
+		BC_ASSERT_EQUAL(marieMsgs, 1, int, "%d");
+		// Pauline didn't received the message as she was offline
+		int paulineMsgs = linphone_chat_room_get_history_size(paulineCr);
+		BC_ASSERT_EQUAL(paulineMsgs, 0, int, "%d");
+
+		// Wait a little bit to detect side effects
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(std::chrono::seconds(2), [] { return false; });
+
+		// Marie deletes the chat room
+		// Pauline cannot now this because she is offline
+		linphone_core_manager_delete_chat_room(marie.getCMgr(), marieCr, coresList);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             initialMarieStats.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		initialMarieStats = marie.getStats();
+		initialPaulineStats = pauline.getStats();
+
+		paulineAddr = pauline.getIdentity();
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		marieCr = create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
+		                                       initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		LinphoneAddress *exhumedConfAddrPtr = (LinphoneAddress *)linphone_chat_room_get_conference_address(marieCr);
+		BC_ASSERT_PTR_NOT_NULL(exhumedConfAddrPtr);
+		LinphoneAddress *exhumedConfAddr = NULL;
+		if (exhumedConfAddrPtr) {
+			exhumedConfAddr =
+			    linphone_address_clone((LinphoneAddress *)linphone_chat_room_get_conference_address(marieCr));
+			BC_ASSERT_PTR_NOT_NULL(exhumedConfAddr);
+			if (exhumedConfAddr) {
+				BC_ASSERT_FALSE(linphone_address_equal(confAddr, exhumedConfAddr));
+			}
+		}
+
+		BC_ASSERT_EQUAL((int)marie.getCore().getChatRooms().size(), 1, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 1, int, "%d");
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 1, int, "%d");
+
+		// Wait a little bit to detect side effects
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(std::chrono::seconds(2), [] { return false; });
+
+		initialPaulineStats = pauline.getStats();
+		// Pauline comes up online
+		linphone_core_set_network_reachable(pauline.getLc(), TRUE);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneRegistrationOk,
+		                             initialPaulineStats.number_of_LinphoneRegistrationOk + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneChatRoomConferenceJoined,
+		                             initialPaulineStats.number_of_LinphoneChatRoomConferenceJoined + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_EQUAL((int)pauline.getCore().getChatRooms().size(), 1, int, "%d");
+
+		char *paulineDeviceIdentity = linphone_core_get_device_identity(pauline.getLc());
+		LinphoneAddress *paulineDeviceAddr = linphone_address_new(paulineDeviceIdentity);
+		bctbx_free(paulineDeviceIdentity);
+		auto newPaulineCr = pauline.searchChatRoom(paulineDeviceAddr, confAddr);
+		linphone_address_unref(paulineDeviceAddr);
+		BC_ASSERT_PTR_NOT_NULL(newPaulineCr);
+		BC_ASSERT_PTR_EQUAL(newPaulineCr, paulineCr);
+
+		if (newPaulineCr) {
+			LinphoneAddress *paulineNewConfAddr =
+			    linphone_address_ref((LinphoneAddress *)linphone_chat_room_get_conference_address(newPaulineCr));
+			BC_ASSERT_PTR_NOT_NULL(paulineNewConfAddr);
+			if (paulineNewConfAddr) {
+				BC_ASSERT_FALSE(linphone_address_equal(confAddr, paulineNewConfAddr));
+				if (exhumedConfAddr) {
+					BC_ASSERT_TRUE(linphone_address_equal(exhumedConfAddr, paulineNewConfAddr));
+				}
+			}
+			linphone_address_unref(paulineNewConfAddr);
+
+			BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(newPaulineCr), 1, int, "%d");
+			BC_ASSERT_STRING_EQUAL(linphone_chat_room_get_subject(newPaulineCr), initialSubject);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+			                             initialPaulineStats.number_of_LinphoneMessageReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			paulineMsgs = linphone_chat_room_get_history_size(newPaulineCr);
+			BC_ASSERT_EQUAL(paulineMsgs, 1, int, "%d");
+
+			LinphoneChatMessage *paulineMsg =
+			    linphone_chat_room_create_message_from_utf8(newPaulineCr, "Sorry I was offline :(");
+			linphone_chat_message_send(paulineMsg);
+			BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([paulineMsg] {
+				return (linphone_chat_message_get_state(paulineMsg) == LinphoneChatMessageStateDelivered);
+			}));
+			BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([marieCr] {
+				return linphone_chat_room_get_unread_messages_count(marieCr) == 1;
+			}));
+
+			// Since Marie has deleted the chat room, she lost all messages she sent before deleting it
+			marieMsgs = linphone_chat_room_get_history_size(marieCr);
+			BC_ASSERT_EQUAL(marieMsgs, 1, int, "%d");
+			paulineMsgs = linphone_chat_room_get_history_size(newPaulineCr);
+			BC_ASSERT_EQUAL(paulineMsgs, 2, int, "%d");
+
+			LinphoneChatMessage *marieMsg = linphone_chat_room_create_message_from_utf8(marieCr, "exhumed!!");
+			linphone_chat_message_send(marieMsg);
+			BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([marieMsg] {
+				return (linphone_chat_message_get_state(marieMsg) == LinphoneChatMessageStateDelivered);
+			}));
+			BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([newPaulineCr]() mutable {
+				return linphone_chat_room_get_unread_messages_count(newPaulineCr) == 2;
+			}));
+			linphone_chat_message_unref(marieMsg);
+
+			marieMsgs = linphone_chat_room_get_history_size(marieCr);
+			BC_ASSERT_EQUAL(marieMsgs, 2, int, "%d");
+			paulineMsgs = linphone_chat_room_get_history_size(newPaulineCr);
+			BC_ASSERT_EQUAL(paulineMsgs, 3, int, "%d");
+		}
+
+		linphone_address_unref(exhumedConfAddr);
+
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(std::chrono::seconds(1), [] { return false; });
+
+		CoreManagerAssert({focus, marie}).waitUntil(std::chrono::seconds(2), [] { return false; });
+
+		initialMarieStats = marie.getStats();
+		initialPaulineStats = pauline.getStats();
+
+		linphone_core_manager_delete_chat_room(marie.getCMgr(), marieCr, coresList);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             initialMarieStats.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             initialPaulineStats.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void multidomain_group_chat_room(void) {
+	Focus focusExampleDotOrg("chloe_rc");
+	Focus focusAuth1DotExampleDotOrg("arthur_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focusExampleDotOrg.getIdentity());
+		ClientConference pauline("pauline_rc", focusExampleDotOrg.getIdentity());
+		ClientConference michelle("michelle_rc", focusExampleDotOrg.getIdentity());
+
+		focusExampleDotOrg.registerAsParticipantDevice(marie);
+		focusExampleDotOrg.registerAsParticipantDevice(pauline);
+		focusExampleDotOrg.registerAsParticipantDevice(michelle);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focusExampleDotOrg.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+
+		stats initialMarieStats = marie.getStats();
+		stats initialPaulineStats = pauline.getStats();
+		stats initialMichelleStats = michelle.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues";
+		LinphoneChatRoom *marieCr =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
+		                                 initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
+		LinphoneAddress *confAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr));
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(
+		    coresList, pauline.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 2, FALSE);
+
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &initialMichelleStats, confAddr, initialSubject, 2, FALSE);
+
+		if (paulineCr || michelleCr) {
+			// throw BCTBX_EXCEPTION << "Cannot create chatroom giving up";
+			// goto end;
+		}
+		BC_ASSERT_TRUE(CoreManagerAssert({focusExampleDotOrg, marie, pauline, michelle}).wait([&focusExampleDotOrg] {
+			for (auto chatRoom : focusExampleDotOrg.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		LinphoneChatMessage *msg = linphone_chat_room_create_message_from_utf8(marieCr, "message blabla");
+		linphone_chat_message_send(msg);
+		BC_ASSERT_TRUE(CoreManagerAssert({focusExampleDotOrg, marie, pauline, michelle}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focusExampleDotOrg, marie, pauline, michelle}).wait([paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+		BC_ASSERT_TRUE(CoreManagerAssert({focusExampleDotOrg, marie, pauline, michelle}).wait([michelleCr] {
+			return linphone_chat_room_get_unread_messages_count(michelleCr) == 1;
+		}));
+		linphone_chat_message_unref(msg);
+
+		// now change focus in order to get conference with multiple domain.
+		focusAuth1DotExampleDotOrg.registerAsParticipantDevice(marie);
+		focusAuth1DotExampleDotOrg.registerAsParticipantDevice(pauline);
+		focusAuth1DotExampleDotOrg.registerAsParticipantDevice(michelle);
+
+		// change conference factory uri
+		Address focusAuth1DotExampleDotOrgFactoryAddress = focusAuth1DotExampleDotOrg.getIdentity();
+		marie.configureCoreForConference(focusAuth1DotExampleDotOrgFactoryAddress);
+		pauline.configureCoreForConference(focusAuth1DotExampleDotOrgFactoryAddress);
+		michelle.configureCoreForConference(focusAuth1DotExampleDotOrgFactoryAddress);
+
+		coresList = bctbx_list_append(coresList, focusAuth1DotExampleDotOrg.getLc());
+		initialMarieStats = marie.getStats();
+		initialPaulineStats = pauline.getStats();
+		initialMichelleStats = michelle.getStats();
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+		LinphoneChatRoom *marieCrfocusAuth1DotExampleDotOrg =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
+		                                 initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
+		LinphoneAddress *confAddrfocusAuth1DotExampleDotOrg =
+		    linphone_address_clone(linphone_chat_room_get_conference_address(marieCrfocusAuth1DotExampleDotOrg));
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCrfocusAuth1DotExampleDotOrg =
+		    check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &initialPaulineStats,
+		                                         confAddrfocusAuth1DotExampleDotOrg, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(paulineCrfocusAuth1DotExampleDotOrg);
+		LinphoneChatRoom *michelleCrfocusAuth1DotExampleDotOrg =
+		    check_creation_chat_room_client_side(coresList, michelle.getCMgr(), &initialMichelleStats,
+		                                         confAddrfocusAuth1DotExampleDotOrg, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(michelleCrfocusAuth1DotExampleDotOrg);
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focusAuth1DotExampleDotOrg, marie, pauline, michelle})
+		                   .wait([&focusAuth1DotExampleDotOrg] {
+			                   for (auto chatRoom : focusAuth1DotExampleDotOrg.getCore().getChatRooms()) {
+				                   for (auto participant : chatRoom->getParticipants()) {
+					                   for (auto device : participant->getDevices())
+						                   if (device->getState() != ParticipantDevice::State::Present) {
+							                   return false;
+						                   }
+				                   }
+			                   }
+			                   return true;
+		                   }));
+
+		msg = linphone_chat_room_create_message_from_utf8(marieCrfocusAuth1DotExampleDotOrg, "message blabla");
+		linphone_chat_message_send(msg);
+		BC_ASSERT_TRUE(CoreManagerAssert({focusAuth1DotExampleDotOrg, marie, pauline, michelle}).wait([msg] {
+			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+		}));
+
+		// great, now I want to see what happened if marie restart.
+		coresList = bctbx_list_remove(coresList, marie.getLc());
+		marie.reStart();
+		marie.setupMgrForConference();
+		coresList = bctbx_list_append(coresList, marie.getLc());
+
+		// Retrieve chat room
+		LinphoneAddress *marieDeviceAddr =
+		    linphone_address_clone(linphone_proxy_config_get_contact(marie.getDefaultProxyConfig()));
+		marieCr = marie.searchChatRoom(marieDeviceAddr, confAddr);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		marieCrfocusAuth1DotExampleDotOrg = marie.searchChatRoom(marieDeviceAddr, confAddrfocusAuth1DotExampleDotOrg);
+		BC_ASSERT_PTR_NOT_NULL(marieCrfocusAuth1DotExampleDotOrg);
+
+		CoreManagerAssert({focusExampleDotOrg, marie, pauline, michelle}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		ClientConference laure("laure_tcp_rc", focusExampleDotOrg.getIdentity());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		Address laureAddr = laure.getIdentity();
+		focusExampleDotOrg.registerAsParticipantDevice(laure);
+
+		initialMarieStats = marie.getStats();
+		initialPaulineStats = pauline.getStats();
+		initialMichelleStats = michelle.getStats();
+		stats initialLaureStats = laure.getStats();
+
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(laureAddr.toC()));
+		linphone_chat_room_add_participants(marieCr, participantsAddresses);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreationPending,
+		                             initialLaureStats.number_of_LinphoneConferenceStateCreationPending + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialLaureStats.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneChatRoomConferenceJoined,
+		                             initialLaureStats.number_of_LinphoneChatRoomConferenceJoined + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure.getCMgr(), &initialLaureStats,
+		                                                                 confAddr, initialSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(laureCr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_added,
+		                             initialMarieStats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added,
+		                             initialPaulineStats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_added,
+		                             initialMichelleStats.number_of_participants_added + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 3, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 3, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 3, int, "%d");
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_NotifyReceived,
+		                             initialPaulineStats.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_NotifyReceived,
+		                             initialMichelleStats.number_of_NotifyReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		focusAuth1DotExampleDotOrg.registerAsParticipantDevice(laure);
+		laure.configureCoreForConference(focusAuth1DotExampleDotOrgFactoryAddress);
+
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(laureAddr.toC()));
+		linphone_chat_room_add_participants(marieCrfocusAuth1DotExampleDotOrg, participantsAddresses);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreationPending,
+		                             initialLaureStats.number_of_LinphoneConferenceStateCreationPending + 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreated,
+		                             initialLaureStats.number_of_LinphoneConferenceStateCreated + 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneChatRoomConferenceJoined,
+		                             initialLaureStats.number_of_LinphoneChatRoomConferenceJoined + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneChatRoom *laureCrfocusAuth1DotExampleDotOrg =
+		    check_creation_chat_room_client_side(coresList, laure.getCMgr(), &initialLaureStats,
+		                                         confAddrfocusAuth1DotExampleDotOrg, initialSubject, 3, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(laureCrfocusAuth1DotExampleDotOrg);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_added,
+		                             initialMarieStats.number_of_participants_added + 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added,
+		                             initialPaulineStats.number_of_participants_added + 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_added,
+		                             initialMichelleStats.number_of_participants_added + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCrfocusAuth1DotExampleDotOrg), 3, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCrfocusAuth1DotExampleDotOrg), 3, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCrfocusAuth1DotExampleDotOrg), 3, int, "%d");
+
+		linphone_chat_message_unref(msg);
+
+		linphone_address_unref(marieDeviceAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_server_ephemeral_mode_changed(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		// Enable IMDN
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		stats chloe_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues";
+		const LinphoneChatRoomEphemeralMode adminMode = LinphoneChatRoomEphemeralModeAdminManaged;
+		LinphoneChatRoomParams *params = linphone_core_create_default_chat_room_params(marie.getLc());
+
+		linphone_chat_room_params_enable_group(params, FALSE);
+		linphone_chat_room_params_enable_encryption(params, FALSE);
+		linphone_chat_room_params_set_ephemeral_mode(params, adminMode);
+		linphone_chat_room_params_set_ephemeral_lifetime(params, 0);
+		linphone_chat_room_params_set_backend(params, LinphoneChatRoomBackendFlexisipChat);
+
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_params(
+		    coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject, params);
+		linphone_chat_room_params_unref(params);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 1, FALSE);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(paulineCr));
+
+		pauline_stat = pauline.getStats();
+		linphone_chat_room_set_ephemeral_lifetime(marieCr, 10);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_NotifyReceived,
+		                             pauline_stat.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(50), [&pauline] {
+			for (auto chatRoom : pauline.getCore().getChatRooms()) {
+				if (!chatRoom->ephemeralEnabled() || (chatRoom->getEphemeralLifetime() != 10)) {
+					return false;
+				}
+			}
+			return true;
+		}));
+
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(marieCr), 10, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 10, int, "%d");
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			for (auto chatRoom : focus.getCore().getChatRooms()) {
+				for (auto participant : chatRoom->getParticipants()) {
+					for (auto device : participant->getDevices())
+						if (device->getState() != ParticipantDevice::State::Present) {
+							return false;
+						}
+				}
+			}
+			return true;
+		}));
+
+		chloe_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+
+		constexpr int noMsg = 10;
+		sendEphemeralMessageInAdminMode(focus, marie, pauline, marieCr, paulineCr, "Hello ", noMsg);
+
+		pauline_stat = pauline.getStats();
+		linphone_chat_room_set_ephemeral_lifetime(marieCr, 0);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_NotifyReceived,
+		                             pauline_stat.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), adminMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(paulineCr));
+
+		pauline_stat = pauline.getStats();
+		const LinphoneChatRoomEphemeralMode deviceMode = LinphoneChatRoomEphemeralModeDeviceManaged;
+		linphone_chat_room_set_ephemeral_mode(marieCr, deviceMode);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_NotifyReceived,
+		                             pauline_stat.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+		pauline_stat = pauline.getStats();
+		marie_stat = marie.getStats();
+
+		linphone_chat_room_enable_ephemeral(paulineCr, TRUE);
+		linphone_chat_room_set_ephemeral_lifetime(paulineCr, 5);
+
+		wait_for_list(coresList, NULL, 1, 2000);
+
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(marieCr), deviceMode, int, "%d");
+		BC_ASSERT_FALSE(linphone_chat_room_ephemeral_enabled(marieCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_mode(paulineCr), deviceMode, int, "%d");
+		BC_ASSERT_TRUE(linphone_chat_room_ephemeral_enabled(paulineCr));
+		BC_ASSERT_EQUAL(linphone_chat_room_get_ephemeral_lifetime(paulineCr), 5, int, "%d");
+
+		LinphoneChatMessage *nonEphemeralMessage = _send_message(marieCr, "I have disabled ephemeral messages");
+
+		auto marieHistory = linphone_chat_room_get_history(marieCr, 0);
+		BC_ASSERT_EQUAL((int)bctbx_list_size(marieHistory), 1, int, "%i");
+		bctbx_list_free_with_data(marieHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+		                             pauline_stat.number_of_LinphoneMessageReceived + 1, 11000));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([nonEphemeralMessage] {
+			return (linphone_chat_message_get_state(nonEphemeralMessage) == LinphoneChatMessageStateDelivered);
+		}));
+
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&, paulineCr] {
+			return linphone_chat_room_get_unread_messages_count(paulineCr) == 1;
+		}));
+
+		auto paulineHistory = linphone_chat_room_get_history(paulineCr, 0);
+		BC_ASSERT_EQUAL((int)bctbx_list_size(paulineHistory), 1, int, "%i");
+		bctbx_list_free_with_data(paulineHistory, (bctbx_list_free_func)linphone_chat_message_unref);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDeliveredToUser,
+		                             marie_stat.number_of_LinphoneMessageDeliveredToUser + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Pauline marks the message as read, check that the state is now displayed on Marie's side
+		linphone_chat_room_mark_as_read(paulineCr);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDisplayed,
+		                             marie_stat.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		sendEphemeralMessageInAdminMode(focus, pauline, marie, paulineCr, marieCr, "Test ephemeral message ", noMsg);
+
+		if (nonEphemeralMessage) {
+			linphone_chat_message_unref(nonEphemeralMessage);
+		}
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_lime_server_message(bool encrypted) {
+	Focus focus("chloe_rc");
+	LinphoneChatMessage *msg;
+	{ // to make sure focus is destroyed after clients.
+		linphone_core_enable_lime_x3dh(focus.getLc(), true);
+
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), encrypted);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+		stats laure_stat = laure.getStats();
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+
+		if (encrypted) {
+			auto rawEncryptionSuccess = 0;
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_X3dhUserCreationSuccess,
+			                             marie_stat.number_of_X3dhUserCreationSuccess + 1, x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_X3dhUserCreationSuccess,
+			                             laure_stat.number_of_X3dhUserCreationSuccess + 1, x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_X3dhUserCreationSuccess,
+			                             pauline_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(pauline.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(laure.getLc()));
+
+			// Test the raw encryption/decryption
+			auto marieEncryptionEngine = L_GET_CPP_PTR_FROM_C_OBJECT(marie.getCMgr()->lc)->getEncryptionEngine();
+			char *deviceId = linphone_address_as_string_uri_only(
+			    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(marie.getLc())));
+			std::string marieAddressString{deviceId};
+			bctbx_free(deviceId);
+			auto paulineEncryptionEngine = L_GET_CPP_PTR_FROM_C_OBJECT(pauline.getCMgr()->lc)->getEncryptionEngine();
+			deviceId = linphone_address_as_string_uri_only(
+			    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(pauline.getLc())));
+			std::string paulineAddressString{deviceId};
+			bctbx_free(deviceId);
+
+			std::string messageString = "This is my message to you Rudy";
+			std::string ADString = "These are my AD to you Rudy";
+			auto message = std::make_shared<std::vector<uint8_t>>(messageString.cbegin(), messageString.cend());
+			auto AD = std::make_shared<std::vector<uint8_t>>(ADString.cbegin(), ADString.cend());
+			std::vector<uint8_t> cipherText{};
+
+			marieEncryptionEngine->rawEncrypt(
+			    marieAddressString, std::list<std::string>{paulineAddressString}, message, AD,
+			    [&rawEncryptionSuccess, &cipherText, paulineAddressString](
+			        const bool status, std::unordered_map<std::string, std::vector<uint8_t>> cipherTexts) {
+				    auto search = cipherTexts.find(paulineAddressString);
+				    if (status && search != cipherTexts.end()) {
+					    rawEncryptionSuccess++;
+					    cipherText = cipherTexts[paulineAddressString];
+				    }
+			    });
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &rawEncryptionSuccess, 1, x3dhServer_creationTimeout));
+			if (rawEncryptionSuccess == 1) {
+				// try to decrypt only if encryption was a success
+				std::vector<uint8_t> plainText{};
+				BC_ASSERT_TRUE(paulineEncryptionEngine->rawDecrypt(paulineAddressString, marieAddressString, *AD,
+				                                                   cipherText, plainText));
+				std::string plainTextString{plainText.cbegin(), plainText.cend()};
+				BC_ASSERT_TRUE(plainTextString == messageString);
+			}
+		}
+
+		Address paulineAddr = pauline.getIdentity();
+		Address laureAddr = laure.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(laureAddr.toC()));
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues";
+		LinphoneChatRoom *marieCr =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject,
+		                                 encrypted, LinphoneChatRoomEphemeralModeDeviceManaged);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(paulineCr);
+		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure.getCMgr(), &laure_stat,
+		                                                                 confAddr, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(laureCr);
+		if (paulineCr && laureCr) {
+			// Marie sends the message
+			const char *marieMessage = "Hey ! What's up ?";
+			msg = _send_message_ephemeral(marieCr, marieMessage, FALSE);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+			                             pauline_stat.number_of_LinphoneMessageReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			LinphoneChatMessage *paulineLastMsg = pauline.getStats().last_received_chat_message;
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneMessageReceived,
+			                             laure_stat.number_of_LinphoneMessageReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			LinphoneChatMessage *laureLastMsg = laure.getStats().last_received_chat_message;
+			linphone_chat_message_unref(msg);
+			if (paulineLastMsg && laureLastMsg) {
+				// Check that the message was correctly decrypted if encrypted
+				BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(paulineLastMsg), marieMessage);
+				LinphoneAddress *marieAddr = linphone_address_new(linphone_core_get_identity(marie.getLc()));
+				BC_ASSERT_TRUE(
+				    linphone_address_weak_equal(marieAddr, linphone_chat_message_get_from_address(paulineLastMsg)));
+				BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(laureLastMsg), marieMessage);
+				BC_ASSERT_TRUE(
+				    linphone_address_weak_equal(marieAddr, linphone_chat_message_get_from_address(laureLastMsg)));
+				linphone_address_unref(marieAddr);
+			}
+		}
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, laure}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void group_chat_room_lime_server_encrypted_message(void) {
+	group_chat_room_lime_server_message(TRUE);
+}
+
+static void group_chat_room_lime_server_clear_message(void) {
+	group_chat_room_lime_server_message(FALSE);
+}
+
+static void group_chat_room_lime_session_corrupted(void) {
+	Focus focus("chloe_rc");
+	LinphoneChatMessage *msg;
+	{ // to make sure focus is destroyed after clients.
+		linphone_core_enable_lime_x3dh(focus.getLc(), true);
+
+		ClientConference marie("marie_rc", focus.getIdentity(), true);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), true);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), true);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(laure.getLc()));
+
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+		stats laure_stat = laure.getStats();
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_X3dhUserCreationSuccess,
+		                             marie_stat.number_of_X3dhUserCreationSuccess + 1, x3dhServer_creationTimeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_X3dhUserCreationSuccess,
+		                             laure_stat.number_of_X3dhUserCreationSuccess + 1, x3dhServer_creationTimeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_X3dhUserCreationSuccess,
+		                             pauline_stat.number_of_X3dhUserCreationSuccess + 1, x3dhServer_creationTimeout));
+
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie.getLc()));
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(pauline.getLc()));
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(laure.getLc()));
+
+		Address paulineAddr = pauline.getIdentity();
+		Address laureAddr = laure.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(laureAddr.toC()));
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues";
+		LinphoneChatRoom *marieCr =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject,
+		                                 TRUE, LinphoneChatRoomEphemeralModeDeviceManaged);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(paulineCr);
+		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure.getCMgr(), &laure_stat,
+		                                                                 confAddr, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(laureCr);
+		if (paulineCr && laureCr) {
+			// Marie sends the message
+			const char *marieMessage = "Hey ! What's up ?";
+			msg = _send_message(marieCr, marieMessage);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+			                             pauline_stat.number_of_LinphoneMessageReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			LinphoneChatMessage *paulineLastMsg = pauline.getStats().last_received_chat_message;
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneMessageReceived,
+			                             laure_stat.number_of_LinphoneMessageReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			LinphoneChatMessage *laureLastMsg = laure.getStats().last_received_chat_message;
+			linphone_chat_message_unref(msg);
+			if (!BC_ASSERT_PTR_NOT_NULL(paulineLastMsg)) goto end;
+			if (!BC_ASSERT_PTR_NOT_NULL(laureLastMsg)) goto end;
+
+			// Check that the message was correctly decrypted if encrypted
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(paulineLastMsg), marieMessage);
+			LinphoneAddress *marieAddr = linphone_address_new(linphone_core_get_identity(marie.getLc()));
+			BC_ASSERT_TRUE(
+			    linphone_address_weak_equal(marieAddr, linphone_chat_message_get_from_address(paulineLastMsg)));
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(laureLastMsg), marieMessage);
+			BC_ASSERT_TRUE(
+			    linphone_address_weak_equal(marieAddr, linphone_chat_message_get_from_address(laureLastMsg)));
+			linphone_address_unref(marieAddr);
+
+			// Corrupt Pauline sessions in lime database: WARNING: if SOCI is not found, this call does nothing and the
+			// test fails
+			lime_delete_DRSessions(pauline.getCMgr()->lime_database_path);
+			// Trick to force the reloading of the lime engine so the session in cache is cleared
+			linphone_core_enable_lime_x3dh(pauline.getLc(), FALSE);
+			linphone_core_enable_lime_x3dh(pauline.getLc(), TRUE);
+
+			// Marie send a new message, it shall fail and get a 488 response
+			const char *marieTextMessage2 = "Do you copy?";
+			msg = _send_message(marieCr, marieTextMessage2);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDelivered,
+			                             marie_stat.number_of_LinphoneMessageDelivered + 2,
+			                             liblinphone_tester_sip_timeout)); // Delivered to the server
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneMessageReceived,
+			                             laure_stat.number_of_LinphoneMessageReceived + 2,
+			                             liblinphone_tester_sip_timeout)); // the message is correctly received by Laure
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageNotDelivered,
+			                             marie_stat.number_of_LinphoneMessageNotDelivered + 1,
+			                             liblinphone_tester_sip_timeout)); // Not delivered to pauline
+			BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneMessageReceived, 1, int, "%d");
+			linphone_chat_message_unref(msg);
+			laureLastMsg = laure.getStats().last_received_chat_message;
+			if (!BC_ASSERT_PTR_NOT_NULL(laureLastMsg)) goto end;
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(laureLastMsg), marieTextMessage2);
+			marieAddr = linphone_address_new(linphone_core_get_identity(marie.getLc()));
+			BC_ASSERT_TRUE(
+			    linphone_address_weak_equal(marieAddr, linphone_chat_message_get_from_address(laureLastMsg)));
+			linphone_address_unref(marieAddr);
+
+			// Try again, it shall work this time
+			const char *marieTextMessage3 = "Hello again";
+			marie_stat = marie.getStats();
+			msg = _send_message(marieCr, marieTextMessage3);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageSent, 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDelivered,
+			                             marie_stat.number_of_LinphoneMessageDelivered + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+			                             pauline_stat.number_of_LinphoneMessageReceived + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneMessageReceived,
+			                             laure_stat.number_of_LinphoneMessageReceived + 3,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDeliveredToUser,
+			                             marie_stat.number_of_LinphoneMessageDeliveredToUser + 1,
+			                             liblinphone_tester_sip_timeout));
+			paulineLastMsg = pauline.getStats().last_received_chat_message;
+			if (!BC_ASSERT_PTR_NOT_NULL(paulineLastMsg)) goto end;
+			laureLastMsg = laure.getStats().last_received_chat_message;
+			if (!BC_ASSERT_PTR_NOT_NULL(laureLastMsg)) goto end;
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(paulineLastMsg), marieTextMessage3);
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(laureLastMsg), marieTextMessage3);
+			marieAddr = linphone_address_new(linphone_core_get_identity(marie.getLc()));
+			BC_ASSERT_TRUE(
+			    linphone_address_weak_equal(marieAddr, linphone_chat_message_get_from_address(paulineLastMsg)));
+			BC_ASSERT_TRUE(
+			    linphone_address_weak_equal(marieAddr, linphone_chat_message_get_from_address(laureLastMsg)));
+			linphone_address_unref(marieAddr);
+			linphone_chat_message_unref(msg);
+		}
+
+	end:
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, laure}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
+static void one_to_one_group_chat_room_deletion_by_server_client_base(bool encrypted) {
+	Focus focus("chloe_rc");
+	LinphoneChatMessage *msg;
+	{ // to make sure focus is destroyed after clients.
+		linphone_core_enable_lime_x3dh(focus.getLc(), true);
+
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+
+		stats marie_stat = marie.getStats();
+		stats pauline_stat = pauline.getStats();
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+
+		if (encrypted) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_X3dhUserCreationSuccess,
+			                             marie_stat.number_of_X3dhUserCreationSuccess + 1, x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_X3dhUserCreationSuccess,
+			                             pauline_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(pauline.getLc()));
+		}
+
+		Address paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr.toC()));
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues";
+		LinphoneChatRoom *marieCr =
+		    create_chat_room_client_side(coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject,
+		                                 encrypted, LinphoneChatRoomEphemeralModeDeviceManaged);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		// Check that the chat room is correctly created on Pauline's side and that the participants are added
+		LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 1, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(paulineCr);
+
+		if (paulineCr && marieCr) {
+			// Marie sends the message
+			const char *marieMessage = "Hey ! What's up ?";
+			msg = _send_message(marieCr, marieMessage);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+			                             pauline_stat.number_of_LinphoneMessageReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			LinphoneChatMessage *paulineLastMsg = pauline.getStats().last_received_chat_message;
+			linphone_chat_message_unref(msg);
+			BC_ASSERT_PTR_NOT_NULL(paulineLastMsg);
+
+			// Check that the message was correctly decrypted if encrypted
+			BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_utf8_text(paulineLastMsg), marieMessage);
+			LinphoneAddress *marieAddr = linphone_address_new(linphone_core_get_identity(marie.getLc()));
+			BC_ASSERT_TRUE(
+			    linphone_address_weak_equal(marieAddr, linphone_chat_message_get_from_address(paulineLastMsg)));
+			linphone_address_unref(marieAddr);
+
+			LinphoneAddress *localAddr = linphone_address_clone(linphone_chat_room_get_local_address(paulineCr));
+			LinphoneAddress *peerAddr = linphone_address_clone(linphone_chat_room_get_peer_address(paulineCr));
+
+			// Restart pauline so that she has to send an INVITE and BYE it to exit the chatroom
+			coresList = bctbx_list_remove(coresList, pauline.getLc());
+			pauline.reStart();
+			setup_mgr_for_conference(pauline.getCMgr(), NULL);
+			coresList = bctbx_list_append(coresList, pauline.getLc());
+			paulineCr = linphone_core_search_chat_room(pauline.getLc(), NULL, localAddr, peerAddr, NULL);
+			BC_ASSERT_PTR_NOT_NULL(paulineCr);
+
+			LinphoneChatRoom *focusCr = linphone_core_search_chat_room(focus.getLc(), NULL, NULL, peerAddr, NULL);
+			BC_ASSERT_PTR_NOT_NULL(focusCr);
+
+			LinphoneParticipant *paulineParticipant = NULL;
+			LinphoneParticipantDevice *paulineDevice = NULL;
+
+			if (focusCr) {
+				paulineParticipant = linphone_chat_room_find_participant(focusCr, localAddr);
+				BC_ASSERT_PTR_NOT_NULL(paulineParticipant);
+				if (paulineParticipant) {
+					paulineDevice = linphone_participant_find_device(paulineParticipant, localAddr);
+					BC_ASSERT_PTR_NOT_NULL(paulineDevice);
+				}
+			}
+
+			linphone_address_unref(localAddr);
+			linphone_address_unref(peerAddr);
+
+			OrtpNetworkSimulatorParams simparams = {0};
+			simparams.mode = OrtpNetworkSimulatorOutbound;
+			simparams.enabled = TRUE;
+			simparams.max_bandwidth = 430000; /*we first limit to 430 kbit/s*/
+			simparams.max_buffer_size = (int)simparams.max_bandwidth;
+			simparams.latency = 60;
+			simparams.loss_rate = 90;
+			linphone_core_set_network_simulator_params(pauline.getLc(), &simparams);
+			linphone_core_set_network_simulator_params(focus.getLc(), &simparams);
+
+			linphone_core_delete_chat_room(marie.getLc(), marieCr);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateDeleted,
+			                             marie_stat.number_of_LinphoneConferenceStateDeleted + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			// wait until chatroom is deleted server side
+			BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline}).wait([&paulineDevice] {
+				return (paulineDevice) ? (linphone_participant_device_get_state(paulineDevice) ==
+				                          LinphoneParticipantDeviceStateLeaving)
+				                       : false;
+			}));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneChatRoomSessionReleased, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			linphone_core_delete_chat_room(pauline.getLc(), paulineCr);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateDeleted,
+			                             pauline_stat.number_of_LinphoneConferenceStateDeleted + 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+	}
+}
+
+static void secure_one_to_one_group_chat_room_deletion_by_server_client(void) {
+	one_to_one_group_chat_room_deletion_by_server_client_base(TRUE);
+}
+
+static void one_to_one_group_chat_room_deletion_by_server_client(void) {
+	one_to_one_group_chat_room_deletion_by_server_client_base(FALSE);
+}
+
+static void conference_scheduler_state_changed(LinphoneConferenceScheduler *scheduler,
+                                               LinphoneConferenceSchedulerState state) {
+	stats *stat = get_stats(linphone_conference_scheduler_get_core(scheduler));
+	switch (state) {
+		case LinphoneConferenceSchedulerStateIdle:
+			stat->number_of_ConferenceSchedulerStateIdle++;
+			break;
+		case LinphoneConferenceSchedulerStateAllocationPending:
+			stat->number_of_ConferenceSchedulerStateAllocationPending++;
+			break;
+		case LinphoneConferenceSchedulerStateReady:
+			stat->number_of_ConferenceSchedulerStateReady++;
+			break;
+		case LinphoneConferenceSchedulerStateError:
+			stat->number_of_ConferenceSchedulerStateError++;
+			break;
+		case LinphoneConferenceSchedulerStateUpdating:
+			stat->number_of_ConferenceSchedulerStateUpdating++;
+			break;
+	}
+}
+
+static void conference_scheduler_invitations_sent(LinphoneConferenceScheduler *scheduler,
+                                                  BCTBX_UNUSED(const bctbx_list_t *failed_addresses)) {
+	stats *stat = get_stats(linphone_conference_scheduler_get_core(scheduler));
+	stat->number_of_ConferenceSchedulerInvitationsSent++;
+}
+
+static void check_conference_info(LinphoneCoreManager *mgr,
+                                  LinphoneAddress *confAddr,
+                                  LinphoneCoreManager *organizer,
+                                  size_t no_members,
+                                  long long start_time,
+                                  int duration,
+                                  const char *subject,
+                                  const char *description,
+                                  unsigned int sequence,
+                                  LinphoneConferenceInfoState state) {
+	LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr);
+	if (BC_ASSERT_PTR_NOT_NULL(info)) {
+		BC_ASSERT_TRUE(linphone_address_weak_equal(organizer->identity, linphone_conference_info_get_organizer(info)));
+		BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
+
+		const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+		BC_ASSERT_EQUAL(bctbx_list_size(info_participants), no_members, size_t, "%zu");
+
+		if (start_time > 0) {
+			BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(info), start_time, long long, "%lld");
+		} else {
+			BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld");
+		}
+		const int duration_m = linphone_conference_info_get_duration(info);
+		BC_ASSERT_EQUAL(duration_m, ((duration < 0) ? 0 : duration), int, "%d");
+		if (subject) {
+			BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(info), subject);
+		} else {
+			BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(info));
+		}
+		if (description) {
+			BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(info), description);
+		} else {
+			BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(info));
+		}
+		const unsigned int ics_sequence = linphone_conference_info_get_ics_sequence(info);
+		BC_ASSERT_EQUAL(ics_sequence, sequence, int, "%d");
+		BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(info), (int)state, int, "%d");
+		linphone_conference_info_unref(info);
+	}
+}
+
+static bool have_common_audio_payload(LinphoneCoreManager *mgr1, LinphoneCoreManager *mgr2) {
+	bool found = false;
+	const bctbx_list_t *elem = linphone_core_get_audio_codecs(mgr1->lc);
+	for (; elem != NULL; elem = elem->next) {
+		PayloadType *pt1 = (PayloadType *)elem->data;
+		if (linphone_core_payload_type_enabled(mgr1->lc, pt1) == TRUE) {
+			LinphonePayloadType *pt2 =
+			    linphone_core_get_payload_type(mgr2->lc, pt1->mime_type, pt1->clock_rate, pt1->channels);
+			if (pt2 && linphone_payload_type_enabled(pt2)) {
+				found = true;
+			}
+			linphone_payload_type_unref(pt2);
+		}
+	}
+	return found;
+}
+
+static LinphoneAddress *
+create_conference_on_server(Focus &focus,
+                            ClientConference &organizer,
+                            std::map<LinphoneCoreManager *, LinphoneParticipantRole> requested_participants,
+                            time_t start_time,
+                            time_t end_time,
+                            const char *subject,
+                            const char *description,
+                            bool_t send_ics) {
+	bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+	coresList = bctbx_list_append(coresList, organizer.getLc());
+	std::vector<stats> participant_stats;
+	std::map<LinphoneCoreManager *, LinphoneCall *> previous_calls;
+	bctbx_list_t *participant_infos = NULL;
+	std::list<LinphoneCoreManager *> participants;
+	const LinphoneConferenceInfo *updated_conf_info = NULL;
+	bool focus_organizer_common_payload = have_common_audio_payload(organizer.getCMgr(), focus.getCMgr());
+	bool dialout = ((end_time <= 0) && (start_time <= 0));
+	bool found_me = false;
+	char *conference_address_str = NULL;
+	size_t organizer_expected_participant_number = 0;
+	size_t participant_expected_participant_number = 0;
+	char *uid = NULL;
+	LinphoneConferenceInfo *info = NULL;
+	for (auto &p : requested_participants) {
+		LinphoneParticipantInfo *participant_info = linphone_participant_info_new(p.first->identity);
+		linphone_participant_info_set_role(participant_info, p.second);
+		participant_infos = bctbx_list_append(participant_infos, participant_info);
+		LinphoneCoreManager *mgr = p.first;
+		if (mgr == organizer.getCMgr()) {
+			found_me = true;
+		} else {
+			coresList = bctbx_list_append(coresList, mgr->lc);
+			participant_stats.push_back(mgr->stat);
+			participants.push_back(mgr);
+		}
+	}
+
+	stats organizer_stat = organizer.getStats();
+	stats focus_stat = focus.getStats();
+
+	for (auto &mgr : participants) {
+		previous_calls[mgr] = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+	}
+
+	// Marie creates a new group chat room
+	LinphoneConferenceScheduler *conference_scheduler = linphone_core_create_conference_scheduler(organizer.getLc());
+	LinphoneConferenceSchedulerCbs *cbs = linphone_factory_create_conference_scheduler_cbs(linphone_factory_get());
+	linphone_conference_scheduler_cbs_set_state_changed(cbs, conference_scheduler_state_changed);
+	linphone_conference_scheduler_cbs_set_invitations_sent(cbs, conference_scheduler_invitations_sent);
+	linphone_conference_scheduler_add_callbacks(conference_scheduler, cbs);
+	linphone_conference_scheduler_cbs_unref(cbs);
+
+	LinphoneConferenceInfo *conf_info = linphone_conference_info_new();
+
+	LinphoneAccount *default_account = linphone_core_get_default_account(organizer.getLc());
+	LinphoneAddress *organizer_address = default_account
+	                                         ? linphone_address_clone(linphone_account_params_get_identity_address(
+	                                               linphone_account_get_params(default_account)))
+	                                         : linphone_address_new(linphone_core_get_identity(organizer.getLc()));
+	linphone_conference_info_set_organizer(conf_info, organizer_address);
+	linphone_conference_info_set_participants_2(conf_info, participant_infos);
+	if ((end_time >= 0) && (start_time >= 0) && (end_time > start_time)) {
+		linphone_conference_info_set_duration(
+		    conf_info, (int)((end_time - start_time) / 60)); // duration is expected to be set in minutes
+	}
+	linphone_conference_info_set_date_time(conf_info, start_time);
+	linphone_conference_info_set_subject(conf_info, subject);
+	linphone_conference_info_set_description(conf_info, description);
+
+	linphone_conference_scheduler_set_info(conference_scheduler, conf_info);
+	linphone_conference_info_unref(conf_info);
+
+	BC_ASSERT_TRUE(wait_for_list(coresList, &organizer.getStats().number_of_ConferenceSchedulerStateAllocationPending,
+	                             organizer_stat.number_of_ConferenceSchedulerStateAllocationPending + 1,
+	                             liblinphone_tester_sip_timeout));
+
+	int idx = 0;
+	std::list<LinphoneCoreManager *> actual_participants;
+	int call_errors_cnt = 0;
+	LinphoneAddress *conference_address = NULL;
+	if (dialout) {
+
+		if (focus_organizer_common_payload) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &organizer.getStats().number_of_LinphoneCallOutgoingInit,
+			                             organizer_stat.number_of_LinphoneCallOutgoingInit + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+			                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+		} else {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &organizer.getStats().number_of_ConferenceSchedulerStateError,
+			                             organizer_stat.number_of_ConferenceSchedulerStateError + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			updated_conf_info = linphone_conference_scheduler_get_info(conference_scheduler);
+			goto end;
+		}
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingInit,
+		                  focus_stat.number_of_LinphoneCallOutgoingInit + static_cast<int>(participants.size()),
+		                  liblinphone_tester_sip_timeout));
+
+		int call_ok_cnt = 0;
+		// Conference server dials out participants
+		for (auto &mgr : participants) {
+			auto old_stats = participant_stats[idx];
+			if (have_common_audio_payload(mgr, focus.getCMgr()) && !previous_calls[mgr]) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallIncomingReceived,
+				                             old_stats.number_of_LinphoneCallIncomingReceived + 1,
+				                             liblinphone_tester_sip_timeout));
+				call_ok_cnt++;
+				actual_participants.push_back(mgr);
+			} else {
+				call_errors_cnt++;
+			}
+			idx++;
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingProgress,
+		                             focus_stat.number_of_LinphoneCallOutgoingProgress + call_ok_cnt,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingRinging,
+		                             focus_stat.number_of_LinphoneCallOutgoingRinging + call_ok_cnt,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_alerting,
+		                             focus_stat.number_of_participant_devices_alerting + call_ok_cnt,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallError,
+		                             focus_stat.number_of_LinphoneCallError + call_errors_cnt,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed + call_errors_cnt,
+		                             liblinphone_tester_sip_timeout));
+
+		if (focus_organizer_common_payload) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &organizer.getStats().number_of_participant_devices_removed,
+			                             organizer_stat.number_of_participant_devices_removed + call_errors_cnt,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+	} else {
+		actual_participants = participants;
+	}
+
+	BC_ASSERT_TRUE(wait_for_list(coresList, &organizer.getStats().number_of_ConferenceSchedulerStateReady,
+	                             organizer_stat.number_of_ConferenceSchedulerStateReady + 1,
+	                             liblinphone_tester_sip_timeout));
+
+	updated_conf_info = linphone_conference_scheduler_get_info(conference_scheduler);
+	conference_address = linphone_address_clone(linphone_conference_info_get_uri(updated_conf_info));
+
+	if (!!send_ics) {
+		LinphoneChatRoomParams *chat_room_params = linphone_core_create_default_chat_room_params(organizer.getLc());
+		linphone_chat_room_params_set_backend(chat_room_params, LinphoneChatRoomBackendBasic);
+		linphone_conference_scheduler_send_invitations(conference_scheduler, chat_room_params);
+		linphone_chat_room_params_unref(chat_room_params);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &organizer.getStats().number_of_ConferenceSchedulerInvitationsSent,
+		                             organizer_stat.number_of_ConferenceSchedulerInvitationsSent + 1,
+		                             liblinphone_tester_sip_timeout));
+	}
+
+	info = linphone_core_find_conference_information_from_uri(organizer.getLc(), conference_address);
+	if (BC_ASSERT_PTR_NOT_NULL(info)) {
+		uid = ms_strdup(linphone_conference_info_get_ics_uid(info));
+		if (!!send_ics) {
+			BC_ASSERT_PTR_NOT_NULL(uid);
+			for (auto &p : participants) {
+				linphone_conference_info_check_participant(info, p->identity, 0);
+			}
+		} else {
+			BC_ASSERT_PTR_NULL(uid);
+		}
+		linphone_conference_info_unref(info);
+	}
+
+	organizer_expected_participant_number =
+	    requested_participants.size() + ((!found_me && dialout && focus_organizer_common_payload) ? 1 : 0);
+	participant_expected_participant_number =
+	    requested_participants.size() + ((!found_me && dialout && focus_organizer_common_payload) ? 1 : 0);
+	check_conference_info(organizer.getCMgr(), conference_address, organizer.getCMgr(),
+	                      organizer_expected_participant_number, start_time,
+	                      ((start_time > 0) && (end_time > 0)) ? (int)(end_time - start_time) / 60 : 0, subject,
+	                      description, 0, LinphoneConferenceInfoStateNew);
+
+	idx = 0;
+	for (auto &mgr : participants) {
+		if (!dialout || !previous_calls[mgr]) {
+			auto old_stats = participant_stats[idx];
+			if (!!send_ics) {
+				// chat room in created state
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceived,
+				                             old_stats.number_of_LinphoneMessageReceived + 1,
+				                             liblinphone_tester_sip_timeout));
+				if (!linphone_core_conference_ics_in_message_body_enabled(organizer.getLc())) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceivedWithFile,
+					                             old_stats.number_of_LinphoneMessageReceivedWithFile + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				BC_ASSERT_PTR_NOT_NULL(mgr->stat.last_received_chat_message);
+				if (mgr->stat.last_received_chat_message != NULL) {
+					const string expected = ContentType::Icalendar.getMediaType();
+					BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_content_type(mgr->stat.last_received_chat_message),
+					                       expected.c_str());
+				}
+
+				bctbx_list_t *chat_room_participants = bctbx_list_append(NULL, mgr->identity);
+				LinphoneChatRoom *cr = linphone_core_search_chat_room(organizer.getLc(), NULL, organizer_address, NULL,
+				                                                      chat_room_participants);
+				bctbx_list_free(chat_room_participants);
+				BC_ASSERT_PTR_NOT_NULL(cr);
+				if (cr) {
+					LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
+					BC_ASSERT_PTR_NOT_NULL(msg);
+
+					if (msg) {
+						const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
+						BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
+						LinphoneContent *original_content = (LinphoneContent *)bctbx_list_get_data(original_contents);
+						BC_ASSERT_PTR_NOT_NULL(original_content);
+
+						LinphoneConferenceInfo *conf_info_in_db =
+						    linphone_core_find_conference_information_from_uri(mgr->lc, conference_address);
+						if (!BC_ASSERT_PTR_NOT_NULL(conf_info_in_db)) {
+							goto end;
+						}
+
+						LinphoneConferenceInfo *conf_info_from_original_content =
+						    linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(),
+						                                                                   original_content);
+						if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) {
+							BC_ASSERT_TRUE(linphone_address_weak_equal(
+							    organizer_address,
+							    linphone_conference_info_get_organizer(conf_info_from_original_content)));
+							BC_ASSERT_TRUE(linphone_address_equal(
+							    linphone_conference_info_get_organizer(conf_info_in_db),
+							    linphone_conference_info_get_organizer(conf_info_from_original_content)));
+							BC_ASSERT_TRUE(linphone_address_weak_equal(
+							    conference_address, linphone_conference_info_get_uri(conf_info_from_original_content)));
+							BC_ASSERT_TRUE(linphone_address_equal(
+							    linphone_conference_info_get_uri(conf_info_in_db),
+							    linphone_conference_info_get_uri(conf_info_from_original_content)));
+
+							const bctbx_list_t *ics_participants =
+							    linphone_conference_info_get_participants(conf_info_from_original_content);
+							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participant_expected_participant_number,
+							                size_t, "%zu");
+
+							const bctbx_list_t *ics_participants_db =
+							    linphone_conference_info_get_participants(conf_info_in_db);
+							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants_db),
+							                participant_expected_participant_number, size_t, "%zu");
+
+							if (start_time > 0) {
+								BC_ASSERT_EQUAL(
+								    (long long)linphone_conference_info_get_date_time(conf_info_from_original_content),
+								    (long long)start_time, long long, "%lld");
+								BC_ASSERT_EQUAL(
+								    (long long)linphone_conference_info_get_date_time(conf_info_in_db),
+								    (long long)linphone_conference_info_get_date_time(conf_info_from_original_content),
+								    long long, "%lld");
+								if (end_time > 0) {
+									const int duration_s =
+									    linphone_conference_info_get_duration(conf_info_from_original_content) * 60;
+									BC_ASSERT_EQUAL(duration_s, (int)(end_time - start_time), int, "%d");
+									BC_ASSERT_EQUAL(
+									    (int)linphone_conference_info_get_duration(conf_info_in_db),
+									    (int)linphone_conference_info_get_duration(conf_info_from_original_content),
+									    int, "%0d");
+								}
+							}
+							if (subject) {
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_subject(conf_info_from_original_content), subject);
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_subject(conf_info_in_db),
+								    linphone_conference_info_get_subject(conf_info_from_original_content));
+							} else {
+								BC_ASSERT_PTR_NULL(
+								    linphone_conference_info_get_subject(conf_info_from_original_content));
+								BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(conf_info_in_db));
+							}
+							if (description) {
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_description(conf_info_from_original_content),
+								    description);
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_description(conf_info_from_original_content),
+								    linphone_conference_info_get_description(conf_info_in_db));
+							} else {
+								BC_ASSERT_PTR_NULL(
+								    linphone_conference_info_get_description(conf_info_from_original_content));
+								BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(conf_info_in_db));
+							}
+							BC_ASSERT_STRING_EQUAL(
+							    linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid);
+							BC_ASSERT_STRING_EQUAL(
+							    linphone_conference_info_get_ics_uid(conf_info_in_db),
+							    linphone_conference_info_get_ics_uid(conf_info_from_original_content));
+
+							const unsigned int ics_sequence =
+							    linphone_conference_info_get_ics_sequence(conf_info_in_db);
+							BC_ASSERT_EQUAL(ics_sequence, 0, int, "%d");
+							BC_ASSERT_EQUAL(linphone_conference_info_get_ics_sequence(conf_info_in_db),
+							                linphone_conference_info_get_ics_sequence(conf_info_from_original_content),
+							                unsigned int, "%0u");
+							linphone_conference_info_unref(conf_info_from_original_content);
+							linphone_conference_info_unref(conf_info_in_db);
+						}
+						linphone_chat_message_unref(msg);
+					}
+				}
+			}
+
+			if (!!send_ics || ((end_time <= 0) && (start_time <= 0))) {
+				auto itConferenceMgrs = std::find(actual_participants.begin(), actual_participants.end(), mgr);
+				if (itConferenceMgrs != actual_participants.end()) {
+					LinphoneConferenceInfo *conf_info_in_db =
+					    linphone_core_find_conference_information_from_uri(mgr->lc, conference_address);
+					if (!BC_ASSERT_PTR_NOT_NULL(conf_info_in_db)) {
+						goto end;
+					}
+					check_conference_info(
+					    mgr, conference_address, organizer.getCMgr(), participant_expected_participant_number,
+					    start_time, ((start_time > 0) && (end_time > 0)) ? (int)(end_time - start_time) / 60 : 0,
+					    subject, (!!send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew);
+					if (!!send_ics) {
+						for (auto &p : participants) {
+							linphone_conference_info_check_participant(conf_info_in_db, p->identity, 0);
+						}
+						linphone_conference_info_check_organizer(conf_info_in_db, 0);
+					}
+					if (conf_info_in_db) {
+						linphone_conference_info_unref(conf_info_in_db);
+					}
+				}
+			}
+		}
+
+		idx++;
+	}
+
+	if (uid) {
+		ms_free(uid);
+	}
+
+	if (!!send_ics || ((end_time <= 0) && (start_time <= 0))) {
+		if (conference_address) {
+			check_conference_info(organizer.getCMgr(), conference_address, organizer.getCMgr(),
+			                      organizer_expected_participant_number, start_time,
+			                      (((start_time > 0) && (end_time > 0)) ? (int)(end_time - start_time) / 60 : 0),
+			                      subject, description, 0, LinphoneConferenceInfoStateNew);
+		}
+
+		BC_ASSERT_EQUAL(organizer.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                organizer_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(organizer.getStats().number_of_LinphoneConferenceStateTerminated,
+		                organizer_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(organizer.getStats().number_of_LinphoneConferenceStateDeleted,
+		                organizer_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+	}
+
+	conference_address_str =
+	    (conference_address) ? linphone_address_as_string(conference_address) : ms_strdup("<unknown>");
+	ms_message("%s is creating conference %s on server %s", linphone_core_get_identity(organizer.getLc()),
+	           conference_address_str, linphone_core_get_identity(focus.getLc()));
+	ms_free(conference_address_str);
+
+end:
+	if (organizer_address) linphone_address_unref(organizer_address);
+	linphone_conference_scheduler_unref(conference_scheduler);
+	bctbx_list_free(coresList);
+	bctbx_list_free_with_data(participant_infos, (bctbx_list_free_func)linphone_participant_info_unref);
+
+	return conference_address;
+}
+
+static size_t compute_no_video_streams(bool_t enable_video, LinphoneCall *call, LinphoneConference *conference) {
+	size_t nb_video_streams = 0;
+
+	const LinphoneCallParams *call_params =
+	    linphone_call_is_in_conference(call) ? linphone_call_get_remote_params(call) : linphone_call_get_params(call);
+
+	bool_t call_video_enabled = linphone_call_params_video_enabled(call_params);
+	LinphoneMediaDirection call_video_dir = linphone_call_params_get_video_direction(call_params);
+	LinphoneConferenceLayout call_video_layout = linphone_call_params_get_conference_video_layout(call_params);
+	if (enable_video && call_video_enabled && (call_video_dir != LinphoneMediaDirectionInactive)) {
+		bctbx_list_t *devices = linphone_conference_get_participant_device_list(conference);
+		for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+			LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+			LinphoneMediaDirection dir = linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo);
+			if ((dir == LinphoneMediaDirectionSendRecv) || (dir == LinphoneMediaDirectionSendOnly)) {
+				nb_video_streams++;
+			}
+		}
+		bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+
+		if (((call_video_layout == LinphoneConferenceLayoutActiveSpeaker) &&
+		     (call_video_dir == LinphoneMediaDirectionRecvOnly)) ||
+		    (call_video_dir == LinphoneMediaDirectionSendRecv) || (call_video_dir == LinphoneMediaDirectionSendOnly)) {
+			nb_video_streams += 1;
+		}
+	} else {
+		nb_video_streams = 0;
+	}
+
+	return nb_video_streams;
+}
+
+static void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs,
+                                        std::list<LinphoneCoreManager *> conferenceMgrs,
+                                        LinphoneCoreManager *focus,
+                                        std::map<LinphoneCoreManager *, LinphoneParticipantRole> members,
+                                        const LinphoneAddress *confAddr,
+                                        bool_t enable_video) {
+	for (auto mgr : conferenceMgrs) {
+		// wait bit more to detect side effect if any
+		BC_ASSERT_TRUE(CoreManagerAssert(coreMgrs).waitUntil(chrono::seconds(50), [mgr, &focus, &members, confAddr,
+		                                                                           enable_video] {
+			size_t nb_audio_streams = 1;
+			size_t nb_text_streams = 0;
+			std::list<LinphoneCall *> calls;
+
+			bool video_check = false;
+			bool participant_check = false;
+			bool device_present = false;
+			bool call_ok = true;
+			bool audio_direction_ok = true;
+
+			if (mgr == focus) {
+				for (auto m : members) {
+					LinphoneCoreManager *mMgr = m.first;
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mMgr->lc, confAddr);
+					call_ok &= (pcall != nullptr);
+					LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, mMgr->identity);
+					call_ok &= (call != nullptr);
+					if (call) {
+						calls.push_back(call);
+					} else {
+						calls.push_back(nullptr);
+					}
+				}
+			} else {
+				LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+				call_ok &= (call != nullptr);
+				if (call) {
+					calls.push_back(call);
+				} else {
+					calls.push_back(nullptr);
+				}
+			}
+
+			call_ok &= (calls.size() > 0);
+			LinphoneConference *conference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			for (auto call : calls) {
+				if (call) {
+					size_t nb_video_streams = compute_no_video_streams(enable_video, call, conference);
+					const SalMediaDescription *call_result_desc = _linphone_call_get_result_desc(call);
+					call_ok &= ((call_result_desc->nbActiveStreamsOfType(SalAudio) == nb_audio_streams) &&
+					            (call_result_desc->nbActiveStreamsOfType(SalVideo) == nb_video_streams) &&
+					            (call_result_desc->nbActiveStreamsOfType(SalText) == nb_text_streams) &&
+					            (linphone_call_get_state(call) == LinphoneCallStateStreamsRunning));
+				}
+			}
+
+			if (conference) {
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(conference);
+				video_check = (bctbx_list_size(devices) > 0);
+				participant_check = (bctbx_list_size(devices) > 0);
+				device_present = (bctbx_list_size(devices) > 0);
+				LinphoneCall *call = NULL;
+				for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+					LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+					const LinphoneAddress *device_address = linphone_participant_device_get_address(d);
+					bool_t found = FALSE;
+					for (const auto &p : members) {
+						LinphoneCoreManager *mgr = p.first;
+						found |= linphone_address_weak_equal(mgr->identity, device_address);
+					}
+					if (mgr == focus) {
+						call = linphone_core_get_call_by_remote_address2(mgr->lc, device_address);
+					} else {
+						if (calls.front()) {
+							call = calls.front();
+						}
+					}
+
+					bool_t is_me = linphone_conference_is_me(conference, device_address);
+					LinphoneParticipant *p = is_me ? linphone_conference_get_me(conference)
+					                               : linphone_conference_find_participant(conference, device_address);
+					participant_check &= (p != nullptr);
+					LinphoneMediaDirection expected_audio_direction = LinphoneMediaDirectionInactive;
+					if (p) {
+						LinphoneParticipantRole role = linphone_participant_get_role(p);
+						expected_audio_direction =
+						    ((role == LinphoneParticipantRoleSpeaker) ? LinphoneMediaDirectionSendRecv
+						                                              : LinphoneMediaDirectionRecvOnly);
+						LinphoneMediaDirection audio_dir =
+						    linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeAudio);
+						audio_direction_ok &= (audio_dir == expected_audio_direction);
+					} else {
+						audio_direction_ok = false;
+					}
+
+					LinphoneParticipantDeviceState expected_state = LinphoneParticipantDeviceStateJoining;
+					if (found) {
+						expected_state = LinphoneParticipantDeviceStatePresent;
+					} else {
+						expected_state = LinphoneParticipantDeviceStateLeft;
+					}
+					device_present &= (linphone_participant_device_get_state(d) == expected_state);
+					if (call) {
+						if (is_me) {
+							const LinphoneCallParams *call_current_params = linphone_call_get_current_params(call);
+							LinphoneMediaDirection call_audio_direction =
+							    linphone_call_params_get_audio_direction(call_current_params);
+							audio_direction_ok &= (call_audio_direction == expected_audio_direction);
+						}
+
+						const LinphoneCallParams *call_params = linphone_call_get_params(call);
+						bool_t call_video_enabled = linphone_call_params_video_enabled(call_params);
+						if (enable_video && ((mgr == focus) || call_video_enabled)) {
+							// Video is available if the direction is sendrecv or sendonly
+							LinphoneMediaDirection video_dir =
+							    linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo);
+							video_check &=
+							    (linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) ==
+							     ((video_dir == LinphoneMediaDirectionSendRecv) ||
+							      (video_dir == LinphoneMediaDirectionSendOnly)));
+						} else {
+							video_check &=
+							    !linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo);
+						}
+					}
+				}
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+
+				for (auto m : members) {
+					LinphoneCoreManager *mMgr = m.first;
+					LinphoneParticipantRole role = m.second;
+					LinphoneParticipant *p = linphone_conference_is_me(conference, mMgr->identity)
+					                             ? linphone_conference_get_me(conference)
+					                             : linphone_conference_find_participant(conference, mMgr->identity);
+					participant_check &= (p != nullptr);
+					if (p) {
+						participant_check &= (linphone_participant_get_role(p) == role);
+					}
+				}
+			}
+			return audio_direction_ok && video_check && device_present && call_ok && participant_check;
+		}));
+	}
+}
+
+static void set_video_settings_in_conference(LinphoneCoreManager *focus,
+                                             LinphoneCoreManager *participant,
+                                             std::list<LinphoneCoreManager *> members,
+                                             const LinphoneAddress *confAddr,
+                                             bool_t enable_video,
+                                             LinphoneMediaDirection video_direction,
+                                             bool_t answer_enable_video,
+                                             LinphoneMediaDirection answer_video_direction) {
+	std::list<LinphoneCoreManager *> active_cores = members;
+	active_cores.push_back(focus);
+
+	bctbx_list_t *coresList = bctbx_list_append(NULL, focus->lc);
+	stats *participants_initial_stats = NULL;
+	stats focus_stat = focus->stat;
+	int counter = 1;
+	bool_t sendonly_video = TRUE;
+	bool_t recvonly_video = TRUE;
+
+	LinphoneConferenceLayout call_conference_layout = LinphoneConferenceLayoutGrid;
+
+	for (auto mgr : members) {
+		coresList = bctbx_list_append(coresList, mgr->lc);
+		// Allocate memory
+		participants_initial_stats = (stats *)realloc(participants_initial_stats, counter * sizeof(stats));
+		// Append element
+		participants_initial_stats[counter - 1] = mgr->stat;
+
+		LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+		BC_ASSERT_PTR_NOT_NULL(call);
+		if (call) {
+			if (participant != mgr) {
+				const LinphoneCallParams *call_params = linphone_call_get_current_params(call);
+				bool_t call_enable_video = linphone_call_params_video_enabled(call_params);
+				bool_t call_video_direction = linphone_call_params_get_video_direction(call_params);
+				if (call_enable_video) {
+					sendonly_video &= (call_video_direction == LinphoneMediaDirectionSendOnly);
+					recvonly_video &= (call_video_direction == LinphoneMediaDirectionRecvOnly);
+				}
+			} else {
+				const LinphoneCallParams *call_params = linphone_call_get_params(call);
+				call_conference_layout = linphone_call_params_get_conference_video_layout(call_params);
+			}
+		}
+
+		// Increment counter
+		counter++;
+	}
+
+	bool_t inactive_video = ((recvonly_video && (video_direction == LinphoneMediaDirectionRecvOnly)) ||
+	                         (sendonly_video && (video_direction == LinphoneMediaDirectionSendOnly))) &&
+	                        (call_conference_layout == LinphoneConferenceLayoutGrid);
+	bool_t previous_enable_video = FALSE;
+	LinphoneMediaDirection previous_video_direction = LinphoneMediaDirectionInvalid;
+
+	LinphoneCall *participant_call = linphone_core_get_call_by_remote_address2(participant->lc, confAddr);
+	BC_ASSERT_PTR_NOT_NULL(participant_call);
+	if (participant_call) {
+
+		const LinphoneCallParams *call_params = linphone_call_get_current_params(participant_call);
+		previous_enable_video = linphone_call_params_video_enabled(call_params);
+		previous_video_direction = linphone_call_params_get_video_direction(call_params);
+
+		ms_message("%s %s video with direction %s", linphone_core_get_identity(participant->lc),
+		           ((enable_video) ? "enables" : "disables"), linphone_media_direction_to_string(video_direction));
+
+		LinphoneCallParams *new_params = linphone_core_create_call_params(participant->lc, participant_call);
+		linphone_call_params_enable_video(new_params, enable_video);
+		linphone_call_params_set_video_direction(new_params, video_direction);
+		linphone_call_update(participant_call, new_params);
+		linphone_call_params_unref(new_params);
+	}
+
+	BC_ASSERT_TRUE(wait_for_list(coresList, &focus->stat.number_of_LinphoneCallUpdatedByRemote,
+	                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 1, liblinphone_tester_sip_timeout));
+
+	int focus_defer_update =
+	    !!linphone_config_get_int(linphone_core_get_config(focus->lc), "sip", "defer_update_default", FALSE);
+	bool_t enable = enable_video && ((focus_defer_update == TRUE) ? answer_enable_video : TRUE);
+	if (focus_defer_update == TRUE) {
+		LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(participant->lc));
+		LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus->lc, uri);
+		linphone_address_unref(uri);
+		BC_ASSERT_PTR_NOT_NULL(focus_call);
+		if (focus_call) {
+			ms_message("%s %s video with direction %s", linphone_core_get_identity(focus->lc),
+			           ((answer_enable_video) ? "accepts" : "refuses"),
+			           linphone_media_direction_to_string(answer_video_direction));
+			LinphoneCallParams *focus_params = linphone_core_create_call_params(focus->lc, focus_call);
+			linphone_call_params_enable_video(focus_params, answer_enable_video);
+			linphone_call_params_set_video_direction(focus_params, answer_video_direction);
+			linphone_call_accept_update(focus_call, focus_params);
+			linphone_call_params_unref(focus_params);
+		}
+	}
+
+	counter = 0;
+	int no_updates = 0;
+	for (auto mgr : members) {
+		if (((previous_enable_video != enable) && (previous_video_direction == LinphoneMediaDirectionSendRecv)) ||
+		    (enable && previous_enable_video && (previous_video_direction != video_direction)) ||
+		    (mgr == participant)) {
+			LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				const LinphoneCallParams *call_lparams = linphone_call_get_params(call);
+				if (linphone_call_params_video_enabled(call_lparams)) {
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating,
+					                             participants_initial_stats[counter].number_of_LinphoneCallUpdating + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(
+					    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning,
+					                  participants_initial_stats[counter].number_of_LinphoneCallStreamsRunning + 1,
+					                  liblinphone_tester_sip_timeout));
+
+					no_updates++;
+				}
+			}
+
+			if ((previous_enable_video == enable) && (!enable)) {
+				BC_ASSERT_FALSE(wait_for_list(
+				    coresList, &mgr->stat.number_of_participant_devices_media_capability_changed,
+				    participants_initial_stats[counter].number_of_participant_devices_media_capability_changed + 1,
+				    5000));
+			} else {
+				BC_ASSERT_TRUE(wait_for_list(
+				    coresList, &mgr->stat.number_of_participant_devices_media_capability_changed,
+				    participants_initial_stats[counter].number_of_participant_devices_media_capability_changed + 1,
+				    liblinphone_tester_sip_timeout));
+			}
+			BC_ASSERT_EQUAL(mgr->stat.number_of_participants_added,
+			                participants_initial_stats[counter].number_of_participants_added, int, "%0d");
+			BC_ASSERT_EQUAL(mgr->stat.number_of_participant_devices_added,
+			                participants_initial_stats[counter].number_of_participant_devices_added, int, "%0d");
+			BC_ASSERT_EQUAL(mgr->stat.number_of_participant_devices_joined,
+			                participants_initial_stats[counter].number_of_participant_devices_joined, int, "%0d");
+		}
+		counter++;
+	}
+	BC_ASSERT_TRUE(wait_for_list(coresList, &focus->stat.number_of_LinphoneCallUpdatedByRemote,
+	                             focus_stat.number_of_LinphoneCallUpdatedByRemote + no_updates,
+	                             liblinphone_tester_sip_timeout));
+	BC_ASSERT_TRUE(wait_for_list(coresList, &focus->stat.number_of_LinphoneCallStreamsRunning,
+	                             focus_stat.number_of_LinphoneCallStreamsRunning + no_updates,
+	                             liblinphone_tester_sip_timeout));
+	if ((previous_enable_video == enable) && (!enable)) {
+		BC_ASSERT_FALSE(wait_for_list(coresList, &focus->stat.number_of_participant_devices_media_capability_changed,
+		                              focus_stat.number_of_participant_devices_media_capability_changed + 1, 3000));
+	} else {
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus->stat.number_of_participant_devices_media_capability_changed,
+		                             focus_stat.number_of_participant_devices_media_capability_changed + 1,
+		                             liblinphone_tester_sip_timeout));
+	}
+	BC_ASSERT_EQUAL(focus->stat.number_of_participants_added, focus_stat.number_of_participants_added, int, "%0d");
+	BC_ASSERT_EQUAL(focus->stat.number_of_participant_devices_added, focus_stat.number_of_participant_devices_added,
+	                int, "%0d");
+	BC_ASSERT_EQUAL(focus->stat.number_of_participant_devices_joined, focus_stat.number_of_participant_devices_joined,
+	                int, "%0d");
+
+	for (auto mgr : active_cores) {
+		LinphoneAddress *uri2 = linphone_address_new(linphone_core_get_identity(mgr->lc));
+		LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri2, confAddr, NULL);
+		linphone_address_unref(uri2);
+		BC_ASSERT_PTR_NOT_NULL(pconference);
+		if (pconference) {
+			LinphoneParticipant *p = (mgr == participant)
+			                             ? linphone_conference_get_me(pconference)
+			                             : linphone_conference_find_participant(pconference, participant->identity);
+			BC_ASSERT_PTR_NOT_NULL(p);
+			if (p) {
+				bctbx_list_t *devices = linphone_participant_get_devices(p);
+				for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+					LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+					LinphoneMediaDirection expected_video_direction = video_direction;
+					if (enable == TRUE) {
+						if (recvonly_video && (video_direction == LinphoneMediaDirectionRecvOnly) &&
+						    (call_conference_layout == LinphoneConferenceLayoutGrid)) {
+							expected_video_direction = LinphoneMediaDirectionInactive;
+						} else {
+							expected_video_direction = video_direction;
+						}
+					} else {
+						expected_video_direction = LinphoneMediaDirectionInactive;
+					}
+					BC_ASSERT_EQUAL(linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo),
+					                expected_video_direction, int, "%0d");
+				}
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+			}
+		}
+	}
+
+	LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(participant->lc, confAddr);
+	BC_ASSERT_PTR_NOT_NULL(pcall);
+	if (pcall) {
+		const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+		BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enable_video, int, "%0d");
+		const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+		BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams),
+		                ((inactive_video) ? FALSE : ((focus_defer_update == TRUE) ? enable : enable_video)), int,
+		                "%0d");
+		const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+		BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), ((inactive_video) ? FALSE : enable), int,
+		                "%0d");
+	}
+
+	LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(participant->lc));
+	LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus->lc, uri);
+	linphone_address_unref(uri);
+	BC_ASSERT_PTR_NOT_NULL(ccall);
+	if (ccall) {
+		const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+		BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams),
+		                (focus_defer_update == TRUE) ? answer_enable_video : enable_video, int, "%0d");
+		const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+		BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enable_video, int, "%0d");
+		const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+		BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), ((inactive_video) ? FALSE : enable), int,
+		                "%0d");
+	}
+
+	bctbx_list_free(coresList);
+	ms_free(participants_initial_stats);
+}
+
+static void call_to_inexisting_conference_address(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+
+		bctbx_list_t *coresList = NULL;
+		coresList = bctbx_list_append(coresList, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+
+		focus.registerAsParticipantDevice(marie);
+
+		LinphoneAddress *confAddr = linphone_address_new(L_STRING_TO_C(focus.getIdentity().toString()));
+		linphone_address_set_uri_param(confAddr, "conf-id", "xxxxx");
+
+		stats marie_stat = marie.getStats();
+
+		LinphoneCallParams *new_params = linphone_core_create_call_params(marie.getLc(), nullptr);
+		linphone_core_invite_address_with_params_2(marie.getLc(), confAddr, new_params, NULL, nullptr);
+		linphone_call_params_unref(new_params);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallOutgoingInit,
+		                             marie_stat.number_of_LinphoneCallOutgoingInit + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallError,
+		                             marie_stat.number_of_LinphoneCallError + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased,
+		                             marie_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_conference_base(time_t start_time,
+                                   int duration,
+                                   bool_t uninvited_participant_dials,
+                                   LinphoneConferenceParticipantListType participant_list_type,
+                                   bool_t remove_participant,
+                                   const LinphoneMediaEncryption encryption,
+                                   bool_t enable_video,
+                                   LinphoneConferenceLayout layout,
+                                   bool_t enable_ice,
+                                   bool_t enable_stun,
+                                   bool_t audio_only_participant,
+                                   bool_t server_restart,
+                                   bool_t client_restart,
+                                   bool_t do_not_use_proxy,
+                                   LinphoneMediaDirection video_direction,
+                                   bool_t network_restart) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(berthe);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                 berthe.getCMgr()}) {
+			if (enable_video) {
+				if ((audio_only_participant == FALSE) || (mgr != pauline.getCMgr())) {
+					LinphoneVideoActivationPolicy *pol =
+					    linphone_factory_create_video_activation_policy(linphone_factory_get());
+					linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+					linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+					linphone_core_set_video_activation_policy(mgr->lc, pol);
+					linphone_video_activation_policy_unref(pol);
+				}
+
+				linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+				linphone_core_enable_video_capture(mgr->lc, TRUE);
+				linphone_core_enable_video_display(mgr->lc, TRUE);
+
+				if (layout == LinphoneConferenceLayoutGrid) {
+					linphone_core_set_preferred_video_definition_by_name(mgr->lc, "720p");
+					linphone_config_set_string(linphone_core_get_config(mgr->lc), "video", "max_conference_size",
+					                           "vga");
+				}
+			}
+
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, layout);
+				linphone_core_set_media_encryption(mgr->lc, encryption);
+			}
+
+			if (do_not_use_proxy) {
+				linphone_core_set_default_proxy_config(mgr->lc, NULL);
+			}
+
+			enable_stun_in_core(mgr, enable_stun, enable_ice);
+			linphone_core_manager_wait_for_stun_resolution(mgr);
+
+			linphone_config_set_int(linphone_core_get_config(mgr->lc), "sip", "update_call_when_ice_completed", TRUE);
+			linphone_config_set_int(linphone_core_get_config(mgr->lc), "sip",
+			                        "update_call_when_ice_completed_with_dtls", FALSE);
+
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+		linphone_core_set_conference_participant_list_type(focus.getLc(), participant_list_type);
+
+		stats focus_stat = focus.getStats();
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
+		std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(),
+		                                                laure.getCMgr()};
+		std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()};
+
+		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
+		const char *description = "Paris Baker";
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleListener;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+		char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		if (server_restart) {
+			coresList = bctbx_list_remove(coresList, focus.getLc());
+
+			ms_message("%s is restarting its core", linphone_core_get_identity(focus.getLc()));
+			// Restart flexisip
+			focus.reStart();
+
+			if (enable_video) {
+				LinphoneVideoActivationPolicy *pol =
+				    linphone_factory_create_video_activation_policy(linphone_factory_get());
+				linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+				linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+				linphone_core_set_video_activation_policy(focus.getLc(), pol);
+				linphone_video_activation_policy_unref(pol);
+
+				linphone_core_enable_video_capture(focus.getLc(), TRUE);
+				linphone_core_enable_video_display(focus.getLc(), TRUE);
+			}
+
+			linphone_core_set_conference_participant_list_type(focus.getLc(), participant_list_type);
+			linphone_core_set_default_conference_layout(focus.getLc(), layout);
+			coresList = bctbx_list_append(coresList, focus.getLc());
+		}
+
+		for (auto mgr : members) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			linphone_call_params_set_media_encryption(new_params, encryption);
+			linphone_call_params_set_video_direction(new_params, video_direction);
+			if (mgr == laure.getCMgr()) {
+				linphone_call_params_enable_mic(new_params, FALSE);
+			}
+			linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+		}
+
+		int idx = 1;
+		for (auto mgr : members) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			int no_streams_running =
+			    ((enable_ice && ((audio_only_participant == FALSE) || (mgr != pauline.getCMgr()))) ? 3 : 2);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, (no_streams_running - 1),
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, no_streams_running,
+			                             liblinphone_tester_sip_timeout));
+			// Update to add to conference.
+			// If ICE is enabled, the addition to a conference may go through a resume of the call
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+			                             ((mgr == marie.getCMgr()) ? 3 : 2), liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, 5000));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+
+			if ((encryption == LinphoneMediaEncryptionDTLS) || (encryption == LinphoneMediaEncryptionZRTP)) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEncryptedOn, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEncryptedOn, idx,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pcall);
+			if (pcall) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+				const LinphoneMediaEncryption pcall_enc = linphone_call_params_get_media_encryption(call_cparams);
+				BC_ASSERT_EQUAL(pcall_enc, encryption, int, "%d");
+			}
+			LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(ccall);
+			if (ccall) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+				const LinphoneMediaEncryption ccall_enc = linphone_call_params_get_media_encryption(call_cparams);
+				BC_ASSERT_EQUAL(ccall_enc, encryption, int, "%d");
+			}
+
+			idx++;
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 3,
+		                             liblinphone_tester_sip_timeout));
+		int focus_no_streams_running = ((enable_ice) ? 9 : 6);
+		// Update to end ICE negotiations
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + (focus_no_streams_running - 3),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running,
+		                             liblinphone_tester_sip_timeout));
+		// Update to add to conference.
+		// If ICE is enabled, the addition to a conference may go through a resume of the call
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 3, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + 3, 5000));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + 3, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + 3,
+		                             liblinphone_tester_sip_timeout));
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : members) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
+		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
+		                            memberList, confAddr, enable_video);
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		for (auto mgr : conferenceMgrs) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference);
+				int no_participants = 0;
+				if (start_time >= 0) {
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+					                (long long)start_time, long long, "%lld");
+				}
+				BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+				                (long long)end_time, long long, "%lld");
+
+				bctbx_list_t *participant_device_list = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(participant_device_list), members.size(), size_t, "%zu");
+				for (bctbx_list_t *d_it = participant_device_list; d_it; d_it = bctbx_list_next(d_it)) {
+					LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(d_it);
+					BC_ASSERT_PTR_NOT_NULL(d);
+					if (d) {
+						BC_ASSERT_TRUE((!!linphone_participant_device_get_is_muted(d)) ==
+						               (linphone_address_weak_equal(linphone_participant_device_get_address(d),
+						                                            laure.getCMgr()->identity)));
+						linphone_participant_device_set_user_data(d, mgr->lc);
+						LinphoneParticipantDeviceCbs *cbs =
+						    linphone_factory_create_participant_device_cbs(linphone_factory_get());
+						linphone_participant_device_cbs_set_is_muted(cbs, on_muted_notified);
+						linphone_participant_device_add_callbacks(d, cbs);
+						linphone_participant_device_cbs_unref(cbs);
+					}
+				}
+				bctbx_list_free_with_data(participant_device_list, (void (*)(void *))linphone_participant_device_unref);
+
+				if (mgr == focus.getCMgr()) {
+					no_participants = static_cast<int>(members.size());
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = static_cast<int>(members.size() - 1);
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+					if (enable_ice) {
+						if (video_direction == LinphoneMediaDirectionSendRecv) {
+							BC_ASSERT_TRUE(check_ice(mgr, focus.getCMgr(), LinphoneIceStateHostConnection));
+						} else {
+							LinphoneCall *c1, *c2;
+							MSTimeSpec ts;
+
+							c1 = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+							c2 = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+							BC_ASSERT_TRUE(linphone_call_get_microphone_muted(c1) == (mgr == laure.getCMgr()));
+
+							BC_ASSERT_PTR_NOT_NULL(c1);
+							BC_ASSERT_PTR_NOT_NULL(c2);
+							if (!c1 || !c2) {
+								BC_ASSERT_EQUAL(
+								    linphone_call_params_video_enabled(linphone_call_get_current_params(c1)),
+								    linphone_call_params_video_enabled(linphone_call_get_current_params(c2)), int,
+								    "%d");
+								BC_ASSERT_EQUAL(
+								    linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(c1)),
+								    linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(c2)),
+								    int, "%d");
+								bool_t audio_enabled =
+								    linphone_call_params_audio_enabled(linphone_call_get_current_params(c1));
+								if (audio_enabled) {
+									liblinphone_tester_clock_start(&ts);
+									LinphoneCallStats *stats1 = NULL;
+									LinphoneCallStats *stats2 = NULL;
+									do {
+										if ((c1 != NULL) && (c2 != NULL)) {
+											stats1 = linphone_call_get_audio_stats(c1);
+											stats2 = linphone_call_get_audio_stats(c2);
+											if (linphone_call_stats_get_ice_state(stats1) ==
+											        LinphoneIceStateHostConnection &&
+											    linphone_call_stats_get_ice_state(stats2) ==
+											        LinphoneIceStateHostConnection) {
+												break;
+											}
+											linphone_core_iterate(mgr->lc);
+											linphone_core_iterate(focus.getLc());
+											linphone_call_stats_unref(stats1);
+											linphone_call_stats_unref(stats2);
+											stats1 = stats2 = NULL;
+										}
+										ms_usleep(20000);
+									} while (!liblinphone_tester_clock_elapsed(&ts, liblinphone_tester_sip_timeout));
+									if (stats1) linphone_call_stats_unref(stats1);
+									if (stats2) linphone_call_stats_unref(stats2);
+								}
+							}
+						}
+					}
+
+					LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(mgr->lc);
+					bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+					linphone_video_activation_policy_unref(pol);
+
+					int no_streams_audio = 1;
+					int no_streams_video = (enabled) ? 4 : 0;
+					int no_active_streams_video = 0;
+					int no_streams_text = 0;
+
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						no_active_streams_video =
+						    static_cast<int>(compute_no_video_streams(enabled, pcall, pconference));
+						if (!enable_ice) {
+							_linphone_call_check_max_nb_streams(pcall, no_streams_audio, no_streams_video,
+							                                    no_streams_text);
+						}
+						_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams),
+						                enabled && (no_active_streams_video > 0), int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams),
+						                enabled && (no_active_streams_video > 0), int, "%0d");
+
+						if (enabled && layout == LinphoneConferenceLayoutGrid &&
+						    video_direction == LinphoneMediaDirectionSendRecv) {
+							MSVideoSize vsize = linphone_call_params_get_sent_video_size(call_cparams);
+							BC_ASSERT_EQUAL(vsize.width, 640, int, "%d");
+							BC_ASSERT_EQUAL(vsize.height, 480, int, "%d");
+						}
+					}
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_active_streams_video,
+						                                       no_streams_text);
+						if (!enable_ice) {
+							_linphone_call_check_max_nb_streams(ccall, no_streams_audio, no_streams_video,
+							                                    no_streams_text);
+							const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+							const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						}
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams),
+						                enabled && (no_active_streams_video > 0), int, "%0d");
+					}
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+			}
+		}
+
+		ms_message("Marie mutes its microphone");
+		LinphoneConference *marie_conference = linphone_core_search_conference_2(marie.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(marie_conference);
+		if (marie_conference) {
+			linphone_conference_mute_microphone(marie_conference, TRUE);
+		}
+
+		for (auto mgr : conferenceMgrs) {
+			if (mgr != marie.getCMgr()) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneParticipantDeviceMuted, 1, 5000));
+			}
+			if (mgr != focus.getCMgr()) {
+				LinphoneCall *c1 = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+				BC_ASSERT_TRUE(linphone_call_get_microphone_muted(c1) ==
+				               ((mgr == laure.getCMgr()) || (mgr == marie.getCMgr())));
+			}
+
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+
+			bctbx_list_t *participant_device_list = linphone_conference_get_participant_device_list(pconference);
+			for (bctbx_list_t *d_it = participant_device_list; d_it; d_it = bctbx_list_next(d_it)) {
+				LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(d_it);
+				BC_ASSERT_PTR_NOT_NULL(d);
+				if (d) {
+					BC_ASSERT_TRUE((!!linphone_participant_device_get_is_muted(d)) ==
+					               ((linphone_address_weak_equal(linphone_participant_device_get_address(d),
+					                                             laure.getCMgr()->identity)) ||
+					                (linphone_address_weak_equal(linphone_participant_device_get_address(d),
+					                                             marie.getCMgr()->identity))));
+				}
+			}
+			bctbx_list_free_with_data(participant_device_list, (void (*)(void *))linphone_participant_device_unref);
+		}
+
+		if (client_restart) {
+			ms_message("Marie restarts its core");
+			coresList = bctbx_list_remove(coresList, marie.getLc());
+			// Restart flexisip
+			marie.reStart();
+
+			if (enable_video) {
+				LinphoneVideoActivationPolicy *pol =
+				    linphone_factory_create_video_activation_policy(linphone_factory_get());
+				linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+				linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+				linphone_core_set_video_activation_policy(marie.getLc(), pol);
+				linphone_video_activation_policy_unref(pol);
+
+				linphone_core_enable_video_capture(marie.getLc(), TRUE);
+				linphone_core_enable_video_display(marie.getLc(), TRUE);
+			}
+
+			linphone_core_set_default_conference_layout(marie.getLc(), layout);
+			coresList = bctbx_list_append(coresList, marie.getLc());
+
+			stats focus_stat2 = focus.getStats();
+			stats marie_stat2 = marie.getStats();
+
+			LinphoneCallParams *new_params = linphone_core_create_call_params(marie.getLc(), nullptr);
+			linphone_call_params_set_media_encryption(new_params, encryption);
+			linphone_core_invite_address_with_params_2(marie.getLc(), confAddr, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallOutgoingProgress,
+			                             marie_stat2.number_of_LinphoneCallOutgoingProgress + 1,
+			                             liblinphone_tester_sip_timeout));
+			int no_streams_running = ((enable_ice) ? 3 : 2);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+			                             marie_stat2.number_of_LinphoneCallUpdating + (no_streams_running - 1),
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+			                             marie_stat2.number_of_LinphoneCallStreamsRunning + no_streams_running,
+			                             liblinphone_tester_sip_timeout));
+			// Update to add to conference.
+			// If ICE is enabled, the addition to a conference may go through a resume of the call
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+			                             marie_stat2.number_of_LinphoneConferenceStateCreated + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+			                             marie_stat2.number_of_LinphoneSubscriptionOutgoingProgress + 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+			                             marie_stat2.number_of_LinphoneSubscriptionActive + 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_NotifyReceived,
+			                             marie_stat2.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+			                             focus_stat2.number_of_LinphoneCallIncomingReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			int focus_no_streams_running2 = ((enable_ice) ? 2 : 1);
+			// Update to end ICE negotiations
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+			                  focus_stat2.number_of_LinphoneCallUpdatedByRemote + (focus_no_streams_running2 - 1),
+			                  liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat2.number_of_LinphoneCallStreamsRunning + focus_no_streams_running2,
+			                             liblinphone_tester_sip_timeout));
+
+			if ((encryption == LinphoneMediaEncryptionDTLS) || (encryption == LinphoneMediaEncryptionZRTP)) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEncryptedOn,
+				                             marie_stat2.number_of_LinphoneCallEncryptedOn + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEncryptedOn,
+				                             focus_stat2.number_of_LinphoneCallEncryptedOn + 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(marie.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pcall);
+			if (pcall) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+				const LinphoneMediaEncryption pcall_enc = linphone_call_params_get_media_encryption(call_cparams);
+				BC_ASSERT_EQUAL(pcall_enc, encryption, int, "%d");
+			}
+			LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), marie.getCMgr()->identity);
+			BC_ASSERT_PTR_NOT_NULL(ccall);
+			if (ccall) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+				const LinphoneMediaEncryption ccall_enc = linphone_call_params_get_media_encryption(call_cparams);
+				BC_ASSERT_EQUAL(ccall_enc, encryption, int, "%d");
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+			                             focus_stat2.number_of_LinphoneSubscriptionIncomingReceived + 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+			                             focus_stat2.number_of_LinphoneSubscriptionActive + 1, 5000));
+
+			// wait bit more to detect side effect if any
+			CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+				return false;
+			});
+
+			for (auto mgr : conferenceMgrs) {
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				linphone_address_unref(uri);
+				BC_ASSERT_PTR_NOT_NULL(pconference);
+				if (pconference) {
+					const LinphoneConferenceParams *conference_params =
+					    linphone_conference_get_current_params(pconference);
+					int no_participants = 0;
+					if (start_time >= 0) {
+						BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+						                (long long)start_time, long long, "%lld");
+					}
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+					                (long long)end_time, long long, "%lld");
+
+					bctbx_list_t *participant_device_list =
+					    linphone_conference_get_participant_device_list(pconference);
+					for (bctbx_list_t *d_it = participant_device_list; d_it; d_it = bctbx_list_next(d_it)) {
+						LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(d_it);
+						BC_ASSERT_PTR_NOT_NULL(d);
+						if (d) {
+							BC_ASSERT_TRUE((!!linphone_participant_device_get_is_muted(d)) ==
+							               (linphone_address_weak_equal(linphone_participant_device_get_address(d),
+							                                            laure.getCMgr()->identity)));
+						}
+					}
+					bctbx_list_free_with_data(participant_device_list,
+					                          (void (*)(void *))linphone_participant_device_unref);
+
+					if (mgr == focus.getCMgr()) {
+						no_participants = static_cast<int>(members.size());
+						BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+					} else {
+
+						no_participants = static_cast<int>(members.size() - 1);
+						BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+						LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+						BC_ASSERT_PTR_NOT_NULL(current_call);
+						if (current_call) {
+							BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+							                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+						}
+						if (enable_ice) {
+							BC_ASSERT_TRUE(check_ice(mgr, focus.getCMgr(), LinphoneIceStateHostConnection));
+						}
+
+						LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(mgr->lc);
+						bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+						linphone_video_activation_policy_unref(pol);
+
+						int no_streams_audio = 1;
+						int no_streams_video = (enabled) ? 4 : 0;
+						int no_active_streams_video = 0;
+						int no_streams_text = 0;
+
+						LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+						BC_ASSERT_PTR_NOT_NULL(pcall);
+						if (pcall) {
+							no_active_streams_video =
+							    static_cast<int>(compute_no_video_streams(enabled, pcall, pconference));
+							_linphone_call_check_max_nb_streams(pcall, no_streams_audio, no_streams_video,
+							                                    no_streams_text);
+							_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
+							                                       no_streams_text);
+							const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+							const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+							const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+						}
+						LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+						BC_ASSERT_PTR_NOT_NULL(ccall);
+						if (ccall) {
+							_linphone_call_check_max_nb_streams(ccall, no_streams_audio, no_streams_video,
+							                                    no_streams_text);
+							_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_active_streams_video,
+							                                       no_streams_text);
+							const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+							const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+							const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+						}
+					}
+					BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int,
+					                "%0d");
+					bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+					BC_ASSERT_EQUAL(bctbx_list_size(devices), 3, size_t, "%zu");
+					if (devices) {
+						bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+					}
+					BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+					LinphoneParticipant *me = linphone_conference_get_me(pconference);
+					BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+					               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+					BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+					bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+					for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+						LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+						BC_ASSERT_TRUE(linphone_participant_is_admin(p) ==
+						               linphone_address_weak_equal(linphone_participant_get_address(p),
+						                                           marie.getCMgr()->identity));
+					}
+					bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+					if (mgr != focus.getCMgr()) {
+						check_conference_ssrc(fconference, pconference);
+					}
+				}
+			}
+		}
+
+		// Wait a little bit
+		wait_for_list(coresList, NULL, 0, 3000);
+
+		if (network_restart) {
+			ms_message("Marie toggles its network");
+			stats focus_stat2 = focus.getStats();
+			stats marie_stat = marie.getStats();
+			linphone_core_set_network_reachable(marie.getLc(), FALSE);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionTerminated,
+			                             marie_stat.number_of_LinphoneSubscriptionTerminated + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			// Wait a little bit
+			wait_for_list(coresList, NULL, 0, 1000);
+
+			linphone_core_set_network_reachable(marie.getLc(), TRUE);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+			                             marie_stat.number_of_LinphoneSubscriptionOutgoingProgress + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+			                             focus_stat2.number_of_LinphoneSubscriptionIncomingReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+			                             marie_stat.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+			                             focus_stat2.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		if (enable_video) {
+			LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pauline_call);
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pauline_call);
+
+			Address paulineAddr = pauline.getIdentity();
+			LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineAddr.toC());
+			BC_ASSERT_PTR_NOT_NULL(focus_call);
+
+			LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(pauline.getLc());
+			bool_t enable = !(!!linphone_video_activation_policy_get_automatically_initiate(pol) &&
+			                  linphone_call_params_video_enabled(call_cparams));
+			linphone_video_activation_policy_unref(pol);
+
+			LinphoneAddress *paulineUri = linphone_address_new(linphone_core_get_identity(pauline.getLc()));
+			LinphoneConference *paulineConference =
+			    linphone_core_search_conference(pauline.getLc(), NULL, paulineUri, confAddr, NULL);
+			linphone_address_unref(paulineUri);
+			BC_ASSERT_PTR_NOT_NULL(paulineConference);
+
+			for (int i = 0; i < 4; i++) {
+				stats focus_stat2 = focus.getStats();
+				stats marie_stat2 = marie.getStats();
+				stats pauline_stat2 = pauline.getStats();
+				stats laure_stat2 = laure.getStats();
+
+				LinphoneMediaDirection new_video_direction = video_direction;
+				if ((video_direction == LinphoneMediaDirectionRecvOnly) && (layout == LinphoneConferenceLayoutGrid)) {
+					new_video_direction = LinphoneMediaDirectionSendRecv;
+				}
+
+				ms_message("%s %s video with direction %s", linphone_core_get_identity(pauline.getLc()),
+				           (enable ? "enables" : "disables"), linphone_media_direction_to_string(new_video_direction));
+
+				if (pauline_call) {
+					LinphoneCallParams *new_params = linphone_core_create_call_params(pauline.getLc(), pauline_call);
+					linphone_call_params_enable_video(new_params, enable);
+					linphone_call_params_set_video_direction(new_params, new_video_direction);
+					linphone_call_update(pauline_call, new_params);
+					linphone_call_params_unref(new_params);
+				}
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallUpdating,
+				                             pauline_stat2.number_of_LinphoneCallUpdating + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+				                             pauline_stat2.number_of_LinphoneCallStreamsRunning + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+				                             focus_stat2.number_of_LinphoneCallUpdatedByRemote + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+				                             focus_stat2.number_of_LinphoneCallStreamsRunning + 1,
+				                             liblinphone_tester_sip_timeout));
+
+				if (new_video_direction == LinphoneMediaDirectionSendRecv) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+					                             marie_stat2.number_of_LinphoneCallUpdating + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+					                             marie_stat2.number_of_LinphoneCallStreamsRunning + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallUpdating,
+					                             laure_stat2.number_of_LinphoneCallUpdating + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallStreamsRunning,
+					                             laure_stat2.number_of_LinphoneCallStreamsRunning + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+					                             focus_stat2.number_of_LinphoneCallUpdatedByRemote + 3,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+					                             focus_stat2.number_of_LinphoneCallStreamsRunning + 3,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				BC_ASSERT_TRUE(wait_for_list(coresList,
+				                             &focus.getStats().number_of_participant_devices_media_capability_changed,
+				                             focus_stat2.number_of_participant_devices_media_capability_changed + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList,
+				                             &marie.getStats().number_of_participant_devices_media_capability_changed,
+				                             marie_stat2.number_of_participant_devices_media_capability_changed + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList,
+				                             &pauline.getStats().number_of_participant_devices_media_capability_changed,
+				                             pauline_stat2.number_of_participant_devices_media_capability_changed + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList,
+				                             &laure.getStats().number_of_participant_devices_media_capability_changed,
+				                             laure_stat2.number_of_participant_devices_media_capability_changed + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_EQUAL(focus.getStats().number_of_participants_added, focus_stat2.number_of_participants_added,
+				                int, "%0d");
+				BC_ASSERT_EQUAL(focus.getStats().number_of_participant_devices_added,
+				                focus_stat2.number_of_participant_devices_added, int, "%0d");
+				BC_ASSERT_EQUAL(focus.getStats().number_of_participant_devices_joined,
+				                focus_stat2.number_of_participant_devices_joined, int, "%0d");
+				BC_ASSERT_EQUAL(marie.getStats().number_of_participants_added, marie_stat2.number_of_participants_added,
+				                int, "%0d");
+				BC_ASSERT_EQUAL(marie.getStats().number_of_participant_devices_added,
+				                marie_stat2.number_of_participant_devices_added, int, "%0d");
+				BC_ASSERT_EQUAL(marie.getStats().number_of_participant_devices_joined,
+				                marie_stat2.number_of_participant_devices_joined, int, "%0d");
+				BC_ASSERT_EQUAL(pauline.getStats().number_of_participants_added,
+				                pauline_stat2.number_of_participants_added, int, "%0d");
+				BC_ASSERT_EQUAL(pauline.getStats().number_of_participant_devices_added,
+				                pauline_stat2.number_of_participant_devices_added, int, "%0d");
+				BC_ASSERT_EQUAL(pauline.getStats().number_of_participant_devices_joined,
+				                pauline_stat2.number_of_participant_devices_joined, int, "%0d");
+				BC_ASSERT_EQUAL(laure.getStats().number_of_participants_added, laure_stat2.number_of_participants_added,
+				                int, "%0d");
+				BC_ASSERT_EQUAL(laure.getStats().number_of_participant_devices_added,
+				                laure_stat2.number_of_participant_devices_added, int, "%0d");
+				BC_ASSERT_EQUAL(laure.getStats().number_of_participant_devices_joined,
+				                laure_stat2.number_of_participant_devices_joined, int, "%0d");
+
+				for (auto mgr : conferenceMgrs) {
+					LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+					LinphoneConference *pconference =
+					    linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+					linphone_address_unref(uri);
+					BC_ASSERT_PTR_NOT_NULL(pconference);
+					if (pconference) {
+						LinphoneParticipant *p =
+						    (mgr == pauline.getCMgr())
+						        ? linphone_conference_get_me(pconference)
+						        : linphone_conference_find_participant(pconference, pauline.getCMgr()->identity);
+						BC_ASSERT_PTR_NOT_NULL(p);
+						if (p) {
+							bctbx_list_t *devices = linphone_participant_get_devices(p);
+							for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+								LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+								LinphoneMediaDirection expected_video_direction = video_direction;
+								if (enable == TRUE) {
+									if ((video_direction == LinphoneMediaDirectionRecvOnly) &&
+									    (layout == LinphoneConferenceLayoutGrid)) {
+										expected_video_direction = LinphoneMediaDirectionSendOnly;
+									} else {
+										expected_video_direction = video_direction;
+									}
+								} else {
+									expected_video_direction = LinphoneMediaDirectionInactive;
+								}
+								BC_ASSERT_EQUAL(
+								    linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo),
+								    expected_video_direction, int, "%0d");
+							}
+							if (devices) {
+								bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+							}
+						}
+					}
+				}
+
+				if (pauline_call) {
+					const LinphoneCallParams *call_lparams = linphone_call_get_params(pauline_call);
+					BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enable, int, "%0d");
+					const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pauline_call);
+					BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enable, int, "%0d");
+					const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pauline_call);
+					BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enable, int, "%0d");
+				}
+				if (focus_call) {
+					const LinphoneCallParams *call_lparams = linphone_call_get_params(focus_call);
+					BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enable, int, "%0d");
+					const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(focus_call);
+					BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enable, int, "%0d");
+					const LinphoneCallParams *call_cparams = linphone_call_get_current_params(focus_call);
+					BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enable, int, "%0d");
+				}
+
+				if (paulineConference) {
+					bctbx_list_t *devices = linphone_conference_get_participant_device_list(paulineConference);
+					for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+						LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+						if (enable) {
+							if (linphone_conference_is_me(paulineConference,
+							                              linphone_participant_device_get_address(d))) {
+								BC_ASSERT_TRUE(
+								    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) ==
+								    (new_video_direction == LinphoneMediaDirectionSendRecv));
+							} else {
+								BC_ASSERT_TRUE(
+								    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) ==
+								    (linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+								     LinphoneMediaDirectionSendRecv));
+							}
+						} else {
+							BC_ASSERT_FALSE(
+							    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+						}
+					}
+
+					if (devices) {
+						bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+					}
+
+					stats focus_stat3 = focus.getStats();
+					stats marie_stat3 = marie.getStats();
+					stats pauline_stat3 = pauline.getStats();
+					stats laure_stat3 = laure.getStats();
+
+					LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pauline_call);
+
+					bool_t video_enabled = FALSE;
+					if (pauline_call) {
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pauline_call);
+						video_enabled = linphone_call_params_video_enabled(call_cparams);
+					}
+
+					linphone_conference_leave(paulineConference);
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallPausing,
+					                             pauline_stat3.number_of_LinphoneCallPausing + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallPaused,
+					                             pauline_stat3.number_of_LinphoneCallPaused + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallPausedByRemote,
+					                             focus_stat3.number_of_LinphoneCallPausedByRemote + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_on_hold,
+					                             focus_stat3.number_of_participant_devices_on_hold + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_on_hold,
+					                             laure_stat3.number_of_participant_devices_on_hold + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(
+					    coresList, &laure.getStats().number_of_participant_devices_media_capability_changed,
+					    laure_stat3.number_of_participant_devices_media_capability_changed + 1,
+					    liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_on_hold,
+					                             marie_stat3.number_of_participant_devices_on_hold + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(
+					    coresList, &marie.getStats().number_of_participant_devices_media_capability_changed,
+					    marie_stat3.number_of_participant_devices_media_capability_changed + 1,
+					    liblinphone_tester_sip_timeout));
+
+					for (auto mgr : conferenceMgrs) {
+						LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+						LinphoneConference *pconference =
+						    linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+						linphone_address_unref(uri);
+						BC_ASSERT_PTR_NOT_NULL(pconference);
+						if (pconference) {
+							if (mgr == pauline.getCMgr()) {
+								BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+							} else {
+								LinphoneParticipant *participant =
+								    linphone_conference_find_participant(pconference, pauline.getCMgr()->identity);
+								BC_ASSERT_PTR_NOT_NULL(participant);
+								if (participant) {
+									bctbx_list_t *devices = linphone_participant_get_devices(participant);
+									for (bctbx_list_t *it_d = devices; it_d != NULL; it_d = it_d->next) {
+										LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)it_d->data;
+										BC_ASSERT_PTR_NOT_NULL(d);
+										if (d) {
+											BC_ASSERT_EQUAL(linphone_participant_device_get_state(d),
+											                LinphoneParticipantDeviceStateOnHold, int, "%0d");
+										}
+									}
+									bctbx_list_free_with_data(devices,
+									                          (void (*)(void *))linphone_participant_device_unref);
+								}
+							}
+						}
+					}
+
+					linphone_conference_enter(paulineConference);
+
+					int participant_streams_running = 0;
+					int pauline_streams_running = 0;
+					int focus_streams_running = 0;
+					if (video_direction == LinphoneMediaDirectionRecvOnly) {
+						if (layout == LinphoneConferenceLayoutGrid) {
+							/*
+							 * If the participant video direction is set to RecvOnly, the conference server will see
+							 * it as if everybody had disabled the video streams. The test explicitely changes
+							 * Pauline's video direction to SendRecv to trigger events such as media capability and
+							 * availability changed Leaving and rejoining a conference, therefore, triggers media
+							 * events on participant devices only when Pauline enables video capabilities with
+							 * direction SendRecv
+							 */
+							if (enable) {
+								participant_streams_running = 1;
+								focus_streams_running = static_cast<int>(members.size() + 1);
+								pauline_streams_running = 2;
+							} else {
+								focus_streams_running = 1;
+								pauline_streams_running = 1;
+							}
+						} else if (layout == LinphoneConferenceLayoutActiveSpeaker) {
+							focus_streams_running = 1;
+							pauline_streams_running = 1;
+						}
+					} else {
+						participant_streams_running = ((enable) ? 1 : 0);
+						focus_streams_running = static_cast<int>((enable) ? (members.size() + 1) : 1);
+						pauline_streams_running = ((enable) ? 2 : 1);
+					}
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallResuming,
+					                             pauline_stat3.number_of_LinphoneCallResuming + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(
+					    wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+					                  (pauline_stat3.number_of_LinphoneCallStreamsRunning + pauline_streams_running),
+					                  liblinphone_tester_sip_timeout));
+					// 2 streams running for Pauline and one for each participant
+					BC_ASSERT_TRUE(
+					    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+					                  focus_stat3.number_of_LinphoneCallStreamsRunning + focus_streams_running,
+					                  liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+					                             focus_stat3.number_of_participant_devices_joined + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_joined,
+					                             laure_stat3.number_of_participant_devices_joined + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(
+					    coresList, &laure.getStats().number_of_participant_devices_media_capability_changed,
+					    laure_stat3.number_of_participant_devices_media_capability_changed + 2,
+					    liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(
+					    wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallStreamsRunning,
+					                  laure_stat3.number_of_LinphoneCallStreamsRunning + participant_streams_running,
+					                  liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_joined,
+					                             marie_stat3.number_of_participant_devices_joined + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(
+					    coresList, &marie.getStats().number_of_participant_devices_media_capability_changed,
+					    marie_stat3.number_of_participant_devices_media_capability_changed + 2,
+					    liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(
+					    wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+					                  marie_stat3.number_of_LinphoneCallStreamsRunning + participant_streams_running,
+					                  liblinphone_tester_sip_timeout));
+					if (pauline_call) {
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pauline_call);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), video_enabled, int, "%0d");
+					}
+
+					for (auto mgr : conferenceMgrs) {
+						LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+						LinphoneConference *pconference =
+						    linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+						linphone_address_unref(uri);
+						BC_ASSERT_PTR_NOT_NULL(pconference);
+						if (pconference) {
+							if (mgr == pauline.getCMgr()) {
+								BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+							} else {
+								LinphoneParticipant *participant =
+								    linphone_conference_find_participant(pconference, pauline.getCMgr()->identity);
+								BC_ASSERT_PTR_NOT_NULL(participant);
+								if (participant) {
+									bctbx_list_t *devices = linphone_participant_get_devices(participant);
+									for (bctbx_list_t *it_d = devices; it_d != NULL; it_d = it_d->next) {
+										LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)it_d->data;
+										BC_ASSERT_PTR_NOT_NULL(d);
+										if (d) {
+											BC_ASSERT_EQUAL(linphone_participant_device_get_state(d),
+											                LinphoneParticipantDeviceStatePresent, int, "%0d");
+										}
+									}
+									bctbx_list_free_with_data(devices,
+									                          (void (*)(void *))linphone_participant_device_unref);
+								}
+							}
+						}
+					}
+				}
+				// Wait a little bit
+				wait_for_list(coresList, NULL, 0, 1000);
+
+				enable = !enable;
+			}
+		}
+
+		std::list<LinphoneCoreManager *> extraParticipantMgrs;
+		int no_local_participants = 3;
+		if (uninvited_participant_dials) {
+			stats marie_stat2 = marie.getStats();
+			stats focus_stat2 = focus.getStats();
+			stats pauline_stat2 = pauline.getStats();
+			stats laure_stat2 = laure.getStats();
+
+			extraParticipantMgrs.push_back(michelle.getCMgr());
+
+			ms_message("%s is entering conference %s", linphone_core_get_identity(michelle.getLc()),
+			           conference_address_str);
+
+			LinphoneCallParams *params = linphone_core_create_call_params(michelle.getLc(), nullptr);
+			LinphoneCall *michelle_call = linphone_core_invite_address_with_params(michelle.getLc(), confAddr, params);
+			BC_ASSERT_PTR_NOT_NULL(michelle_call);
+			linphone_call_params_unref(params);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			int extra_participants = 0;
+			if (participant_list_type == LinphoneConferenceParticipantListTypeOpen) {
+
+				if (network_restart) {
+					ms_message("%s switches off network before %s is added to conference %s",
+					           linphone_core_get_identity(marie.getLc()), linphone_core_get_identity(michelle.getLc()),
+					           conference_address_str);
+					linphone_core_set_network_reachable(marie.getLc(), FALSE);
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionTerminated,
+					                             marie_stat2.number_of_LinphoneSubscriptionTerminated + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				conferenceMgrs.push_back(michelle.getCMgr());
+				members.push_back(michelle.getCMgr());
+
+				extra_participants = 1;
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallStreamsRunning, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallUpdating, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallStreamsRunning, 2,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(
+				    coresList, &michelle.getStats().number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &michelle.getStats().number_of_LinphoneSubscriptionActive, 1, 5000));
+				BC_ASSERT_TRUE(wait_for_list(
+				    coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+				    focus_stat2.number_of_LinphoneSubscriptionIncomingReceived + 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+				                             focus_stat2.number_of_LinphoneSubscriptionActive + 1,
+				                             liblinphone_tester_sip_timeout));
+
+				if (enable_video) {
+					if ((audio_only_participant == FALSE) && ((video_direction != LinphoneMediaDirectionRecvOnly) ||
+					                                          (layout == LinphoneConferenceLayoutActiveSpeaker))) {
+						BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallUpdating,
+						                             pauline_stat2.number_of_LinphoneCallUpdating + 1,
+						                             liblinphone_tester_sip_timeout));
+						BC_ASSERT_TRUE(wait_for_list(
+						    coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+						    pauline_stat2.number_of_LinphoneCallStreamsRunning + 1, liblinphone_tester_sip_timeout));
+					}
+					BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallUpdating,
+					                             laure_stat2.number_of_LinphoneCallUpdating + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallStreamsRunning,
+					                             laure_stat2.number_of_LinphoneCallStreamsRunning + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+				                             focus_stat2.number_of_participants_added + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+				                             focus_stat2.number_of_participant_devices_added + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+				                             focus_stat2.number_of_participant_devices_joined + 1,
+				                             liblinphone_tester_sip_timeout));
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added,
+				                             pauline_stat2.number_of_participants_added + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+				                             pauline_stat2.number_of_participant_devices_added + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_joined,
+				                             pauline_stat2.number_of_participant_devices_joined + 1,
+				                             liblinphone_tester_sip_timeout));
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participants_added,
+				                             laure_stat2.number_of_participants_added + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_added,
+				                             laure_stat2.number_of_participant_devices_added + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_joined,
+				                             laure_stat2.number_of_participant_devices_joined + 1,
+				                             liblinphone_tester_sip_timeout));
+
+				if (network_restart) {
+					ms_message("%s is back online after %s is added to conference %s",
+					           linphone_core_get_identity(marie.getLc()), linphone_core_get_identity(michelle.getLc()),
+					           conference_address_str);
+					linphone_core_set_network_reachable(marie.getLc(), TRUE);
+					BC_ASSERT_TRUE(wait_for_list(coresList,
+					                             &marie.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+					                             marie_stat2.number_of_LinphoneSubscriptionOutgoingProgress + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList,
+					                             &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+					                             focus_stat2.number_of_LinphoneSubscriptionIncomingReceived + 2,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+					                             marie_stat2.number_of_LinphoneSubscriptionActive + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+					                             focus_stat2.number_of_LinphoneSubscriptionActive + 2,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				if (enable_video) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+					                             marie_stat2.number_of_LinphoneCallUpdating + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+					                             marie_stat2.number_of_LinphoneCallStreamsRunning + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_added,
+				                             marie_stat2.number_of_participants_added + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_added,
+				                             marie_stat2.number_of_participant_devices_added + 1,
+				                             liblinphone_tester_sip_timeout));
+				if (!network_restart) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_joined,
+					                             marie_stat2.number_of_participant_devices_joined + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+				for (const auto &member : members) {
+					try {
+						const auto &participantInfo = participantList.at(member);
+						memberList.insert(std::make_pair(member, participantInfo));
+					} catch (std::out_of_range &) {
+						if (member == marie.getCMgr()) {
+							memberList.insert(std::make_pair(member, LinphoneParticipantRoleSpeaker));
+						} else if (member == michelle.getCMgr()) {
+							memberList.insert(std::make_pair(member, LinphoneParticipantRoleListener));
+						} else {
+							ms_fatal("Unable to find active participant %s in the participant list",
+							         linphone_core_get_identity(member->lc));
+						}
+					}
+				}
+				wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs,
+				                            focus.getCMgr(), memberList, confAddr, enable_video);
+			} else if (participant_list_type == LinphoneConferenceParticipantListTypeClosed) {
+				extra_participants = 0;
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallError, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				// wait bit more to detect side effect if any
+				CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+					return false;
+				});
+
+				BC_ASSERT_EQUAL(michelle.getStats().number_of_LinphoneConferenceStateCreated, 0, int, "%0d");
+				BC_ASSERT_EQUAL(michelle.getStats().number_of_LinphoneSubscriptionOutgoingProgress, 0, int, "%0d");
+				BC_ASSERT_EQUAL(michelle.getStats().number_of_LinphoneSubscriptionActive, 0, int, "%0d");
+				BC_ASSERT_EQUAL(focus.getStats().number_of_participants_added, focus_stat2.number_of_participants_added,
+				                int, "%0d");
+				BC_ASSERT_EQUAL(focus.getStats().number_of_participant_devices_added,
+				                focus_stat2.number_of_participant_devices_added, int, "%0d");
+				BC_ASSERT_EQUAL(focus.getStats().number_of_participant_devices_joined,
+				                focus_stat2.number_of_participant_devices_joined, int, "%0d");
+				BC_ASSERT_EQUAL(marie.getStats().number_of_participants_added, marie_stat2.number_of_participants_added,
+				                int, "%0d");
+				BC_ASSERT_EQUAL(marie.getStats().number_of_participant_devices_added,
+				                marie_stat2.number_of_participant_devices_added, int, "%0d");
+				BC_ASSERT_EQUAL(marie.getStats().number_of_participant_devices_joined,
+				                marie_stat2.number_of_participant_devices_joined, int, "%0d");
+				BC_ASSERT_EQUAL(pauline.getStats().number_of_participants_added,
+				                pauline_stat2.number_of_participants_added, int, "%0d");
+				BC_ASSERT_EQUAL(pauline.getStats().number_of_participant_devices_added,
+				                pauline_stat2.number_of_participant_devices_added, int, "%0d");
+				BC_ASSERT_EQUAL(pauline.getStats().number_of_participant_devices_joined,
+				                pauline_stat2.number_of_participant_devices_joined, int, "%0d");
+				BC_ASSERT_EQUAL(laure.getStats().number_of_participants_added, laure_stat2.number_of_participants_added,
+				                int, "%0d");
+				BC_ASSERT_EQUAL(laure.getStats().number_of_participant_devices_added,
+				                laure_stat2.number_of_participant_devices_added, int, "%0d");
+				BC_ASSERT_EQUAL(laure.getStats().number_of_participant_devices_joined,
+				                laure_stat2.number_of_participant_devices_joined, int, "%0d");
+			}
+
+			for (auto mgr : conferenceMgrs) {
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				linphone_address_unref(uri);
+				if (participant_list_type == LinphoneConferenceParticipantListTypeOpen) {
+					BC_ASSERT_PTR_NOT_NULL(pconference);
+				} else if (mgr == michelle.getCMgr()) {
+					BC_ASSERT_PTR_NULL(pconference);
+				}
+				if (pconference) {
+					const LinphoneConferenceParams *conference_params =
+					    linphone_conference_get_current_params(pconference);
+					int no_participants = 0;
+					if (start_time >= 0) {
+						BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+						                (long long)start_time, long long, "%lld");
+					}
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+					                (long long)end_time, long long, "%lld");
+					if (mgr == focus.getCMgr()) {
+						no_participants = no_local_participants + extra_participants;
+						BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+					} else {
+						// Substracting one because we conference server is not in the conference
+						no_participants = (no_local_participants - 1) + extra_participants;
+						BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+
+						LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+						BC_ASSERT_PTR_NOT_NULL(pcall);
+
+						int no_streams_audio = 1;
+						int no_streams_video = 0;
+						int no_active_streams_video = 0;
+						int no_streams_text = 0;
+						if (pcall) {
+							const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+							const bool_t enabled = linphone_call_params_video_enabled(call_cparams);
+							no_streams_video =
+							    (enabled && (participant_list_type == LinphoneConferenceParticipantListTypeOpen)) ? 5
+							    : (enable_video)                                                                  ? 4
+							                                                                                      : 0;
+							no_active_streams_video =
+							    static_cast<int>(compute_no_video_streams(enabled, pcall, pconference));
+							_linphone_call_check_max_nb_streams(pcall, no_streams_audio, no_streams_video,
+							                                    no_streams_text);
+							_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
+							                                       no_streams_text);
+						}
+
+						LinphoneCall *fcall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+						BC_ASSERT_PTR_NOT_NULL(fcall);
+						if (fcall) {
+							_linphone_call_check_max_nb_streams(fcall, no_streams_audio, no_streams_video,
+							                                    no_streams_text);
+							_linphone_call_check_nb_active_streams(fcall, no_streams_audio, no_active_streams_video,
+							                                       no_streams_text);
+						}
+					}
+					BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int,
+					                "%0d");
+					bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+					BC_ASSERT_EQUAL(bctbx_list_size(devices),
+					                static_cast<size_t>(no_local_participants + extra_participants), size_t, "%zu");
+					if (devices) {
+						bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+					}
+					BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				}
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		stats marie_stat = marie.getStats();
+
+		std::list<LinphoneCoreManager *> mgrsToRemove{pauline.getCMgr()};
+		if (remove_participant) {
+			stats pauline_stat = pauline.getStats();
+			stats michelle_stat = michelle.getStats();
+
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(marie.getLc()));
+			LinphoneConference *pconference = linphone_core_search_conference(marie.getLc(), NULL, uri, confAddr, NULL);
+			linphone_address_unref(uri);
+
+			ms_message("%s is removing %s from conference %s", linphone_core_get_identity(marie.getLc()),
+			           linphone_core_get_identity(laure.getLc()), conference_address_str);
+
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			LinphoneAddress *puri = linphone_address_new(linphone_core_get_identity(laure.getLc()));
+			if (pconference) {
+				LinphoneParticipant *participant = linphone_conference_find_participant(pconference, puri);
+				BC_ASSERT_PTR_NOT_NULL(participant);
+				linphone_conference_remove_participant_2(pconference, participant);
+			}
+
+			LinphoneCoreManager *laureMgr = laure.getCMgr();
+			auto itConferenceMgrs = std::find(conferenceMgrs.begin(), conferenceMgrs.end(), laureMgr);
+			if (itConferenceMgrs != conferenceMgrs.end()) {
+				conferenceMgrs.erase(itConferenceMgrs);
+			}
+
+			auto itMembers = std::find(members.begin(), members.end(), laureMgr);
+			if (itMembers != members.end()) {
+				members.erase(itMembers);
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallEnd, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallReleased, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneSubscriptionTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &laure.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+			                             focus_stat.number_of_participants_removed + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+			                             focus_stat.number_of_participant_devices_removed + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+			                             marie_stat.number_of_participants_removed + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+			                             marie_stat.number_of_participant_devices_removed + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_removed,
+			                             pauline_stat.number_of_participants_removed + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_removed,
+			                             pauline_stat.number_of_participant_devices_removed + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			if (enable_video) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+				                             marie_stat.number_of_LinphoneCallUpdating + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+				                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+				                             liblinphone_tester_sip_timeout));
+
+				if ((audio_only_participant == FALSE) && ((video_direction != LinphoneMediaDirectionRecvOnly) ||
+				                                          (layout == LinphoneConferenceLayoutActiveSpeaker))) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallUpdating,
+					                             pauline_stat.number_of_LinphoneCallUpdating + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+					                             pauline_stat.number_of_LinphoneCallStreamsRunning + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+			}
+
+			if ((uninvited_participant_dials) && (participant_list_type == LinphoneConferenceParticipantListTypeOpen)) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_removed,
+				                             michelle_stat.number_of_participants_removed + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_removed,
+				                             michelle_stat.number_of_participant_devices_removed + 1,
+				                             liblinphone_tester_sip_timeout));
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallUpdating,
+				                             michelle_stat.number_of_LinphoneCallUpdating + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallStreamsRunning,
+				                             michelle_stat.number_of_LinphoneCallStreamsRunning + 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			LinphoneConference *conference = linphone_core_search_conference(laure.getLc(), NULL, puri, confAddr, NULL);
+			BC_ASSERT_PTR_NULL(conference);
+			linphone_address_unref(puri);
+
+			no_local_participants = 3;
+			if (uninvited_participant_dials) {
+				stats marie_stat2 = marie.getStats();
+				stats focus_stat2 = focus.getStats();
+				stats pauline_stat2 = pauline.getStats();
+				stats michelle_stat2 = michelle.getStats();
+
+				extraParticipantMgrs.push_back(berthe.getCMgr());
+				conferenceMgrs.push_back(berthe.getCMgr());
+				members.push_back(berthe.getCMgr());
+				ms_message("%s is entering conference %s", linphone_core_get_identity(berthe.getLc()),
+				           conference_address_str);
+
+				LinphoneCallParams *params = linphone_core_create_call_params(berthe.getLc(), nullptr);
+				LinphoneCall *berthe_call = linphone_core_invite_address_with_params(berthe.getLc(), confAddr, params);
+				BC_ASSERT_PTR_NOT_NULL(berthe_call);
+				linphone_call_params_unref(params);
+				BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallOutgoingProgress, 1,
+				                             liblinphone_tester_sip_timeout));
+				int extra_participants = 0;
+				if (participant_list_type == LinphoneConferenceParticipantListTypeOpen) {
+					extra_participants = 1;
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallStreamsRunning, 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallUpdating, 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallStreamsRunning, 2,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneConferenceStateCreated,
+					                             1, liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(
+					    coresList, &berthe.getStats().number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+					BC_ASSERT_TRUE(
+					    wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionActive, 1, 5000));
+
+					if ((audio_only_participant == FALSE) && ((video_direction != LinphoneMediaDirectionRecvOnly) ||
+					                                          (layout == LinphoneConferenceLayoutActiveSpeaker))) {
+						BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallUpdating,
+						                             pauline_stat2.number_of_LinphoneCallUpdating + 1,
+						                             liblinphone_tester_sip_timeout));
+						BC_ASSERT_TRUE(wait_for_list(
+						    coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+						    pauline_stat2.number_of_LinphoneCallStreamsRunning + 1, liblinphone_tester_sip_timeout));
+					}
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+					                             marie_stat2.number_of_LinphoneCallUpdating + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+					                             marie_stat2.number_of_LinphoneCallStreamsRunning + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallUpdating,
+					                             michelle_stat2.number_of_LinphoneCallUpdating + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallStreamsRunning,
+					                             michelle_stat2.number_of_LinphoneCallStreamsRunning + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(
+					    coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+					    focus_stat2.number_of_LinphoneCallUpdatedByRemote + (audio_only_participant) ? 3 : 4,
+					    liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(
+					    coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+					    focus_stat2.number_of_LinphoneCallStreamsRunning + (audio_only_participant) ? 4 : 5,
+					    liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+					                             focus_stat2.number_of_participants_added + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+					                             focus_stat2.number_of_participant_devices_added + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+					                             focus_stat2.number_of_participant_devices_joined + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_added,
+					                             marie_stat2.number_of_participants_added + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_added,
+					                             marie_stat2.number_of_participant_devices_added + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_joined,
+					                             marie_stat2.number_of_participant_devices_joined + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added,
+					                             pauline_stat2.number_of_participants_added + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+					                             pauline_stat2.number_of_participant_devices_added + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_joined,
+					                             pauline_stat2.number_of_participant_devices_joined + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_added,
+					                             michelle_stat2.number_of_participants_added + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_added,
+					                             michelle_stat2.number_of_participant_devices_added + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_joined,
+					                             michelle_stat2.number_of_participant_devices_joined + 1,
+					                             liblinphone_tester_sip_timeout));
+				} else if (participant_list_type == LinphoneConferenceParticipantListTypeClosed) {
+					extra_participants = 0;
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallError, 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallReleased, 1,
+					                             liblinphone_tester_sip_timeout));
+
+					// wait bit more to detect side effect if any
+					CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe})
+					    .waitUntil(chrono::seconds(2), [] { return false; });
+
+					BC_ASSERT_EQUAL(berthe.getStats().number_of_LinphoneConferenceStateCreated, 0, int, "%0d");
+					BC_ASSERT_EQUAL(berthe.getStats().number_of_LinphoneSubscriptionOutgoingProgress, 0, int, "%0d");
+					BC_ASSERT_EQUAL(berthe.getStats().number_of_LinphoneSubscriptionActive, 0, int, "%0d");
+					BC_ASSERT_EQUAL(focus.getStats().number_of_participants_added,
+					                focus_stat2.number_of_participants_added, int, "%0d");
+					BC_ASSERT_EQUAL(focus.getStats().number_of_participant_devices_added,
+					                focus_stat2.number_of_participant_devices_added, int, "%0d");
+					BC_ASSERT_EQUAL(focus.getStats().number_of_participant_devices_joined,
+					                focus_stat2.number_of_participant_devices_joined, int, "%0d");
+					BC_ASSERT_EQUAL(marie.getStats().number_of_participants_added,
+					                marie_stat2.number_of_participants_added, int, "%0d");
+					BC_ASSERT_EQUAL(marie.getStats().number_of_participant_devices_added,
+					                marie_stat2.number_of_participant_devices_added, int, "%0d");
+					BC_ASSERT_EQUAL(marie.getStats().number_of_participant_devices_joined,
+					                marie_stat2.number_of_participant_devices_joined, int, "%0d");
+					BC_ASSERT_EQUAL(pauline.getStats().number_of_participants_added,
+					                pauline_stat2.number_of_participants_added, int, "%0d");
+					BC_ASSERT_EQUAL(pauline.getStats().number_of_participant_devices_added,
+					                pauline_stat2.number_of_participant_devices_added, int, "%0d");
+					BC_ASSERT_EQUAL(pauline.getStats().number_of_participant_devices_joined,
+					                pauline_stat2.number_of_participant_devices_joined, int, "%0d");
+					BC_ASSERT_EQUAL(michelle.getStats().number_of_participants_added,
+					                michelle_stat2.number_of_participants_added, int, "%0d");
+					BC_ASSERT_EQUAL(michelle.getStats().number_of_participant_devices_added,
+					                michelle_stat2.number_of_participant_devices_added, int, "%0d");
+					BC_ASSERT_EQUAL(michelle.getStats().number_of_participant_devices_joined,
+					                michelle_stat2.number_of_participant_devices_joined, int, "%0d");
+				}
+
+				for (auto mgr : conferenceMgrs) {
+					LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+					LinphoneConference *pconference =
+					    linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+					linphone_address_unref(uri);
+					if ((participant_list_type == LinphoneConferenceParticipantListTypeOpen) ||
+					    ((mgr != berthe.getCMgr()) && (mgr != michelle.getCMgr()))) {
+						BC_ASSERT_PTR_NOT_NULL(pconference);
+					} else if ((mgr == berthe.getCMgr()) || (mgr == michelle.getCMgr())) {
+						BC_ASSERT_PTR_NULL(pconference);
+					}
+					if (pconference) {
+						const LinphoneConferenceParams *conference_params =
+						    linphone_conference_get_current_params(pconference);
+						int no_participants = 0;
+						if (start_time >= 0) {
+							BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+							                (long long)start_time, long long, "%lld");
+						}
+						BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+						                (long long)end_time, long long, "%lld");
+						if (mgr == focus.getCMgr()) {
+							no_participants = no_local_participants + extra_participants;
+							BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+						} else {
+							LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+							BC_ASSERT_PTR_NOT_NULL(pcall);
+
+							int no_streams_audio = 1;
+							int no_streams_video = 0;
+							int no_active_streams_video = 0;
+							int no_streams_text = 0;
+							if (pcall) {
+								const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+								const bool_t enabled = linphone_call_params_video_enabled(call_cparams);
+								no_streams_video =
+								    (enabled && (participant_list_type == LinphoneConferenceParticipantListTypeOpen))
+								        ? 5
+								    : (enable_video) ? 4
+								                     : 0;
+								no_active_streams_video =
+								    static_cast<int>(compute_no_video_streams(enabled, pcall, pconference));
+								_linphone_call_check_max_nb_streams(pcall, no_streams_audio, no_streams_video,
+								                                    no_streams_text);
+								_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
+								                                       no_streams_text);
+							}
+
+							LinphoneCall *fcall =
+							    linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+							BC_ASSERT_PTR_NOT_NULL(fcall);
+							if (fcall) {
+								_linphone_call_check_max_nb_streams(fcall, no_streams_audio, no_streams_video,
+								                                    no_streams_text);
+								_linphone_call_check_nb_active_streams(fcall, no_streams_audio, no_active_streams_video,
+								                                       no_streams_text);
+							}
+
+							// Substracting one because we conference server is not in the conference
+							no_participants = (no_local_participants - 1) + extra_participants;
+							BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+						}
+						BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int,
+						                "%0d");
+						bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+						BC_ASSERT_EQUAL(bctbx_list_size(devices),
+						                static_cast<size_t>(no_local_participants + extra_participants), size_t, "%zu");
+						if (devices) {
+							bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+						}
+						BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+					}
+				}
+
+				// wait bit more to detect side effect if any
+				CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+					return false;
+				});
+			}
+
+		} else {
+			mgrsToRemove.push_back(laure.getCMgr());
+		}
+
+		LinphoneAddress *paulineUri = linphone_address_new(linphone_core_get_identity(pauline.getLc()));
+		LinphoneConference *paulineConference =
+		    linphone_core_search_conference(pauline.getLc(), NULL, paulineUri, confAddr, NULL);
+		linphone_address_unref(paulineUri);
+		BC_ASSERT_PTR_NOT_NULL(paulineConference);
+
+		if (paulineConference) {
+			stats focus_stat2 = focus.getStats();
+			stats marie_stat2 = marie.getStats();
+			stats pauline_stat2 = pauline.getStats();
+			stats laure_stat2 = laure.getStats();
+			stats michelle_stat2 = michelle.getStats();
+
+			LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pauline_call);
+
+			bool_t video_enabled = FALSE;
+			if (pauline_call) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pauline_call);
+				video_enabled = linphone_call_params_video_enabled(call_cparams);
+			}
+
+			linphone_conference_leave(paulineConference);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallPausing,
+			                             pauline_stat2.number_of_LinphoneCallPausing + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallPaused,
+			                             pauline_stat2.number_of_LinphoneCallPaused + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallPausedByRemote,
+			                             focus_stat2.number_of_LinphoneCallPausedByRemote + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_on_hold,
+			                             focus_stat2.number_of_participant_devices_on_hold + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			if (!remove_participant) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_on_hold,
+				                             laure_stat2.number_of_participant_devices_on_hold + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList,
+				                             &laure.getStats().number_of_participant_devices_media_capability_changed,
+				                             laure_stat2.number_of_participant_devices_media_capability_changed + 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_on_hold,
+			                             marie_stat2.number_of_participant_devices_on_hold + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &marie.getStats().number_of_participant_devices_media_capability_changed,
+			                             marie_stat2.number_of_participant_devices_media_capability_changed + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			if (uninvited_participant_dials && (participant_list_type == LinphoneConferenceParticipantListTypeOpen)) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_on_hold,
+				                             michelle_stat2.number_of_participant_devices_on_hold + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(
+				    coresList, &michelle.getStats().number_of_participant_devices_media_capability_changed,
+				    michelle_stat2.number_of_participant_devices_media_capability_changed + 1,
+				    liblinphone_tester_sip_timeout));
+			}
+
+			linphone_conference_enter(paulineConference);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallResuming,
+			                             pauline_stat2.number_of_LinphoneCallResuming + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+			                             pauline_stat2.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat2.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+			                             focus_stat2.number_of_participant_devices_joined + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			if (!remove_participant) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_joined,
+				                             laure_stat2.number_of_participant_devices_joined + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList,
+				                             &laure.getStats().number_of_participant_devices_media_capability_changed,
+				                             laure_stat2.number_of_participant_devices_media_capability_changed + 2,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_joined,
+			                             marie_stat2.number_of_participant_devices_joined + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &marie.getStats().number_of_participant_devices_media_capability_changed,
+			                             marie_stat2.number_of_participant_devices_media_capability_changed + 2,
+			                             liblinphone_tester_sip_timeout));
+
+			if (uninvited_participant_dials && (participant_list_type == LinphoneConferenceParticipantListTypeOpen)) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_joined,
+				                             michelle_stat2.number_of_participant_devices_joined + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(
+				    coresList, &michelle.getStats().number_of_participant_devices_media_capability_changed,
+				    michelle_stat2.number_of_participant_devices_media_capability_changed + 1,
+				    liblinphone_tester_sip_timeout));
+			}
+
+			if (pauline_call) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pauline_call);
+				BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), video_enabled, int, "%0d");
+			}
+		}
+
+		for (auto mgr : mgrsToRemove) {
+
+			auto itConferenceMgrs = std::find(conferenceMgrs.begin(), conferenceMgrs.end(), mgr);
+			if (itConferenceMgrs != conferenceMgrs.end()) {
+				conferenceMgrs.erase(itConferenceMgrs);
+			}
+
+			auto itMembers = std::find(members.begin(), members.end(), mgr);
+			if (itMembers != members.end()) {
+				members.erase(itMembers);
+			}
+
+			LinphoneCall *call = linphone_core_get_current_call(mgr->lc);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				stats marie_stat2 = marie.getStats();
+				stats focus_stat2 = focus.getStats();
+				if (network_restart) {
+					ms_message("%s switches off network before %s leaves conference %s",
+					           linphone_core_get_identity(marie.getLc()), linphone_core_get_identity(mgr->lc),
+					           conference_address_str);
+					linphone_core_set_network_reachable(marie.getLc(), FALSE);
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionTerminated,
+					                             marie_stat2.number_of_LinphoneSubscriptionTerminated + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				linphone_call_terminate(call);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				BC_ASSERT_PTR_NULL(pconference);
+				linphone_address_unref(uri);
+
+				if (network_restart) {
+					ms_message("%s is back online after %s leaves conference %s",
+					           linphone_core_get_identity(marie.getLc()), linphone_core_get_identity(mgr->lc),
+					           conference_address_str);
+					linphone_core_set_network_reachable(marie.getLc(), TRUE);
+					BC_ASSERT_TRUE(wait_for_list(coresList,
+					                             &marie.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+					                             marie_stat2.number_of_LinphoneSubscriptionOutgoingProgress + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList,
+					                             &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+					                             focus_stat2.number_of_LinphoneSubscriptionIncomingReceived + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+					                             marie_stat2.number_of_LinphoneSubscriptionActive + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+					                             focus_stat2.number_of_LinphoneSubscriptionActive + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+					                             marie_stat2.number_of_participants_removed + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+					                             marie_stat2.number_of_participant_devices_removed + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+					                             marie_stat2.number_of_LinphoneCallStreamsRunning + 2,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+					                             focus_stat2.number_of_LinphoneCallStreamsRunning + 2,
+					                             liblinphone_tester_sip_timeout));
+				}
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                             focus_stat.number_of_participants_removed + 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+		                             marie_stat.number_of_participants_removed + 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+		                             marie_stat.number_of_participant_devices_removed + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		if (uninvited_participant_dials) {
+			if (participant_list_type == LinphoneConferenceParticipantListTypeOpen) {
+				int extra_participants = static_cast<int>(extraParticipantMgrs.size());
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_removed, 2,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_removed, 2,
+				                             liblinphone_tester_sip_timeout));
+
+				if (remove_participant) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_participants_removed, 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_participant_devices_removed, 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				for (auto mgr : {focus.getCMgr(), marie.getCMgr(), michelle.getCMgr(), berthe.getCMgr()}) {
+					LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+					LinphoneConference *pconference =
+					    linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+					BC_ASSERT_PTR_NOT_NULL(pconference);
+					linphone_address_unref(uri);
+					if (pconference) {
+						BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+						                ((mgr == focus.getCMgr()) ? (extra_participants + 1) : extra_participants), int,
+						                "%0d");
+						bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+						BC_ASSERT_EQUAL(bctbx_list_size(devices), (extra_participants + 1), size_t, "%zu");
+						if (devices) {
+							bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+						}
+						BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+					}
+				}
+
+				stats marie_stat2 = marie.getStats();
+				stats focus_stat2 = focus.getStats();
+
+				for (auto mgr : extraParticipantMgrs) {
+					LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+
+					auto itConferenceMgrs = std::find(conferenceMgrs.begin(), conferenceMgrs.end(), mgr);
+					if (itConferenceMgrs != conferenceMgrs.end()) {
+						conferenceMgrs.erase(itConferenceMgrs);
+					}
+
+					auto itMembers = std::find(members.begin(), members.end(), mgr);
+					if (itMembers != members.end()) {
+						members.erase(itMembers);
+					}
+
+					BC_ASSERT_PTR_NOT_NULL(call);
+					if (call) {
+						linphone_call_terminate(call);
+						BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1,
+						                             liblinphone_tester_sip_timeout));
+						BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+						                             liblinphone_tester_sip_timeout));
+						BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+						                             liblinphone_tester_sip_timeout));
+						BC_ASSERT_TRUE(wait_for_list(coresList,
+						                             &mgr->stat.number_of_LinphoneConferenceStateTerminationPending, 1,
+						                             liblinphone_tester_sip_timeout));
+						BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated,
+						                             1, liblinphone_tester_sip_timeout));
+						BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+						                             liblinphone_tester_sip_timeout));
+					}
+				}
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+				                             focus_stat2.number_of_participants_removed + extra_participants,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+				                             focus_stat2.number_of_participant_devices_removed + extra_participants,
+				                             liblinphone_tester_sip_timeout));
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+				                             marie_stat2.number_of_participants_removed + extra_participants,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+				                             marie_stat2.number_of_participant_devices_removed + extra_participants,
+				                             liblinphone_tester_sip_timeout));
+			} else if (participant_list_type == LinphoneConferenceParticipantListTypeClosed) {
+				LinphoneCall *call = linphone_core_get_current_call(michelle.getLc());
+				BC_ASSERT_PTR_NULL(call);
+
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(michelle.getLc()));
+				LinphoneConference *pconference =
+				    linphone_core_search_conference(michelle.getLc(), NULL, uri, confAddr, NULL);
+				BC_ASSERT_PTR_NULL(pconference);
+				linphone_address_unref(uri);
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                marie_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateTerminated,
+		                marie_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateDeleted,
+		                marie_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		for (auto mgr : conferenceMgrs) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+				                ((mgr == focus.getCMgr()) ? 1 : 0), int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 1, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+			}
+		}
+
+		const bctbx_list_t *calls = linphone_core_get_calls(marie.getLc());
+		BC_ASSERT_EQUAL(bctbx_list_size(calls), 1, size_t, "%zu");
+
+		LinphoneCall *call = linphone_core_get_call_by_remote_address2(marie.getLc(), focus.getCMgr()->identity);
+		BC_ASSERT_PTR_NOT_NULL(call);
+		if (call) {
+			linphone_call_terminate(call);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &marie.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			// Explicitely terminate conference as those on server are static by default
+			LinphoneConference *pconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				linphone_conference_terminate(pconference);
+			}
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &focus.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		std::list<LinphoneCoreManager *> allMembers{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()};
+		if ((participant_list_type == LinphoneConferenceParticipantListTypeOpen) && uninvited_participant_dials) {
+			allMembers.push_back(michelle.getCMgr());
+			if (remove_participant) {
+				allMembers.push_back(berthe.getCMgr());
+			}
+		}
+		for (auto mgr : allMembers) {
+			const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+			BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs),
+			                ((client_restart && (mgr == marie.getCMgr())) ? 2 : 1), unsigned int, "%u");
+
+			bctbx_list_t *mgr_focus_call_log =
+			    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+			if (mgr_focus_call_log) {
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log),
+				                ((client_restart && (mgr == marie.getCMgr())) ? 2 : 1), unsigned int, "%u");
+				for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+					LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				}
+				bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		ms_free(conference_address_str);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_simple_conference(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionNone, FALSE, LinphoneConferenceLayoutGrid, FALSE, FALSE, FALSE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionRecvOnly, FALSE);
+}
+
+static void create_simple_conference_with_server_restart(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionNone, FALSE, LinphoneConferenceLayoutGrid, FALSE, FALSE, FALSE, TRUE,
+	                       FALSE, FALSE, LinphoneMediaDirectionRecvOnly, TRUE);
+}
+
+static void create_simple_conference_with_client_restart(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionNone, FALSE, LinphoneConferenceLayoutGrid, FALSE, FALSE, FALSE, FALSE,
+	                       TRUE, FALSE, LinphoneMediaDirectionRecvOnly, TRUE);
+}
+
+static void create_simple_ice_conference(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionNone, TRUE, LinphoneConferenceLayoutGrid, TRUE, FALSE, FALSE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionRecvOnly, TRUE);
+}
+
+static void create_simple_stun_ice_conference(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionNone, TRUE, LinphoneConferenceLayoutGrid, TRUE, TRUE, FALSE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_simple_zrtp_conference(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionZRTP, TRUE, LinphoneConferenceLayoutActiveSpeaker, FALSE, FALSE,
+	                       FALSE, FALSE, FALSE, FALSE, LinphoneMediaDirectionRecvOnly, FALSE);
+}
+
+static void create_simple_dtls_conference(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionDTLS, TRUE, LinphoneConferenceLayoutActiveSpeaker, FALSE, FALSE,
+	                       FALSE, FALSE, FALSE, FALSE, LinphoneMediaDirectionRecvOnly, FALSE);
+}
+
+static void create_simple_srtp_conference(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionSRTP, TRUE, LinphoneConferenceLayoutGrid, FALSE, FALSE, FALSE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionRecvOnly, FALSE);
+}
+
+static void create_simple_ice_srtp_conference(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionSRTP, TRUE, LinphoneConferenceLayoutGrid, TRUE, FALSE, FALSE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_simple_ice_dtls_conference(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionDTLS, TRUE, LinphoneConferenceLayoutGrid, TRUE, FALSE, FALSE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_simple_stun_ice_srtp_conference(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionSRTP, TRUE, LinphoneConferenceLayoutActiveSpeaker, TRUE, TRUE, FALSE,
+	                       FALSE, FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_conference_with_uninvited_participant(void) {
+	create_conference_base(ms_time(NULL), -1, TRUE, LinphoneConferenceParticipantListTypeOpen, TRUE,
+	                       LinphoneMediaEncryptionNone, TRUE, LinphoneConferenceLayoutGrid, FALSE, FALSE, FALSE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionRecvOnly, TRUE);
+}
+
+static void create_conference_with_uninvited_participant_not_allowed(void) {
+	create_conference_base(ms_time(NULL), -1, TRUE, LinphoneConferenceParticipantListTypeClosed, FALSE,
+	                       LinphoneMediaEncryptionNone, FALSE, LinphoneConferenceLayoutActiveSpeaker, FALSE, FALSE,
+	                       FALSE, FALSE, FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_conference_starting_immediately(void) {
+	create_conference_base(ms_time(NULL), 0, FALSE, LinphoneConferenceParticipantListTypeClosed, FALSE,
+	                       LinphoneMediaEncryptionNone, FALSE, LinphoneConferenceLayoutGrid, FALSE, FALSE, FALSE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionRecvOnly, FALSE);
+}
+
+static void create_conference_starting_in_the_past(void) {
+	create_conference_base(ms_time(NULL) - 600, 900, FALSE, LinphoneConferenceParticipantListTypeClosed, TRUE,
+	                       LinphoneMediaEncryptionNone, FALSE, LinphoneConferenceLayoutActiveSpeaker, FALSE, FALSE,
+	                       FALSE, FALSE, FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_simple_conference_with_audio_only_participant(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionNone, TRUE, LinphoneConferenceLayoutGrid, FALSE, FALSE, TRUE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_simple_ice_conference_with_audio_only_participant(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionNone, TRUE, LinphoneConferenceLayoutGrid, TRUE, TRUE, TRUE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionRecvOnly, FALSE);
+}
+
+static void create_simple_stun_ice_conference_with_audio_only_participant(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionNone, TRUE, LinphoneConferenceLayoutGrid, TRUE, TRUE, TRUE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_simple_stun_ice_srtp_conference_with_audio_only_participant(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionSRTP, TRUE, LinphoneConferenceLayoutGrid, TRUE, TRUE, TRUE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionRecvOnly, FALSE);
+}
+
+static void create_conference_with_audio_only_and_uninvited_participant(void) {
+	create_conference_base(ms_time(NULL), -1, TRUE, LinphoneConferenceParticipantListTypeOpen, TRUE,
+	                       LinphoneMediaEncryptionNone, TRUE, LinphoneConferenceLayoutGrid, FALSE, FALSE, TRUE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_simple_conference_with_audio_only_participant_enabling_video(void) {
+	create_conference_base(ms_time(NULL), -1, FALSE, LinphoneConferenceParticipantListTypeOpen, FALSE,
+	                       LinphoneMediaEncryptionNone, TRUE, LinphoneConferenceLayoutGrid, FALSE, FALSE, TRUE, FALSE,
+	                       FALSE, FALSE, LinphoneMediaDirectionSendRecv, FALSE);
+}
+
+static void create_conference_with_server_restart_base(bool_t organizer_first) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		stats focus_stat = focus.getStats();
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
+		std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(),
+		                                                laure.getCMgr()};
+		std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()};
+
+		time_t start_time = ms_time(NULL) + 60;
+		int duration = 30;
+		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
+		const char *description = "London Pub";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+		char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		coresList = bctbx_list_remove(coresList, focus.getLc());
+		// Restart flexisip
+		focus.reStart();
+
+		LinphoneVideoActivationPolicy *pol = linphone_factory_create_video_activation_policy(linphone_factory_get());
+		linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+		linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+		linphone_core_set_video_activation_policy(focus.getLc(), pol);
+		linphone_video_activation_policy_unref(pol);
+
+		linphone_core_enable_video_capture(focus.getLc(), TRUE);
+		linphone_core_enable_video_display(focus.getLc(), TRUE);
+
+		coresList = bctbx_list_append(coresList, focus.getLc());
+
+		LinphoneCoreManager *first_to_join = NULL;
+		std::list<LinphoneCoreManager *> other_members{pauline.getCMgr()};
+		if (organizer_first) {
+			first_to_join = marie.getCMgr();
+			other_members.push_back(laure.getCMgr());
+		} else {
+			first_to_join = laure.getCMgr();
+			other_members.push_back(marie.getCMgr());
+		}
+
+		ms_message("First participant %s is calling conference %s", linphone_core_get_identity(first_to_join->lc),
+		           conference_address_str);
+		LinphoneCallParams *first_part_new_params = linphone_core_create_call_params(first_to_join->lc, nullptr);
+		linphone_core_invite_address_with_params_2(first_to_join->lc, confAddr, first_part_new_params, NULL, nullptr);
+		linphone_call_params_unref(first_part_new_params);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &first_to_join->stat.number_of_LinphoneCallOutgoingProgress, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &first_to_join->stat.number_of_LinphoneCallStreamsRunning, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : other_members) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			ms_message("%s is calling conference %s", linphone_core_get_identity(mgr->lc), conference_address_str);
+			linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+		}
+
+		for (auto mgr : members) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			int no_streams_running = 2;
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, (no_streams_running - 1),
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, no_streams_running,
+			                             liblinphone_tester_sip_timeout));
+			// Update to add to conference.
+			// If ICE is enabled, the addition to a conference may go through a resume of the call
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+			                             ((mgr == marie.getCMgr()) ? 3 : 2), liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, 5000));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 3,
+		                             liblinphone_tester_sip_timeout));
+		int focus_no_streams_running = 6;
+		// Update to end ICE negotiations
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + (focus_no_streams_running - 3),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running,
+		                             liblinphone_tester_sip_timeout));
+		// Update to add to conference.
+		// If ICE is enabled, the addition to a conference may go through a resume of the call
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 3, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + 3, 5000));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + 3, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + 3,
+		                             liblinphone_tester_sip_timeout));
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : members) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
+		wait_for_conference_streams({focus, marie, pauline, laure}, conferenceMgrs, focus.getCMgr(), memberList,
+		                            confAddr, TRUE);
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		for (auto mgr : conferenceMgrs) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference);
+				int no_participants = 0;
+				if (start_time >= 0) {
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+					                (long long)start_time, long long, "%lld");
+				}
+				BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+				                (long long)end_time, long long, "%lld");
+				bctbx_list_t *participant_device_list = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(participant_device_list), 3, size_t, "%zu");
+				bctbx_list_free_with_data(participant_device_list, (void (*)(void *))linphone_participant_device_unref);
+
+				if (mgr == focus.getCMgr()) {
+					no_participants = 3;
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = 2;
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+
+					LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(mgr->lc);
+					bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+					linphone_video_activation_policy_unref(pol);
+
+					int no_streams_audio = 1;
+					int no_streams_video = (enabled) ? 4 : 0;
+					int no_active_streams_video = (enabled) ? no_streams_video : 0;
+					int no_streams_text = 0;
+
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						_linphone_call_check_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						_linphone_call_check_nb_streams(ccall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_active_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+			}
+		}
+
+		const int total_marie_calls =
+		    marie.getStats().number_of_LinphoneCallEnd + (int)bctbx_list_size(linphone_core_get_calls(marie.getLc()));
+		const int total_focus_calls =
+		    focus.getStats().number_of_LinphoneCallEnd + (int)bctbx_list_size(linphone_core_get_calls(focus.getLc()));
+		const int total_pauline_calls = pauline.getStats().number_of_LinphoneCallEnd +
+		                                (int)bctbx_list_size(linphone_core_get_calls(pauline.getLc()));
+		const int total_laure_calls =
+		    laure.getStats().number_of_LinphoneCallEnd + (int)bctbx_list_size(linphone_core_get_calls(laure.getLc()));
+
+		linphone_core_terminate_all_calls(pauline.getLc());
+		linphone_core_terminate_all_calls(laure.getLc());
+		linphone_core_terminate_all_calls(marie.getLc());
+
+		// Wait for calls to be terminated
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd, total_marie_calls, 30000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallEnd, total_pauline_calls, 30000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallEnd, total_laure_calls, 30000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd, total_focus_calls, 40000));
+
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased, total_marie_calls, 30000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallReleased, total_pauline_calls, 30000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallReleased, total_laure_calls, 30000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased, total_focus_calls, 40000));
+
+		if (confAddr && fconference) {
+			linphone_conference_terminate(fconference);
+		}
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+
+			// Wait for all conferences to be terminated
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated,
+			                             (mgr == focus.getCMgr()) ? 3 : 1, liblinphone_tester_sip_timeout));
+
+			if (mgr && (mgr != focus.getCMgr())) {
+				LinphoneCall *participant_call =
+				    linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+				BC_ASSERT_PTR_NULL(participant_call);
+				LinphoneCall *conference_call = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+				BC_ASSERT_PTR_NULL(conference_call);
+
+				const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 1, unsigned int, "%u");
+
+				bctbx_list_t *mgr_focus_call_log =
+				    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+				BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+				if (mgr_focus_call_log) {
+					BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u");
+					for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+						LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+						BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+					}
+					bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+				}
+			}
+		}
+
+		ms_free(conference_address_str);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_conference_with_server_restart_organizer_first(void) {
+	create_conference_with_server_restart_base(TRUE);
+}
+
+static void create_conference_with_server_restart_participant_first(void) {
+	create_conference_with_server_restart_base(FALSE);
+}
+
+static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mismatch) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(berthe);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                 berthe.getCMgr()}) {
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, LinphoneConferenceLayoutGrid);
+				linphone_core_set_media_encryption(mgr->lc, LinphoneMediaEncryptionSRTP);
+			}
+
+			enable_stun_in_core(mgr, TRUE, TRUE);
+			linphone_core_manager_wait_for_stun_resolution(mgr);
+
+			if ((organizer_codec_mismatch && (mgr == marie.getCMgr())) ||
+			    (!organizer_codec_mismatch && (mgr == michelle.getCMgr()))) {
+				disable_all_audio_codecs_except_one(mgr->lc, "pcmu", -1);
+			} else {
+				disable_all_audio_codecs_except_one(mgr->lc, "pcma", -1);
+			}
+
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		stats focus_stat = focus.getStats();
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                                              berthe.getCMgr()};
+		std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(),    pauline.getCMgr(),
+		                                                laure.getCMgr(), michelle.getCMgr(), berthe.getCMgr()};
+		std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(),
+		                                         michelle.getCMgr(), berthe.getCMgr()};
+
+		time_t start_time = ms_time(NULL);
+		time_t end_time = -1;
+		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
+		const char *description = "Paris Baker";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleListener));
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+		char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneMediaEncryption encryption = LinphoneMediaEncryptionNone;
+		for (auto mgr : members) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			linphone_call_params_set_media_encryption(new_params, encryption);
+			linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+		}
+
+		std::list<LinphoneCoreManager *> codec_mismatch_members;
+		if (organizer_codec_mismatch) {
+			codec_mismatch_members.push_back(marie.getCMgr());
+		} else {
+			codec_mismatch_members.push_back(michelle.getCMgr());
+		}
+
+		for (const auto &m : codec_mismatch_members) {
+			auto itConferenceMgrs = std::find(conferenceMgrs.begin(), conferenceMgrs.end(), m);
+			if (itConferenceMgrs != conferenceMgrs.end()) {
+				conferenceMgrs.erase(itConferenceMgrs);
+			}
+
+			auto itParticipants = std::find(participants.begin(), participants.end(), m);
+			if (itParticipants != participants.end()) {
+				participants.erase(itParticipants);
+			}
+
+			auto itMembers = std::find(members.begin(), members.end(), m);
+			if (itMembers != members.end()) {
+				members.erase(itMembers);
+			}
+		}
+
+		for (auto mgr : members) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			int no_streams_running = 3;
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, (no_streams_running - 1),
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, no_streams_running,
+			                             liblinphone_tester_sip_timeout));
+			// Update to add to conference.
+			// If ICE is enabled, the addition to a conference may go through a resume of the call
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+			                             ((mgr == marie.getCMgr()) ? 3 : 2), liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, 5000));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+
+			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pcall);
+			if (pcall) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+				const LinphoneMediaEncryption pcall_enc = linphone_call_params_get_media_encryption(call_cparams);
+				BC_ASSERT_EQUAL(pcall_enc, encryption, int, "%d");
+			}
+			LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(ccall);
+			if (ccall) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+				const LinphoneMediaEncryption ccall_enc = linphone_call_params_get_media_encryption(call_cparams);
+				BC_ASSERT_EQUAL(ccall_enc, encryption, int, "%d");
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 3,
+		                             liblinphone_tester_sip_timeout));
+		int focus_no_streams_running = 9;
+		// Update to end ICE negotiations
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + (focus_no_streams_running - 3),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running,
+		                             liblinphone_tester_sip_timeout));
+		// Update to add to conference.
+		// If ICE is enabled, the addition to a conference may go through a resume of the call
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 3, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + 3, 5000));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + 3, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + 3,
+		                             liblinphone_tester_sip_timeout));
+		if (organizer_codec_mismatch) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+			                             focus_stat.number_of_participants_removed + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+			                             focus_stat.number_of_participant_devices_removed + 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : members) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
+		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
+		                            memberList, confAddr, TRUE);
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		for (auto mgr : conferenceMgrs) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference);
+				int no_participants = 0;
+				if (start_time >= 0) {
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+					                (long long)start_time, long long, "%lld");
+				}
+				BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+				                (long long)end_time, long long, "%lld");
+
+				bctbx_list_t *participant_device_list = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(participant_device_list), members.size(), size_t, "%zu");
+				for (bctbx_list_t *d_it = participant_device_list; d_it; d_it = bctbx_list_next(d_it)) {
+					LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(d_it);
+					BC_ASSERT_PTR_NOT_NULL(d);
+					if (d) {
+						BC_ASSERT_TRUE(!!!linphone_participant_device_get_is_muted(d));
+					}
+				}
+				bctbx_list_free_with_data(participant_device_list, (void (*)(void *))linphone_participant_device_unref);
+
+				if (mgr == focus.getCMgr()) {
+					no_participants = static_cast<int>(members.size());
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = static_cast<int>(members.size() - 1);
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+					BC_ASSERT_TRUE(check_ice(mgr, focus.getCMgr(), LinphoneIceStateHostConnection));
+
+					LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(mgr->lc);
+					bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+					linphone_video_activation_policy_unref(pol);
+
+					int no_streams_audio = 1;
+					int no_active_streams_video = 0;
+					int no_streams_text = 0;
+
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						no_active_streams_video =
+						    static_cast<int>(compute_no_video_streams(enabled, pcall, pconference));
+						_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams),
+						                enabled && (no_active_streams_video > 0), int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams),
+						                enabled && (no_active_streams_video > 0), int, "%0d");
+					}
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_active_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams),
+						                enabled && (no_active_streams_video > 0), int, "%0d");
+					}
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+			}
+		}
+
+		for (auto mgr : members) {
+			LinphoneCall *call = linphone_core_get_current_call(mgr->lc);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				linphone_call_terminate(call);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				BC_ASSERT_PTR_NULL(pconference);
+				linphone_address_unref(uri);
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                             focus_stat.number_of_participants_removed + static_cast<int>(members.size()),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                  focus_stat.number_of_participant_devices_removed + static_cast<int>(members.size()),
+		                  liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                             focus_stat.number_of_LinphoneCallEnd + static_cast<int>(members.size()),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                             focus_stat.number_of_LinphoneCallReleased + static_cast<int>(members.size()),
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		for (auto mgr : members) {
+			const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+			BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 1, unsigned int, "%u");
+
+			bctbx_list_t *mgr_focus_call_log =
+			    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+			if (mgr_focus_call_log) {
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u");
+				for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+					LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				}
+				bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		ms_free(conference_address_str);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_conference_with_organizer_codec_mismatch(void) {
+	create_conference_with_codec_mismatch_base(TRUE);
+}
+
+static void create_conference_with_participant_codec_mismatch(void) {
+	create_conference_with_codec_mismatch_base(FALSE);
+}
+
+static void create_conference_dial_out_base(bool_t send_ics,
+                                            LinphoneConferenceLayout layout,
+                                            LinphoneVideoActivationPolicy *pol,
+                                            bool_t enable_stun,
+                                            bool_t enable_ice,
+                                            LinphoneConferenceParticipantListType participant_list_type,
+                                            bool_t accept,
+                                            bool_t participant_codec_mismatch) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(berthe);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		bool_t enable_video = !!linphone_video_activation_policy_get_automatically_accept(pol) ||
+		                      !!linphone_video_activation_policy_get_automatically_initiate(pol);
+		bool_t initiate_video = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+		bool_t accept_video = !!linphone_video_activation_policy_get_automatically_accept(pol);
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                 berthe.getCMgr()}) {
+			if (participant_codec_mismatch) {
+				if (mgr == michelle.getCMgr()) {
+					disable_all_audio_codecs_except_one(mgr->lc, "pcmu", -1);
+				} else {
+					disable_all_audio_codecs_except_one(mgr->lc, "pcma", -1);
+				}
+			}
+
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, layout);
+			}
+
+			enable_stun_in_core(mgr, enable_stun, enable_ice);
+			linphone_core_manager_wait_for_stun_resolution(mgr);
+
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+		linphone_core_set_conference_participant_list_type(focus.getLc(), participant_list_type);
+
+		stats focus_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+
+		std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(),    pauline.getCMgr(),
+		                                                laure.getCMgr(), michelle.getCMgr(), berthe.getCMgr()};
+		std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(),
+		                                         michelle.getCMgr(), berthe.getCMgr()};
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                                              berthe.getCMgr()};
+		std::list<LinphoneCoreManager *> codec_mismatch_members;
+
+		const char *initialSubject = "Schedule of the trip towards the top of Europe";
+		const char *description = "To the top of the Mont Blanc!!!! :-)";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr =
+		    create_conference_on_server(focus, marie, participantList, -1, -1, initialSubject, description, send_ics);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		int marie_conferences = ((send_ics) ? 1 : 0) + 1;
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+		                             marie_conferences, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallOutgoingInit,
+		                             marie_stat.number_of_LinphoneCallOutgoingInit + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingInit,
+		                             focus_stat.number_of_LinphoneCallOutgoingInit + 4,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		if (participant_codec_mismatch) {
+			codec_mismatch_members.push_back(michelle.getCMgr());
+
+			for (const auto &m : codec_mismatch_members) {
+				auto itConferenceMgrs = std::find(conferenceMgrs.begin(), conferenceMgrs.end(), m);
+				if (itConferenceMgrs != conferenceMgrs.end()) {
+					conferenceMgrs.erase(itConferenceMgrs);
+				}
+
+				auto itParticipants = std::find(participants.begin(), participants.end(), m);
+				if (itParticipants != participants.end()) {
+					participants.erase(itParticipants);
+				}
+
+				auto itMembers = std::find(members.begin(), members.end(), m);
+				if (itMembers != members.end()) {
+					members.erase(itMembers);
+				}
+
+				bctbx_list_t *focus_call_log =
+				    linphone_core_get_call_history_2(focus.getLc(), m->identity, focus.getCMgr()->identity);
+				BC_ASSERT_PTR_NOT_NULL(focus_call_log);
+				if (focus_call_log) {
+					BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(focus_call_log), 1, unsigned int, "%u");
+					for (bctbx_list_t *it = focus_call_log; it; it = bctbx_list_next(it)) {
+						LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+						BC_ASSERT_EQUAL(linphone_call_log_get_status(call_log), LinphoneCallAborted, int, "%d");
+					}
+					bctbx_list_free_with_data(focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+				}
+
+				bctbx_list_t *member_call_log =
+				    linphone_core_get_call_history_2(m->lc, focus.getCMgr()->identity, m->identity);
+				BC_ASSERT_PTR_NOT_NULL(member_call_log);
+				if (member_call_log) {
+					BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(member_call_log), 1, unsigned int, "%u");
+					for (bctbx_list_t *it = member_call_log; it; it = bctbx_list_next(it)) {
+						LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+						BC_ASSERT_EQUAL(linphone_call_log_get_status(call_log), LinphoneCallAborted, int, "%d");
+					}
+					bctbx_list_free_with_data(member_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+				}
+			}
+		}
+
+		for (auto mgr : participants) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		LinphoneConference *oconference = linphone_core_search_conference_2(marie.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(oconference);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		if (enable_ice) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+			                             marie_stat.number_of_LinphoneCallUpdating + 1, 20000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+			                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+		                             marie_stat.number_of_LinphoneSubscriptionOutgoingProgress + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+		                             marie_stat.number_of_LinphoneSubscriptionActive + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		if (BC_ASSERT_PTR_NOT_NULL(oconference)) {
+			BC_ASSERT_EQUAL(linphone_conference_get_participant_count(oconference), 4, int, "%0d");
+			bctbx_list_t *devices = linphone_conference_get_participant_device_list(oconference);
+			BC_ASSERT_EQUAL(bctbx_list_size(devices), members.size(), size_t, "%zu");
+			if (devices) {
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			}
+		}
+
+		if (confAddr) {
+			for (auto mgr : participants) {
+				check_conference_info(mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject,
+				                      (accept && send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew);
+
+				LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+				BC_ASSERT_PTR_NOT_NULL(pcall);
+				if (pcall) {
+					LinphoneCallLog *call_log = linphone_call_get_call_log(pcall);
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+					if (accept) {
+						linphone_call_accept(pcall);
+					} else {
+						linphone_call_decline(pcall, LinphoneReasonDeclined);
+					}
+				}
+			}
+		}
+
+		int participant_conference_info_participants = 5;
+		if (accept) {
+			int participant_no = static_cast<int>(participants.size());
+			for (auto mgr : participants) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+
+				check_conference_info(mgr, confAddr, marie.getCMgr(), participant_conference_info_participants, 0, 0,
+				                      initialSubject, (send_ics) ? description : NULL, 0,
+				                      LinphoneConferenceInfoStateNew);
+
+				LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+				BC_ASSERT_PTR_NOT_NULL(pcall);
+				if (pcall) {
+					LinphoneCallLog *call_log = linphone_call_get_call_log(pcall);
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+					LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log);
+					if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) {
+						BC_ASSERT_TRUE(linphone_address_weak_equal(
+						    linphone_conference_info_get_organizer(call_log_info), marie.getCMgr()->identity));
+						BC_ASSERT_TRUE(
+						    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
+
+						const bctbx_list_t *info_participants =
+						    linphone_conference_info_get_participants(call_log_info);
+						// Original participants + Marie who joined the conference
+						BC_ASSERT_EQUAL(bctbx_list_size(info_participants), participant_conference_info_participants,
+						                size_t, "%zu");
+
+						BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0,
+						                         long long, "%lld");
+						const int duration_m = linphone_conference_info_get_duration(call_log_info);
+						BC_ASSERT_EQUAL(duration_m, 0, int, "%d");
+						if (initialSubject) {
+							BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(call_log_info), initialSubject);
+						} else {
+							BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(call_log_info));
+						}
+						if (send_ics) {
+							BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(call_log_info),
+							                       description);
+						} else {
+							BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(call_log_info));
+						}
+					}
+				}
+			}
+
+			if (enable_ice) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdating,
+				                             focus_stat.number_of_LinphoneCallUpdating + participant_no - 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat.number_of_LinphoneCallStreamsRunning +
+			                                 ((enable_ice) ? 2 : 1) * static_cast<int>(participants.size() + 1),
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+			                             marie_stat.number_of_LinphoneConferenceStateCreated + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+			                             marie_stat.number_of_LinphoneSubscriptionOutgoingProgress + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+			                             marie_stat.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_NotifyReceived,
+			                             marie_stat.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+			// Update to add to conference.
+			// If ICE is enabled, the addition to a conference may go through a resume of the call
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+			                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+			                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + participant_no,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+			                             focus_stat.number_of_LinphoneSubscriptionActive + participant_no,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+			                             focus_stat.number_of_participants_added + participant_no,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+			                             focus_stat.number_of_participant_devices_added + participant_no,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+			                             focus_stat.number_of_participant_devices_joined + participant_no,
+			                             liblinphone_tester_sip_timeout));
+
+			LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(fconference);
+
+			std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+			for (const auto &member : members) {
+				try {
+					const auto &participantInfo = participantList.at(member);
+					memberList.insert(std::make_pair(member, participantInfo));
+				} catch (std::out_of_range &) {
+					if (member == marie.getCMgr()) {
+						memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+					} else {
+						ms_fatal("Unable to find active participant %s in the participant list",
+						         linphone_core_get_identity(member->lc));
+					}
+				}
+			}
+			wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs,
+			                            focus.getCMgr(), memberList, confAddr, enable_video);
+
+			// wait bit more to detect side effect if any
+			CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(15), [] {
+				return false;
+			});
+
+			for (auto mgr : conferenceMgrs) {
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+				linphone_address_unref(uri);
+				BC_ASSERT_PTR_NOT_NULL(pconference);
+
+				LinphoneVideoActivationPolicy *mgr_pol = linphone_core_get_video_activation_policy(mgr->lc);
+				bool_t video_enabled =
+				    !!((mgr == marie.getCMgr()) ? linphone_video_activation_policy_get_automatically_initiate(mgr_pol)
+				                                : linphone_video_activation_policy_get_automatically_accept(mgr_pol));
+				linphone_video_activation_policy_unref(mgr_pol);
+
+				if (pconference) {
+					int no_participants = 0;
+					if (mgr == focus.getCMgr()) {
+						no_participants = static_cast<int>(members.size());
+						BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+					} else {
+						no_participants = participant_no;
+						BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+						LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+						BC_ASSERT_PTR_NOT_NULL(current_call);
+						if (current_call) {
+							BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+							                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+						}
+						if (enable_ice) {
+							BC_ASSERT_TRUE(check_ice(mgr, focus.getCMgr(), LinphoneIceStateHostConnection));
+						}
+
+						int no_streams_audio = 1;
+						int no_streams_video = 0;
+						int no_active_streams_video = 0;
+						if (initiate_video && accept_video) {
+							no_streams_video = (no_participants + 2);
+						} else if (initiate_video) {
+							no_streams_video = (mgr == marie.getCMgr()) ? 2 : 1;
+						} else if (accept_video) {
+							no_streams_video = (mgr == marie.getCMgr()) ? 0 : (no_participants + 1);
+						} else {
+							no_streams_video = (mgr == marie.getCMgr()) ? 0 : 1;
+						}
+
+						if (video_enabled) {
+							if (initiate_video && accept_video) {
+								no_active_streams_video = (no_participants + 2);
+							} else if (initiate_video) {
+								no_active_streams_video = (mgr == marie.getCMgr()) ? 2 : 0;
+							} else if (accept_video) {
+								no_active_streams_video = (no_participants + 1);
+							}
+						}
+						int no_streams_text = 0;
+
+						LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+						BC_ASSERT_PTR_NOT_NULL(pcall);
+						if (pcall) {
+							_linphone_call_check_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text);
+							_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
+							                                       no_streams_text);
+							const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), video_enabled, int,
+							                "%0d");
+							const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), video_enabled, int,
+							                "%0d");
+							const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), video_enabled, int,
+							                "%0d");
+						}
+
+						LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+						BC_ASSERT_PTR_NOT_NULL(ccall);
+						if (ccall) {
+							_linphone_call_check_nb_streams(ccall, no_streams_audio, no_streams_video, no_streams_text);
+							_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_active_streams_video,
+							                                       no_streams_text);
+							const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), video_enabled, int,
+							                "%0d");
+							const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), video_enabled, int,
+							                "%0d");
+							const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), video_enabled, int,
+							                "%0d");
+						}
+					}
+					BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int,
+					                "%0d");
+					bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+					BC_ASSERT_EQUAL(bctbx_list_size(devices), members.size(), size_t, "%zu");
+					if (devices) {
+						bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+					}
+					BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+					LinphoneParticipant *me = linphone_conference_get_me(pconference);
+					BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+					               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+					BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+					bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+					for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+						LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+						BC_ASSERT_TRUE(linphone_participant_is_admin(p) ==
+						               linphone_address_weak_equal(linphone_participant_get_address(p),
+						                                           marie.getCMgr()->identity));
+					}
+					bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+					if (mgr != focus.getCMgr()) {
+						check_conference_ssrc(fconference, pconference);
+					}
+
+					LinphoneConference *conference = linphone_core_search_conference_2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(conference);
+					if (conference) {
+						bctbx_list_t *devices = linphone_conference_get_participant_device_list(conference);
+						for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+							LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+							// If we are currently carrying out checks on the conference server side, the must set the
+							// value of video enabled flag for each participant. In fact each call session may have the
+							// video enabled or not and this is taken into account to compute the video availablity
+							// flag. Nonetheless, this is not required for the participants as they only have one call
+							// session towards the conference server therefore we can reuse the value computed earlier
+							// on.
+							if (mgr == focus.getCMgr()) {
+								if (linphone_address_weak_equal(marie.getIdentity().toC(),
+								                                linphone_participant_device_get_address(d))) {
+									// The organizer will not offer video streams in its INVITE to join a conference if
+									// the policy doesn't allow it
+									if (!initiate_video) {
+										video_enabled = FALSE;
+									} else {
+										video_enabled = TRUE;
+									}
+								} else {
+									// The participants will not accept video streams to answer the conference server
+									// INVITE to join a conference if the policy doesn't allow it
+									if (!accept_video) {
+										video_enabled = FALSE;
+									} else {
+										video_enabled = TRUE;
+									}
+								}
+							}
+
+							if (enable_video) {
+								if (linphone_conference_is_me(conference, linphone_participant_device_get_address(d))) {
+									BC_ASSERT_TRUE(linphone_participant_device_get_stream_availability(
+									                   d, LinphoneStreamTypeVideo) == video_enabled);
+								} else {
+									bool_t video_available =
+									    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo);
+									LinphoneMediaDirection video_direction =
+									    linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo);
+									BC_ASSERT_TRUE(video_available ==
+									               (((video_direction == LinphoneMediaDirectionSendOnly) ||
+									                 (video_direction == LinphoneMediaDirectionSendRecv)) &&
+									                video_enabled));
+								}
+							} else {
+								BC_ASSERT_FALSE(
+								    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+							}
+						}
+
+						if (devices) {
+							bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+						}
+					}
+				}
+			}
+
+			if (enable_video) {
+				LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
+				BC_ASSERT_PTR_NOT_NULL(pauline_call);
+
+				Address paulineAddr = pauline.getIdentity();
+				LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineAddr.toC());
+				BC_ASSERT_PTR_NOT_NULL(focus_call);
+
+				LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(pauline.getLc());
+				bool_t enable = !!!linphone_video_activation_policy_get_automatically_accept(pol);
+				linphone_video_activation_policy_unref(pol);
+
+				LinphoneAddress *paulineUri = linphone_address_new(linphone_core_get_identity(pauline.getLc()));
+				LinphoneConference *paulineConference =
+				    linphone_core_search_conference(pauline.getLc(), NULL, paulineUri, confAddr, NULL);
+				linphone_address_unref(paulineUri);
+				BC_ASSERT_PTR_NOT_NULL(paulineConference);
+
+				for (int i = 0; i < 4; i++) {
+					set_video_settings_in_conference(focus.getCMgr(), pauline.getCMgr(), members, confAddr, enable,
+					                                 LinphoneMediaDirectionSendRecv, enable,
+					                                 LinphoneMediaDirectionSendRecv);
+
+					if (paulineConference) {
+						bctbx_list_t *devices = linphone_conference_get_participant_device_list(paulineConference);
+						for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+							LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+							if (enable) {
+								if (linphone_conference_is_me(paulineConference,
+								                              linphone_participant_device_get_address(d))) {
+									BC_ASSERT_TRUE(linphone_participant_device_get_stream_availability(
+									    d, LinphoneStreamTypeVideo));
+								} else {
+									BC_ASSERT_TRUE(linphone_participant_device_get_stream_availability(
+									                   d, LinphoneStreamTypeVideo) ==
+									               (linphone_participant_device_get_stream_capability(
+									                    d, LinphoneStreamTypeVideo) == LinphoneMediaDirectionSendRecv));
+								}
+							} else {
+								BC_ASSERT_TRUE(linphone_participant_device_get_stream_availability(
+								                   d, LinphoneStreamTypeVideo) == enable);
+							}
+						}
+
+						if (devices) {
+							bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+						}
+					}
+					// Wait a little bit
+					wait_for_list(coresList, NULL, 0, 1000);
+
+					enable = !enable;
+				}
+			}
+
+			focus_stat = focus.getStats();
+			for (auto mgr : members) {
+				LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+				BC_ASSERT_PTR_NOT_NULL(call);
+				if (call) {
+					ms_message("%s is terminating call with %s", linphone_core_get_identity(mgr->lc),
+					           linphone_core_get_identity(focus.getLc()));
+					linphone_call_terminate(call);
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList,
+					                             &mgr->stat.number_of_LinphoneConferenceStateTerminationPending, 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+					                             liblinphone_tester_sip_timeout));
+
+					LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+					LinphoneConference *pconference =
+					    linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+					BC_ASSERT_PTR_NULL(pconference);
+					linphone_address_unref(uri);
+				}
+			}
+
+			int members_no = static_cast<int>(members.size());
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+			                             focus_stat.number_of_LinphoneCallEnd + members_no,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+			                             focus_stat.number_of_LinphoneCallReleased + members_no,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionTerminated,
+			                             focus_stat.number_of_LinphoneSubscriptionTerminated + members_no,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+			                             focus_stat.number_of_participants_removed + members_no,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+			                             focus_stat.number_of_participant_devices_removed + members_no,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+			                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+			BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+			                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+			BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+			                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+			for (auto mgr : {focus.getCMgr()}) {
+				LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+				BC_ASSERT_PTR_NOT_NULL(pconference);
+				if (pconference) {
+					BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), 0, int, "%0d");
+					bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+					BC_ASSERT_EQUAL(bctbx_list_size(devices), 0, size_t, "%zu");
+					if (devices) {
+						bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+					}
+					BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				}
+			}
+
+			focus_stat = focus.getStats();
+			const bctbx_list_t *calls = linphone_core_get_calls(focus.getLc());
+			BC_ASSERT_EQUAL(bctbx_list_size(calls), 0, size_t, "%zu");
+
+			// Explicitely terminate conference as those on server are static by default
+			if (fconference) {
+				linphone_conference_terminate(fconference);
+			}
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &focus.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+		} else {
+			int members_no = static_cast<int>(members.size());
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+			                             focus_stat.number_of_LinphoneCallEnd + 4, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+			                             focus_stat.number_of_LinphoneCallReleased + 4,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+			                             focus_stat.number_of_participants_removed + 4,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+			                             focus_stat.number_of_participant_devices_removed + 4,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed, 4,
+			                             2 * liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed, 4,
+			                             liblinphone_tester_sip_timeout));
+
+			for (auto mgr : participants) {
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			ms_message("%s is terminating call with %s", linphone_core_get_identity(marie.getLc()),
+			           linphone_core_get_identity(focus.getLc()));
+			LinphoneCall *call = linphone_core_get_call_by_remote_address2(marie.getLc(), focus.getCMgr()->identity);
+			linphone_call_terminate(call);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+			                             focus_stat.number_of_LinphoneCallEnd + members_no,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+			                             focus_stat.number_of_LinphoneCallReleased + members_no,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+			                             focus_stat.number_of_participants_removed + members_no,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+			                             focus_stat.number_of_participant_devices_removed + members_no,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		for (auto mgr : members) {
+			const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+			BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 1, unsigned int, "%u");
+
+			bctbx_list_t *mgr_focus_call_log =
+			    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+			if (mgr_focus_call_log) {
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u");
+				for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+					LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				}
+				bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+			}
+			check_conference_info(
+			    mgr, confAddr, marie.getCMgr(), (mgr == marie.getCMgr()) ? 5 : participant_conference_info_participants,
+			    0, 0, initialSubject, ((accept && send_ics) || (mgr == marie.getCMgr())) ? description : NULL, 0,
+			    LinphoneConferenceInfoStateNew);
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_simple_conference_dial_out(void) {
+	LinphoneVideoActivationPolicy *pol = linphone_factory_create_video_activation_policy(linphone_factory_get());
+	linphone_video_activation_policy_set_automatically_accept(pol, FALSE);
+	linphone_video_activation_policy_set_automatically_initiate(pol, FALSE);
+	create_conference_dial_out_base(FALSE, LinphoneConferenceLayoutActiveSpeaker, pol, FALSE, FALSE,
+	                                LinphoneConferenceParticipantListTypeClosed, TRUE, FALSE);
+	linphone_video_activation_policy_unref(pol);
+}
+
+static void create_simple_conference_dial_out_and_ics(void) {
+	LinphoneVideoActivationPolicy *pol = linphone_factory_create_video_activation_policy(linphone_factory_get());
+	linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+	linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+	create_conference_dial_out_base(TRUE, LinphoneConferenceLayoutGrid, pol, TRUE, TRUE,
+	                                LinphoneConferenceParticipantListTypeOpen, TRUE, FALSE);
+	linphone_video_activation_policy_unref(pol);
+}
+
+static void create_simple_conference_dial_out_with_calls_declined(void) {
+	LinphoneVideoActivationPolicy *pol = linphone_factory_create_video_activation_policy(linphone_factory_get());
+	linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+	linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+	create_conference_dial_out_base(FALSE, LinphoneConferenceLayoutGrid, pol, TRUE, TRUE,
+	                                LinphoneConferenceParticipantListTypeOpen, FALSE, FALSE);
+	linphone_video_activation_policy_unref(pol);
+}
+
+static void create_simple_conference_dial_out_participant_codec_mismatch(void) {
+	LinphoneVideoActivationPolicy *pol = linphone_factory_create_video_activation_policy(linphone_factory_get());
+	linphone_video_activation_policy_set_automatically_accept(pol, FALSE);
+	linphone_video_activation_policy_set_automatically_initiate(pol, FALSE);
+	create_conference_dial_out_base(FALSE, LinphoneConferenceLayoutActiveSpeaker, pol, FALSE, FALSE,
+	                                LinphoneConferenceParticipantListTypeClosed, TRUE, TRUE);
+	linphone_video_activation_policy_unref(pol);
+}
+
+static void create_simple_conference_dial_out_with_video_not_accepted(void) {
+	LinphoneVideoActivationPolicy *pol = linphone_factory_create_video_activation_policy(linphone_factory_get());
+	linphone_video_activation_policy_set_automatically_accept(pol, FALSE);
+	linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+	create_conference_dial_out_base(FALSE, LinphoneConferenceLayoutActiveSpeaker, pol, FALSE, FALSE,
+	                                LinphoneConferenceParticipantListTypeClosed, TRUE, FALSE);
+	linphone_video_activation_policy_unref(pol);
+}
+
+static void create_simple_conference_dial_out_with_video_not_initiated(void) {
+	LinphoneVideoActivationPolicy *pol = linphone_factory_create_video_activation_policy(linphone_factory_get());
+	linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+	linphone_video_activation_policy_set_automatically_initiate(pol, FALSE);
+	create_conference_dial_out_base(FALSE, LinphoneConferenceLayoutGrid, pol, FALSE, FALSE,
+	                                LinphoneConferenceParticipantListTypeClosed, TRUE, FALSE);
+	linphone_video_activation_policy_unref(pol);
+}
+
+static void create_simple_conference_dial_out_organizer_codec_mismatch(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(berthe);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                 berthe.getCMgr()}) {
+			if (mgr == marie.getCMgr()) {
+				disable_all_audio_codecs_except_one(mgr->lc, "pcmu", -1);
+			} else {
+				disable_all_audio_codecs_except_one(mgr->lc, "pcma", -1);
+			}
+
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		stats focus_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+
+		std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(),    pauline.getCMgr(),
+		                                                laure.getCMgr(), michelle.getCMgr(), berthe.getCMgr()};
+		std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(),
+		                                         michelle.getCMgr(), berthe.getCMgr()};
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                                              berthe.getCMgr()};
+
+		const char *initialSubject = "Schedule of the trip towards the top of Europe";
+		const char *description = "To the Goutier mountain hut!!!! :-)";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr =
+		    create_conference_on_server(focus, marie, participantList, -1, -1, initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreationFailed,
+		                             focus_stat.number_of_LinphoneConferenceStateCreationFailed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+		                              marie_stat.number_of_LinphoneConferenceStateCreated + 1, 3000));
+		BC_ASSERT_FALSE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                              focus_stat.number_of_LinphoneCallIncomingReceived + 1, 1000));
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NULL(fconference);
+
+		if (confAddr) linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_simple_conference_dial_out_with_some_calls_declined_base(LinphoneReason reason) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(berthe);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                 berthe.getCMgr()}) {
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, LinphoneConferenceLayoutActiveSpeaker);
+			}
+
+			enable_stun_in_core(mgr, TRUE, TRUE);
+			linphone_core_manager_wait_for_stun_resolution(mgr);
+
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+		linphone_core_set_conference_participant_list_type(focus.getLc(), LinphoneConferenceParticipantListTypeOpen);
+
+		stats focus_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+
+		std::list<LinphoneCoreManager *> active_participants{pauline.getCMgr(), michelle.getCMgr()};
+		std::list<LinphoneCoreManager *> declining_participants{laure.getCMgr(), berthe.getCMgr()};
+		std::list<LinphoneCoreManager *> participants = active_participants;
+		for (auto mgr : declining_participants) {
+			participants.push_back(mgr);
+		}
+
+		std::list<LinphoneCoreManager *> all_active_participants = active_participants;
+		all_active_participants.push_back(marie.getCMgr());
+
+		std::list<LinphoneCoreManager *> conference_members = all_active_participants;
+		conference_members.push_back(focus.getCMgr());
+
+		const char *initialSubject = "Team building hike to the mountain hut";
+		const char *description = "Having fun!!!! :-)";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr =
+		    create_conference_on_server(focus, marie, participantList, -1, -1, initialSubject, description, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallOutgoingInit,
+		                             marie_stat.number_of_LinphoneCallOutgoingInit + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingInit,
+		                             focus_stat.number_of_LinphoneCallOutgoingInit + 4,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : participants) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+		                             marie_stat.number_of_LinphoneCallUpdating + 1, 20000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+		                             marie_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+		                             marie_stat.number_of_LinphoneSubscriptionOutgoingProgress + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+		                             marie_stat.number_of_LinphoneSubscriptionActive + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_NotifyReceived,
+		                             marie_stat.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+		LinphoneConference *oconference = linphone_core_search_conference_2(marie.getLc(), confAddr);
+		if (BC_ASSERT_PTR_NOT_NULL(oconference)) {
+			BC_ASSERT_EQUAL(linphone_conference_get_participant_count(oconference), 4, int, "%0d");
+			bctbx_list_t *devices = linphone_conference_get_participant_device_list(oconference);
+			BC_ASSERT_EQUAL(bctbx_list_size(devices), 5, size_t, "%zu");
+			if (devices) {
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			}
+		}
+
+		if (confAddr) {
+			for (auto mgr : participants) {
+				check_conference_info(mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject, NULL, 0,
+				                      LinphoneConferenceInfoStateNew);
+
+				LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+				BC_ASSERT_PTR_NOT_NULL(pcall);
+				if (pcall) {
+					LinphoneCallLog *call_log = linphone_call_get_call_log(pcall);
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+					if (std::find(active_participants.cbegin(), active_participants.cend(), mgr) !=
+					    active_participants.cend()) {
+						linphone_call_accept(pcall);
+					} else {
+						linphone_call_decline(pcall, reason);
+					}
+				}
+			}
+		}
+
+		for (auto mgr : active_participants) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdatedByRemote, 1, 20000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+
+			check_conference_info(mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject, NULL, 0,
+			                      LinphoneConferenceInfoStateNew);
+
+			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pcall);
+			if (pcall) {
+				LinphoneCallLog *call_log = linphone_call_get_call_log(pcall);
+				BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log);
+				if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) {
+					BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_conference_info_get_organizer(call_log_info),
+					                                           marie.getCMgr()->identity));
+					BC_ASSERT_TRUE(
+					    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
+
+					const bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
+					// Original participants + Marie who joined the conference
+					BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 5, size_t, "%zu");
+
+					BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0,
+					                         long long, "%lld");
+					const int duration_m = linphone_conference_info_get_duration(call_log_info);
+					BC_ASSERT_EQUAL(duration_m, 0, int, "%d");
+					if (initialSubject) {
+						BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(call_log_info), initialSubject);
+					} else {
+						BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(call_log_info));
+					}
+					BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(call_log_info));
+				}
+			}
+		}
+
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdating,
+		                  focus_stat.number_of_LinphoneCallUpdating + static_cast<int>(active_participants.size()),
+		                  liblinphone_tester_sip_timeout) +
+		    1);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning +
+		                                 2 * static_cast<int>(active_participants.size() + 1),
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived +
+		                                 static_cast<int>(active_participants.size()) + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive +
+		                                 static_cast<int>(active_participants.size()) + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + 5, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 5,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined +
+		                                 static_cast<int>(all_active_participants.size()),
+		                             liblinphone_tester_sip_timeout));
+
+		// Participants that declined the call
+		for (auto mgr : declining_participants) {
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+		}
+
+		if (reason == LinphoneReasonBusy) {
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallError,
+			                  focus_stat.number_of_LinphoneCallError + static_cast<int>(declining_participants.size()),
+			                  liblinphone_tester_sip_timeout));
+			BC_ASSERT_FALSE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+			                              marie_stat.number_of_participants_removed + 1, 3000));
+			BC_ASSERT_FALSE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+			                              focus_stat.number_of_participants_removed + 1, 1000));
+		} else {
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+			                  focus_stat.number_of_LinphoneCallEnd + static_cast<int>(declining_participants.size()),
+			                  liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+			                             marie_stat.number_of_participants_removed + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+			                             focus_stat.number_of_participants_removed + 2,
+			                             liblinphone_tester_sip_timeout));
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+		                             marie_stat.number_of_participant_devices_removed + 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                  focus_stat.number_of_LinphoneCallReleased + static_cast<int>(declining_participants.size()),
+		                  liblinphone_tester_sip_timeout));
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : all_active_participants) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
+		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conference_members,
+		                            focus.getCMgr(), memberList, confAddr, TRUE);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(15), [] {
+			return false;
+		});
+
+		for (auto mgr : conference_members) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				size_t no_participants = 0;
+				if (mgr == focus.getCMgr()) {
+					no_participants = all_active_participants.size();
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = active_participants.size();
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+					BC_ASSERT_TRUE(check_ice(mgr, focus.getCMgr(), LinphoneIceStateHostConnection));
+
+					LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(mgr->lc);
+					bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+					linphone_video_activation_policy_unref(pol);
+
+					int no_streams_audio = 1;
+					int no_streams_video = (enabled) ? (static_cast<int>(all_active_participants.size()) + 1) : 0;
+					int no_streams_text = 0;
+
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						_linphone_call_check_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						_linphone_call_check_nb_streams(ccall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants_list = linphone_conference_get_participant_list(pconference);
+				if (reason == LinphoneReasonBusy) {
+					no_participants += declining_participants.size();
+				}
+				BC_ASSERT_EQUAL(bctbx_list_size(participants_list), no_participants, size_t, "%zu");
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+				                static_cast<int>(no_participants), int, "%0d");
+				for (bctbx_list_t *itp = participants_list; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants_list, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), all_active_participants.size(), size_t, "%zu");
+				for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+					LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+					if (linphone_conference_is_me(pconference, linphone_participant_device_get_address(d))) {
+						BC_ASSERT_TRUE(linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+					} else {
+						BC_ASSERT_TRUE(
+						    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) ==
+						    (linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+						     LinphoneMediaDirectionSendRecv));
+					}
+				}
+
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+			}
+		}
+
+		LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(pauline_call);
+
+		Address paulineAddr = pauline.getIdentity();
+		LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineAddr.toC());
+		BC_ASSERT_PTR_NOT_NULL(focus_call);
+
+		LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(pauline.getLc());
+		bool_t enable = !!!linphone_video_activation_policy_get_automatically_initiate(pol);
+		linphone_video_activation_policy_unref(pol);
+
+		LinphoneAddress *paulineUri = linphone_address_new(linphone_core_get_identity(pauline.getLc()));
+		LinphoneConference *paulineConference =
+		    linphone_core_search_conference(pauline.getLc(), NULL, paulineUri, confAddr, NULL);
+		linphone_address_unref(paulineUri);
+		BC_ASSERT_PTR_NOT_NULL(paulineConference);
+
+		for (int i = 0; i < 4; i++) {
+			set_video_settings_in_conference(focus.getCMgr(), pauline.getCMgr(), all_active_participants, confAddr,
+			                                 enable, LinphoneMediaDirectionSendRecv, enable,
+			                                 LinphoneMediaDirectionSendRecv);
+
+			if (paulineConference) {
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(paulineConference);
+				for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+					LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+					if (enable) {
+						if (linphone_conference_is_me(paulineConference, linphone_participant_device_get_address(d))) {
+							BC_ASSERT_TRUE(
+							    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+						} else {
+							BC_ASSERT_TRUE(
+							    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) ==
+							    (linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+							     LinphoneMediaDirectionSendRecv));
+						}
+					} else {
+						BC_ASSERT_TRUE(
+						    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) == enable);
+					}
+				}
+
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+			}
+			// Wait a little bit
+			wait_for_list(coresList, NULL, 0, 1000);
+
+			enable = !enable;
+		}
+
+		focus_stat = focus.getStats();
+		for (auto mgr : all_active_participants) {
+			LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				ms_message("%s is terminating call with %s", linphone_core_get_identity(mgr->lc),
+				           linphone_core_get_identity(focus.getLc()));
+				linphone_call_terminate(call);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				BC_ASSERT_PTR_NULL(pconference);
+				linphone_address_unref(uri);
+			}
+		}
+
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                  focus_stat.number_of_LinphoneCallEnd + static_cast<int>(all_active_participants.size()),
+		                  liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                  focus_stat.number_of_LinphoneCallReleased + static_cast<int>(all_active_participants.size()),
+		                  liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionTerminated,
+		                             focus_stat.number_of_LinphoneSubscriptionTerminated +
+		                                 static_cast<int>(all_active_participants.size()),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                  focus_stat.number_of_participants_removed + static_cast<int>(all_active_participants.size()),
+		                  liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed +
+		                                 static_cast<int>(all_active_participants.size()),
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_participant_devices_joined,
+		                static_cast<int>(all_active_participants.size()), int, "%d");
+		BC_ASSERT_EQUAL(marie.getStats().number_of_participant_devices_joined,
+		                static_cast<int>(all_active_participants.size()), int, "%d");
+
+		for (auto mgr : {focus.getCMgr()}) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+				                static_cast<int>((reason == LinphoneReasonBusy) ? declining_participants.size() : 0),
+				                int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 0, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+			}
+		}
+
+		focus_stat = focus.getStats();
+		const bctbx_list_t *calls = linphone_core_get_calls(focus.getLc());
+		BC_ASSERT_EQUAL(bctbx_list_size(calls), 0, size_t, "%zu");
+
+		// Explicitely terminate conference as those on server are static by default
+		if (fconference) {
+			linphone_conference_terminate(fconference);
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(), berthe.getCMgr()}) {
+			const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+			BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 1, unsigned int, "%u");
+
+			bctbx_list_t *mgr_focus_call_log =
+			    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+			if (mgr_focus_call_log) {
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u");
+				for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+					LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				}
+				bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+			}
+			check_conference_info(mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject,
+			                      (mgr == marie.getCMgr()) ? description : NULL, 0, LinphoneConferenceInfoStateNew);
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_simple_conference_dial_out_with_some_calls_declined(void) {
+	create_simple_conference_dial_out_with_some_calls_declined_base(LinphoneReasonDeclined);
+}
+
+static void create_simple_conference_dial_out_with_some_calls_busy(void) {
+	create_simple_conference_dial_out_with_some_calls_declined_base(LinphoneReasonBusy);
+}
+
+static void
+create_conference_with_late_participant_addition_base(time_t start_time,
+                                                      int duration,
+                                                      LinphoneConferenceLayout layout,
+                                                      LinphoneConferenceParticipantListType participant_list_type,
+                                                      bool_t accept,
+                                                      bool_t one_addition) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(berthe);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                 berthe.getCMgr()}) {
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, layout);
+			}
+
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+		linphone_core_set_conference_participant_list_type(focus.getLc(), participant_list_type);
+
+		stats focus_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
+		if (one_addition) {
+			participants.push_back(michelle.getCMgr());
+		}
+
+		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		const char *initialSubject = "Weekly recap";
+		const char *description = "What happened in the past week";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		auto members = participants;
+		members.push_back(marie.getCMgr());
+		auto conferenceMgrs = members;
+		conferenceMgrs.push_back(focus.getCMgr());
+
+		if (start_time < 0) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallOutgoingInit,
+			                             marie_stat.number_of_LinphoneCallOutgoingInit + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingInit,
+			                  focus_stat.number_of_LinphoneCallOutgoingInit + static_cast<int>(participants.size()),
+			                  liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+			                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			for (auto mgr : participants) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+		} else if (confAddr) {
+			for (auto mgr : members) {
+				LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+				linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionSendRecv);
+				if (mgr == laure.getCMgr()) {
+					linphone_call_params_enable_mic(new_params, FALSE);
+				}
+				linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+				linphone_call_params_unref(new_params);
+			}
+
+			for (auto mgr : members) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneConference *oconference = linphone_core_search_conference_2(marie.getLc(), confAddr);
+		if (BC_ASSERT_PTR_NOT_NULL(oconference)) {
+			BC_ASSERT_EQUAL(linphone_conference_get_participant_count(oconference),
+			                static_cast<int>(participants.size()), int, "%0d");
+			bctbx_list_t *devices = linphone_conference_get_participant_device_list(oconference);
+			BC_ASSERT_EQUAL(bctbx_list_size(devices), (participants.size() + 1), size_t, "%zu");
+			if (devices) {
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			}
+		}
+
+		if (confAddr) {
+			for (auto mgr : participants) {
+				check_conference_info(mgr, confAddr, marie.getCMgr(), members.size(), start_time, duration,
+				                      initialSubject, description, 0, LinphoneConferenceInfoStateNew);
+
+				LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+				BC_ASSERT_PTR_NOT_NULL(pcall);
+				if (pcall) {
+					LinphoneCallLog *call_log = linphone_call_get_call_log(pcall);
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+					linphone_call_accept(pcall);
+				}
+			}
+		}
+
+		for (auto mgr : participants) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+
+			check_conference_info(mgr, confAddr, marie.getCMgr(), members.size(), start_time, duration, initialSubject,
+			                      description, 0, LinphoneConferenceInfoStateNew);
+
+			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pcall);
+			if (pcall) {
+				LinphoneCallLog *call_log = linphone_call_get_call_log(pcall);
+				BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log);
+				if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) {
+					BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_conference_info_get_organizer(call_log_info),
+					                                           marie.getCMgr()->identity));
+					BC_ASSERT_TRUE(
+					    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
+
+					const bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
+					// Original participants + Marie who joined the conference
+					BC_ASSERT_EQUAL(bctbx_list_size(info_participants), static_cast<int>(members.size()), size_t,
+					                "%zu");
+
+					if (start_time > 0) {
+						BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(call_log_info), start_time,
+						                long long, "%lld");
+					}
+					const int duration_m = linphone_conference_info_get_duration(call_log_info);
+					BC_ASSERT_EQUAL(duration_m, ((duration < 0) ? 0 : duration), int, "%d");
+					if (initialSubject) {
+						BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(call_log_info), initialSubject);
+					} else {
+						BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(call_log_info));
+					}
+					BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(call_log_info), description);
+				}
+			}
+		}
+
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                  focus_stat.number_of_LinphoneCallStreamsRunning + static_cast<int>(participants.size() + 1),
+		                  liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+		                             marie_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+		                             marie_stat.number_of_LinphoneSubscriptionOutgoingProgress + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+		                             marie_stat.number_of_LinphoneSubscriptionActive + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_NotifyReceived,
+		                             marie_stat.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                  focus_stat.number_of_LinphoneSubscriptionIncomingReceived + static_cast<int>(members.size()),
+		                  liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + static_cast<int>(members.size()),
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + static_cast<int>(members.size()),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + static_cast<int>(members.size()),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + static_cast<int>(members.size()),
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : members) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
+		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
+		                            memberList, confAddr, TRUE);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(15), [] {
+			return false;
+		});
+
+		for (auto mgr : conferenceMgrs) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				int no_participants = 0;
+				if (mgr == focus.getCMgr()) {
+					no_participants = static_cast<int>(members.size());
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = static_cast<int>(participants.size());
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+
+					LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(mgr->lc);
+					bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+					linphone_video_activation_policy_unref(pol);
+
+					int no_streams_audio = 1;
+					int no_streams_video = (enabled) ? (static_cast<int>(members.size()) + 1) : 0;
+					int no_streams_text = 0;
+
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						_linphone_call_check_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						_linphone_call_check_nb_streams(ccall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), members.size(), size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+
+				LinphoneConference *conference = linphone_core_search_conference_2(mgr->lc, confAddr);
+				BC_ASSERT_PTR_NOT_NULL(conference);
+				if (conference) {
+					bctbx_list_t *devices = linphone_conference_get_participant_device_list(conference);
+					for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+						LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+						if (linphone_conference_is_me(conference, linphone_participant_device_get_address(d))) {
+							BC_ASSERT_TRUE(
+							    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+						} else {
+							BC_ASSERT_TRUE(
+							    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) ==
+							    (linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+							     LinphoneMediaDirectionSendRecv));
+						}
+					}
+
+					if (devices) {
+						bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+					}
+				}
+			}
+		}
+
+		focus_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		stats michelle_stat = michelle.getStats();
+		stats berthe_stat = berthe.getStats();
+		stats pauline_stat = pauline.getStats();
+		stats laure_stat = laure.getStats();
+
+		if (one_addition) {
+			linphone_conference_add_participant_2(oconference, berthe.getCMgr()->identity);
+		} else {
+			bctbx_list_t *addresses = NULL;
+			addresses = bctbx_list_append(addresses, berthe.getCMgr()->identity);
+			addresses = bctbx_list_append(addresses, michelle.getCMgr()->identity);
+			linphone_conference_add_participants_2(oconference, addresses);
+			bctbx_list_free(addresses);
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingInit,
+		                             focus_stat.number_of_LinphoneCallOutgoingInit + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingProgress,
+		                             focus_stat.number_of_LinphoneCallOutgoingProgress + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallIncomingReceived,
+		                             berthe_stat.number_of_LinphoneCallIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		if (!one_addition) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingInit,
+			                             focus_stat.number_of_LinphoneCallOutgoingInit + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingProgress,
+			                             focus_stat.number_of_LinphoneCallOutgoingProgress + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallIncomingReceived,
+			                             michelle_stat.number_of_LinphoneCallIncomingReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		LinphoneCall *berthe_call =
+		    linphone_core_get_call_by_remote_address2(berthe.getLc(), focus.getCMgr()->identity);
+		BC_ASSERT_PTR_NOT_NULL(berthe_call);
+
+		LinphoneCall *michelle_call =
+		    linphone_core_get_call_by_remote_address2(michelle.getLc(), focus.getCMgr()->identity);
+		BC_ASSERT_PTR_NOT_NULL(michelle_call);
+
+		int participant_added = ((one_addition) ? 1 : 2);
+
+		if (accept) {
+			if (berthe_call) {
+				linphone_call_accept(berthe_call);
+			}
+
+			conferenceMgrs.push_back(berthe.getCMgr());
+			members.push_back(berthe.getCMgr());
+			memberList.insert(std::make_pair(berthe.getCMgr(), LinphoneParticipantRoleListener));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat.number_of_LinphoneCallStreamsRunning + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallStreamsRunning,
+			                             berthe_stat.number_of_LinphoneCallStreamsRunning + 2,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneConferenceStateCreated,
+			                             berthe_stat.number_of_LinphoneConferenceStateCreated + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+			                             berthe_stat.number_of_LinphoneSubscriptionOutgoingProgress + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionActive,
+			                             berthe_stat.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_NotifyReceived,
+			                             berthe_stat.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+			if (!one_addition) {
+				if (michelle_call) {
+					linphone_call_accept(michelle_call);
+				}
+
+				conferenceMgrs.push_back(michelle.getCMgr());
+				members.push_back(michelle.getCMgr());
+				memberList.insert(std::make_pair(michelle.getCMgr(), LinphoneParticipantRoleListener));
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+				                             focus_stat.number_of_LinphoneCallStreamsRunning + 4,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallStreamsRunning,
+				                             michelle_stat.number_of_LinphoneCallStreamsRunning + 2,
+				                             liblinphone_tester_sip_timeout));
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated,
+				                             michelle_stat.number_of_LinphoneConferenceStateCreated + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(
+				    coresList, &michelle.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+				    michelle_stat.number_of_LinphoneSubscriptionOutgoingProgress + 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneSubscriptionActive,
+				                             michelle_stat.number_of_LinphoneSubscriptionActive + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_NotifyReceived,
+				                             michelle_stat.number_of_NotifyReceived + 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+			                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+			                             focus_stat.number_of_LinphoneSubscriptionActive + participant_added,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+			                             focus_stat.number_of_participants_added + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_added,
+			                             marie_stat.number_of_participants_added + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_added,
+			                             pauline_stat.number_of_participants_added + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participants_added,
+			                             laure_stat.number_of_participants_added + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			if (one_addition) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participants_added,
+				                             michelle_stat.number_of_participants_added + 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_alerting,
+			                             focus_stat.number_of_participant_devices_alerting + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_alerting,
+			                             marie_stat.number_of_participant_devices_alerting + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_alerting,
+			                             pauline_stat.number_of_participant_devices_alerting + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_alerting,
+			                             laure_stat.number_of_participant_devices_alerting + participant_added,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+			                             focus_stat.number_of_participant_devices_added + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_added,
+			                             marie_stat.number_of_participant_devices_added + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+			                             pauline_stat.number_of_participant_devices_added + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_added,
+			                             laure_stat.number_of_participant_devices_added + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+			                             focus_stat.number_of_participant_devices_joined + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_joined,
+			                             marie_stat.number_of_participant_devices_joined + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_joined,
+			                             pauline_stat.number_of_participant_devices_joined + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_joined,
+			                             laure_stat.number_of_participant_devices_joined + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			if (one_addition) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_alerting,
+				                             michelle_stat.number_of_participant_devices_alerting + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_added,
+				                             michelle_stat.number_of_participant_devices_added + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_participant_devices_joined,
+				                             michelle_stat.number_of_participant_devices_joined + 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+		} else {
+			if (berthe_call) {
+				linphone_call_decline(berthe_call, LinphoneReasonDeclined);
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallEnd,
+			                             berthe_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallReleased,
+			                             berthe_stat.number_of_LinphoneCallReleased + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			if (!one_addition) {
+				if (michelle_call) {
+					linphone_call_decline(michelle_call, LinphoneReasonDeclined);
+				}
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallEnd,
+				                             michelle_stat.number_of_LinphoneCallEnd + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneCallReleased,
+				                             michelle_stat.number_of_LinphoneCallReleased + 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+			                             focus_stat.number_of_LinphoneCallEnd + participant_added,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+			                             focus_stat.number_of_LinphoneCallReleased + participant_added,
+			                             liblinphone_tester_sip_timeout));
+		}
+		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
+		                            memberList, confAddr, TRUE);
+
+		LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(pauline_call);
+
+		Address paulineAddr = pauline.getIdentity();
+		LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineAddr.toC());
+		BC_ASSERT_PTR_NOT_NULL(focus_call);
+
+		LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(pauline.getLc());
+		bool_t enable = !!!linphone_video_activation_policy_get_automatically_initiate(pol);
+		linphone_video_activation_policy_unref(pol);
+
+		LinphoneAddress *paulineUri = linphone_address_new(linphone_core_get_identity(pauline.getLc()));
+		LinphoneConference *paulineConference =
+		    linphone_core_search_conference(pauline.getLc(), NULL, paulineUri, confAddr, NULL);
+		linphone_address_unref(paulineUri);
+		BC_ASSERT_PTR_NOT_NULL(paulineConference);
+
+		for (int i = 0; i < 4; i++) {
+			set_video_settings_in_conference(focus.getCMgr(), pauline.getCMgr(), members, confAddr, enable,
+			                                 LinphoneMediaDirectionSendRecv, enable, LinphoneMediaDirectionSendRecv);
+
+			if (paulineConference) {
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(paulineConference);
+				for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+					LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+					if (enable) {
+						if (linphone_conference_is_me(paulineConference, linphone_participant_device_get_address(d))) {
+							BC_ASSERT_TRUE(
+							    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+						} else {
+							BC_ASSERT_TRUE(
+							    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) ==
+							    (linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+							     LinphoneMediaDirectionSendRecv));
+						}
+					} else {
+						BC_ASSERT_TRUE(
+						    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) == enable);
+					}
+				}
+
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+			}
+			// Wait a little bit
+			wait_for_list(coresList, NULL, 0, 1000);
+
+			enable = !enable;
+		}
+
+		focus_stat = focus.getStats();
+		for (auto mgr : members) {
+			LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				ms_message("%s is terminating call with %s", linphone_core_get_identity(mgr->lc),
+				           linphone_core_get_identity(focus.getLc()));
+				linphone_call_terminate(call);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				BC_ASSERT_PTR_NULL(pconference);
+				linphone_address_unref(uri);
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                             focus_stat.number_of_LinphoneCallEnd + ((accept) ? 5 : 4),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                             focus_stat.number_of_LinphoneCallReleased + ((accept) ? 5 : 4),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionTerminated,
+		                             focus_stat.number_of_LinphoneSubscriptionTerminated + ((accept) ? 5 : 4),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                             focus_stat.number_of_participants_removed + ((accept) ? 5 : 4),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed + ((accept) ? 5 : 4),
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		for (auto mgr : {focus.getCMgr()}) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), 0, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 0, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+			}
+		}
+
+		focus_stat = focus.getStats();
+		const bctbx_list_t *calls = linphone_core_get_calls(focus.getLc());
+		BC_ASSERT_EQUAL(bctbx_list_size(calls), 0, size_t, "%zu");
+
+		// Explicitely terminate conference as those on server are static by default
+		if (fconference) {
+			linphone_conference_terminate(fconference);
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : members) {
+			const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+			BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 1, unsigned int, "%u");
+
+			bctbx_list_t *mgr_focus_call_log =
+			    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+			if (mgr_focus_call_log) {
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u");
+				for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+					LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				}
+				bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+			}
+
+			check_conference_info(
+			    mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject,
+			    ((!one_addition && (mgr == michelle.getCMgr())) || (mgr == berthe.getCMgr())) ? NULL : description, 0,
+			    LinphoneConferenceInfoStateNew);
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_conference_with_late_participant_addition(void) {
+	create_conference_with_late_participant_addition_base(ms_time(NULL), -1, LinphoneConferenceLayoutGrid,
+	                                                      LinphoneConferenceParticipantListTypeClosed, TRUE, TRUE);
+}
+
+static void create_conference_with_late_participant_addition_declined(void) {
+	create_conference_with_late_participant_addition_base(ms_time(NULL), -1, LinphoneConferenceLayoutActiveSpeaker,
+	                                                      LinphoneConferenceParticipantListTypeClosed, FALSE, TRUE);
+}
+
+static void create_simple_conference_dial_out_with_late_participant_addition(void) {
+	create_conference_with_late_participant_addition_base(-1, -1, LinphoneConferenceLayoutActiveSpeaker,
+	                                                      LinphoneConferenceParticipantListTypeOpen, TRUE, TRUE);
+}
+
+static void create_simple_conference_dial_out_with_many_late_participant_additions(void) {
+	create_conference_with_late_participant_addition_base(-1, -1, LinphoneConferenceLayoutGrid,
+	                                                      LinphoneConferenceParticipantListTypeOpen, TRUE, FALSE);
+}
+
+static void simple_dial_out_conference_with_no_payloads(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(berthe);
+
+		const bctbx_list_t *elem = linphone_core_get_audio_codecs(pauline.getLc());
+		disable_all_codecs(elem, pauline.getCMgr());
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		linphone_core_set_avpf_mode(focus.getCMgr()->lc, LinphoneAVPFEnabled);
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                 berthe.getCMgr()}) {
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		stats focus_stat = focus.getStats();
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                                              berthe.getCMgr()};
+
+		const char *initialSubject = "Schedule of the trip towards the top of Europe";
+		const char *description = "To the top of the Mont Blanc!!!! :-)";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr =
+		    create_conference_on_server(focus, marie, participantList, -1, -1, initialSubject, description, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		LinphoneConference *fconference =
+		    (confAddr) ? linphone_core_search_conference_2(focus.getLc(), confAddr) : NULL;
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		std::list<LinphoneCoreManager *> mgr_in_conference{marie.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                                                   berthe.getCMgr()};
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingInit,
+		                             focus_stat.number_of_LinphoneCallOutgoingInit + 5,
+		                             liblinphone_tester_sip_timeout));
+		for (auto mgr : participants) {
+			if (mgr == pauline.getCMgr()) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallError,
+				                             focus_stat.number_of_LinphoneCallError + 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+				                             focus_stat.number_of_LinphoneCallReleased + 1,
+				                             liblinphone_tester_sip_timeout));
+			} else {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+		}
+
+		if (confAddr) {
+			for (auto mgr : participants) {
+				LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+				if (mgr == pauline.getCMgr()) {
+					BC_ASSERT_PTR_NULL(pcall);
+				} else {
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						linphone_call_accept(pcall);
+					}
+				}
+			}
+		}
+
+		for (auto mgr : participants) {
+			if (mgr != pauline.getCMgr()) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,
+				                             liblinphone_tester_sip_timeout));
+
+				// If ICE is enabled, the addition to a conference may go through a resume of the call
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, 5000));
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+			}
+		}
+
+		focus_stat = focus.getStats();
+		for (auto mgr : {marie.getCMgr(), laure.getCMgr(), michelle.getCMgr(), berthe.getCMgr()}) {
+			LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				ms_message("%s is terminating call with %s", linphone_core_get_identity(mgr->lc),
+				           linphone_core_get_identity(focus.getLc()));
+				linphone_call_terminate(call);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				BC_ASSERT_PTR_NULL(pconference);
+				linphone_address_unref(uri);
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                             focus_stat.number_of_LinphoneCallEnd + 4, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                             focus_stat.number_of_LinphoneCallReleased + 4, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionTerminated,
+		                             focus_stat.number_of_LinphoneSubscriptionTerminated + 4,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                             focus_stat.number_of_participants_removed + 4, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed + 4,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		for (auto mgr : {focus.getCMgr()}) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), 0, int, "%0d");
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+			}
+		}
+
+		focus_stat = focus.getStats();
+		const bctbx_list_t *calls = linphone_core_get_calls(focus.getLc());
+		BC_ASSERT_EQUAL(bctbx_list_size(calls), 0, size_t, "%zu");
+
+		// Explicitely terminate conference as those on server are static by default
+		if (fconference) {
+			linphone_conference_terminate(fconference);
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void abort_call_to_ice_conference(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		const LinphoneConferenceLayout layout = LinphoneConferenceLayoutGrid;
+
+		bctbx_list_t *coresList = NULL;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, layout);
+			}
+
+			enable_stun_in_core(mgr, TRUE, TRUE);
+			linphone_core_manager_wait_for_stun_resolution(mgr);
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
+
+		time_t start_time = ms_time(NULL);
+		int duration = -1;
+		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		const char *initialSubject = "Test aborted ICE call";
+		const char *description = "Grenoble";
+
+		stats focus_stat = focus.getStats();
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			LinphoneCall *call =
+			    linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			linphone_call_params_unref(new_params);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
+			                             liblinphone_tester_sip_timeout));
+			if (call) {
+				linphone_call_terminate(call);
+			}
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived, 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd, 3, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased, 3,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			reset_counters(&mgr->stat);
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+		}
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			int no_streams_running = 3;
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, (no_streams_running - 1),
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, no_streams_running,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 3,
+		                             liblinphone_tester_sip_timeout));
+		int focus_no_streams_running = 9;
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + (focus_no_streams_running - 3),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + 3,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + 3, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + 3,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference);
+				int no_participants = 0;
+				if (start_time >= 0) {
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+					                (long long)start_time, long long, "%lld");
+				}
+				BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+				                (long long)end_time, long long, "%lld");
+				if (mgr == focus.getCMgr()) {
+					no_participants = 3;
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = 2;
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+					BC_ASSERT_TRUE(check_ice(mgr, focus.getCMgr(), LinphoneIceStateHostConnection));
+
+					LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(mgr->lc);
+					bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+					linphone_video_activation_policy_unref(pol);
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 3, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+			}
+		}
+
+		// Wait a little bit
+		wait_for_list(coresList, NULL, 0, 3000);
+
+		std::list<LinphoneCoreManager *> mgrsToRemove{pauline.getCMgr()};
+		mgrsToRemove.push_back(laure.getCMgr());
+
+		stats marie_stat = marie.getStats();
+
+		for (auto mgr : mgrsToRemove) {
+			LinphoneCall *call = linphone_core_get_current_call(mgr->lc);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				linphone_call_terminate(call);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				BC_ASSERT_PTR_NULL(pconference);
+				linphone_address_unref(uri);
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                             focus_stat.number_of_participants_removed + 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+		                             marie_stat.number_of_participants_removed + 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+		                             marie_stat.number_of_participant_devices_removed + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                marie_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateTerminated,
+		                marie_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateDeleted,
+		                marie_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr()}) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+				                ((mgr == focus.getCMgr()) ? 1 : 0), int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 1, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+			}
+		}
+
+		const bctbx_list_t *calls = linphone_core_get_calls(marie.getLc());
+		BC_ASSERT_EQUAL(bctbx_list_size(calls), 1, size_t, "%zu");
+
+		LinphoneCall *call = linphone_core_get_call_by_remote_address2(marie.getLc(), focus.getCMgr()->identity);
+		BC_ASSERT_PTR_NOT_NULL(call);
+		if (call) {
+			linphone_call_terminate(call);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &marie.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			// Explicitely terminate conference as those on server are static by default
+			LinphoneConference *pconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				linphone_conference_terminate(pconference);
+			}
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &focus.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+			BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 2, unsigned int, "%u");
+
+			bctbx_list_t *mgr_focus_call_log =
+			    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+			if (mgr_focus_call_log) {
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 2, unsigned int, "%u");
+				for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+					LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				}
+				bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void edit_simple_conference_base(bool_t from_organizer,
+                                        bool_t use_default_account,
+                                        bool_t enable_bundle_mode,
+                                        bool_t join,
+                                        bool_t enable_encryption,
+                                        bool_t server_restart,
+                                        bool_t role_changed) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference lise("lise_rc", focus.getIdentity());
+
+		LinphoneCoreManager *manager_editing = (from_organizer) ? marie.getCMgr() : laure.getCMgr();
+		linphone_core_enable_rtp_bundle(manager_editing->lc, enable_bundle_mode);
+		int default_index =
+		    linphone_config_get_int(linphone_core_get_config(manager_editing->lc), "sip", "default_proxy", 0);
+		LinphoneAccountParams *params = linphone_account_params_new_with_config(manager_editing->lc, default_index);
+		LinphoneAddress *alternative_address = linphone_address_new("sip:toto@sip.linphone.org");
+		linphone_account_params_set_identity_address(params, alternative_address);
+		LinphoneAccount *new_account = linphone_account_new(manager_editing->lc, params);
+		linphone_core_add_account(manager_editing->lc, new_account);
+		linphone_account_params_unref(params);
+		linphone_account_unref(new_account);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(lise);
+
+		setup_conference_info_cbs(marie.getCMgr());
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			if ((mgr != focus.getCMgr()) && enable_encryption) {
+				linphone_config_set_int(linphone_core_get_config(mgr->lc), "rtp", "accept_any_encryption", 1);
+				linphone_core_set_media_encryption_mandatory(mgr->lc, TRUE);
+				linphone_core_set_media_encryption(mgr->lc, LinphoneMediaEncryptionZRTP);
+			}
+		}
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		coresList = bctbx_list_append(coresList, lise.getLc());
+
+		std::list<LinphoneCoreManager *> invitedParticipants{pauline.getCMgr(), laure.getCMgr()};
+
+		time_t start_time = time(NULL) + 600; // Start in 10 minutes
+		int duration = 60;                    // minutes
+		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		const char *initialSubject = "Test characters: <S-F12><S-F11><S-F6> £$%§";
+		const char *description = "Testing characters";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : invitedParticipants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
+
+		char *uid = NULL;
+		unsigned int sequence = 0;
+		LinphoneConferenceInfo *conf_info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(conf_info);
+		if (conf_info) {
+			uid = ms_strdup(linphone_conference_info_get_ics_uid(conf_info));
+			BC_ASSERT_PTR_NOT_NULL(uid);
+			sequence = linphone_conference_info_get_ics_sequence(conf_info);
+
+			ms_message("%s is trying to update conference %s - adding %s", linphone_core_get_identity(marie.getLc()),
+			           conference_address_str, linphone_core_get_identity(lise.getLc()));
+
+			stats focus_stat = focus.getStats();
+			stats marie_stat = marie.getStats();
+			linphone_conference_info_set_subject(conf_info, initialSubject);
+			linphone_conference_info_set_description(conf_info, description);
+			LinphoneParticipantInfo *lise_participant_info = linphone_participant_info_new(lise.getCMgr()->identity);
+			linphone_participant_info_set_role(lise_participant_info, LinphoneParticipantRoleListener);
+			linphone_conference_info_add_participant_2(conf_info, lise_participant_info);
+			linphone_participant_info_unref(lise_participant_info);
+
+			if (role_changed) {
+				LinphoneParticipantRole current_pauline_role = participantList[pauline.getCMgr()];
+				LinphoneParticipantRole new_pauline_role = (current_pauline_role == LinphoneParticipantRoleListener)
+				                                               ? LinphoneParticipantRoleSpeaker
+				                                               : LinphoneParticipantRoleListener;
+				ms_message("%s is trying to update conference %s - changing role of %s from %s to %s",
+				           linphone_core_get_identity(marie.getLc()), conference_address_str,
+				           linphone_core_get_identity(pauline.getLc()),
+				           linphone_participant_role_to_string(current_pauline_role),
+				           linphone_participant_role_to_string(new_pauline_role));
+				LinphoneParticipantInfo *pauline_participant_info =
+				    linphone_participant_info_new(pauline.getCMgr()->identity);
+				linphone_participant_info_set_role(pauline_participant_info, new_pauline_role);
+				linphone_conference_info_add_participant_2(conf_info, pauline_participant_info);
+				linphone_participant_info_unref(pauline_participant_info);
+				participantList[pauline.getCMgr()] = new_pauline_role;
+			}
+
+			participants.push_back(lise.getCMgr());
+
+			const auto ics_participant_number = 3;
+			const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+			BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number, size_t, "%zu");
+
+			std::list<stats> participant_stats;
+			for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), lise.getCMgr()}) {
+				participant_stats.push_back(mgr->stat);
+			}
+
+			LinphoneConferenceScheduler *conference_scheduler =
+			    linphone_core_create_conference_scheduler(marie.getLc());
+			LinphoneConferenceSchedulerCbs *cbs =
+			    linphone_factory_create_conference_scheduler_cbs(linphone_factory_get());
+			linphone_conference_scheduler_cbs_set_state_changed(cbs, conference_scheduler_state_changed);
+			linphone_conference_scheduler_cbs_set_invitations_sent(cbs, conference_scheduler_invitations_sent);
+			linphone_conference_scheduler_add_callbacks(conference_scheduler, cbs);
+			linphone_conference_scheduler_cbs_unref(cbs);
+			linphone_conference_scheduler_set_info(conference_scheduler, conf_info);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateUpdating,
+			                             marie_stat.number_of_ConferenceSchedulerStateUpdating + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateReady,
+			                             marie_stat.number_of_ConferenceSchedulerStateReady + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+			                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+			                             focus_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+			                             focus_stat.number_of_LinphoneCallReleased + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			LinphoneChatRoomParams *chat_room_params = linphone_core_create_default_chat_room_params(marie.getLc());
+			linphone_chat_room_params_set_backend(chat_room_params, LinphoneChatRoomBackendBasic);
+			linphone_conference_scheduler_send_invitations(conference_scheduler, chat_room_params);
+			linphone_chat_room_params_unref(chat_room_params);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerInvitationsSent,
+			                             marie_stat.number_of_ConferenceSchedulerInvitationsSent + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), lise.getCMgr()}) {
+				auto old_stats = participant_stats.front();
+				if ((mgr != focus.getCMgr()) && (mgr != marie.getCMgr())) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceived,
+					                             old_stats.number_of_LinphoneMessageReceived + 1,
+					                             liblinphone_tester_sip_timeout));
+					if (!linphone_core_conference_ics_in_message_body_enabled(marie.getLc())) {
+						BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceivedWithFile,
+						                             old_stats.number_of_LinphoneMessageReceivedWithFile + 1,
+						                             liblinphone_tester_sip_timeout));
+					}
+
+					BC_ASSERT_PTR_NOT_NULL(mgr->stat.last_received_chat_message);
+					if (mgr->stat.last_received_chat_message != NULL) {
+						const string expected = ContentType::Icalendar.getMediaType();
+						BC_ASSERT_STRING_EQUAL(
+						    linphone_chat_message_get_content_type(mgr->stat.last_received_chat_message),
+						    expected.c_str());
+					}
+
+					bctbx_list_t *participant_chat_room_participants =
+					    bctbx_list_append(NULL, marie.getCMgr()->identity);
+					LinphoneChatRoom *pcr = linphone_core_search_chat_room(mgr->lc, NULL, mgr->identity, NULL,
+					                                                       participant_chat_room_participants);
+					bctbx_list_free(participant_chat_room_participants);
+					BC_ASSERT_PTR_NOT_NULL(pcr);
+					bctbx_list_t *chat_room_participants = bctbx_list_append(NULL, mgr->identity);
+
+					LinphoneChatRoom *cr = linphone_core_search_chat_room(
+					    marie.getLc(), NULL, marie.getCMgr()->identity, NULL, chat_room_participants);
+					bctbx_list_free(chat_room_participants);
+					BC_ASSERT_PTR_NOT_NULL(cr);
+
+					BC_ASSERT_EQUAL((int)bctbx_list_size(linphone_core_get_chat_rooms(mgr->lc)), 1, int, "%d");
+
+					if (cr) {
+						LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
+						BC_ASSERT_PTR_NOT_NULL(msg);
+
+						const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
+						BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
+						LinphoneContent *original_content = (LinphoneContent *)bctbx_list_get_data(original_contents);
+						if (BC_ASSERT_PTR_NOT_NULL(original_content)) {
+							LinphoneConferenceInfo *conf_info_from_original_content =
+							    linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(),
+							                                                                   original_content);
+							if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) {
+								BC_ASSERT_TRUE(linphone_address_weak_equal(
+								    marie.getCMgr()->identity,
+								    linphone_conference_info_get_organizer(conf_info_from_original_content)));
+								BC_ASSERT_TRUE(linphone_address_weak_equal(
+								    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
+
+								const bctbx_list_t *ics_participants =
+								    linphone_conference_info_get_participants(conf_info_from_original_content);
+								BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number, size_t,
+								                "%zu");
+
+								if (start_time > 0) {
+									BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(
+									                    conf_info_from_original_content),
+									                (long long)start_time, long long, "%lld");
+									if (end_time > 0) {
+										const int duration_m =
+										    linphone_conference_info_get_duration(conf_info_from_original_content);
+										const int duration_s = duration_m * 60;
+										BC_ASSERT_EQUAL(duration_s, (int)(end_time - start_time), int, "%d");
+										BC_ASSERT_EQUAL(duration_m, duration, int, "%d");
+									}
+								}
+								if (initialSubject) {
+									BC_ASSERT_STRING_EQUAL(
+									    linphone_conference_info_get_subject(conf_info_from_original_content),
+									    initialSubject);
+								} else {
+									BC_ASSERT_PTR_NULL(
+									    linphone_conference_info_get_subject(conf_info_from_original_content));
+								}
+								if (description) {
+									BC_ASSERT_STRING_EQUAL(
+									    linphone_conference_info_get_description(conf_info_from_original_content),
+									    description);
+								} else {
+									BC_ASSERT_PTR_NULL(
+									    linphone_conference_info_get_description(conf_info_from_original_content));
+								}
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid);
+								const unsigned int ics_sequence =
+								    linphone_conference_info_get_ics_sequence(conf_info_from_original_content);
+								int exp_sequence = 0;
+								if (mgr == lise.getCMgr()) {
+									exp_sequence = 0;
+								} else {
+									exp_sequence = (sequence + 1);
+								}
+
+								BC_ASSERT_EQUAL(ics_sequence, exp_sequence, int, "%d");
+
+								LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
+
+								if (mgr == lise.getCMgr()) {
+									exp_state = LinphoneConferenceInfoStateNew;
+								} else {
+									exp_state = LinphoneConferenceInfoStateUpdated;
+								}
+								BC_ASSERT_EQUAL(
+								    (int)linphone_conference_info_get_state(conf_info_from_original_content),
+								    (int)exp_state, int, "%d");
+
+								linphone_conference_info_unref(conf_info_from_original_content);
+							}
+						}
+						linphone_chat_message_unref(msg);
+					}
+				}
+				participant_stats.pop_front();
+			}
+			linphone_conference_info_unref(conf_info);
+			linphone_conference_scheduler_unref(conference_scheduler);
+		}
+
+		if (join) {
+			std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr()};
+			std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr()};
+
+			stats focus_stat = focus.getStats();
+			for (auto mgr : members) {
+				LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+				linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+				linphone_call_params_unref(new_params);
+			}
+
+			for (auto mgr : members) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+				                             liblinphone_tester_sip_timeout));
+				int no_streams_running = 2;
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating,
+				                             (no_streams_running - 1), liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning,
+				                             no_streams_running, liblinphone_tester_sip_timeout));
+				// Update to add to conference.
+				// If ICE is enabled, the addition to a conference may go through a resume of the call
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+				                             ((mgr == marie.getCMgr()) ? 3 : 2), liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, 5000));
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+			                             focus_stat.number_of_LinphoneCallIncomingReceived + 2,
+			                             liblinphone_tester_sip_timeout));
+			int focus_no_streams_running = 4;
+			// Update to end ICE negotiations
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+			                  focus_stat.number_of_LinphoneCallUpdatedByRemote + (focus_no_streams_running - 2),
+			                  liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running,
+			                             liblinphone_tester_sip_timeout));
+			// Update to add to conference.
+			// If ICE is enabled, the addition to a conference may go through a resume of the call
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+			                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+			                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 2, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+			                             focus_stat.number_of_LinphoneSubscriptionActive + 2, 5000));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+			                             focus_stat.number_of_participants_added + 2, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+			                             focus_stat.number_of_participant_devices_added + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+			                             focus_stat.number_of_participant_devices_joined + 2,
+			                             liblinphone_tester_sip_timeout));
+
+			std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+			for (const auto &member : members) {
+				try {
+					const auto &participantInfo = participantList.at(member);
+					memberList.insert(std::make_pair(member, participantInfo));
+				} catch (std::out_of_range &) {
+					if (member == marie.getCMgr()) {
+						memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+					} else {
+						ms_fatal("Unable to find active participant %s in the participant list",
+						         linphone_core_get_identity(member->lc));
+					}
+				}
+			}
+			wait_for_conference_streams({focus, marie, pauline, laure, michelle, lise}, conferenceMgrs, focus.getCMgr(),
+			                            memberList, confAddr, TRUE);
+
+			LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(fconference);
+
+			// wait bit more to detect side effect if any
+			CoreManagerAssert({focus, marie, pauline, laure, michelle, lise}).waitUntil(chrono::seconds(2), [] {
+				return false;
+			});
+
+			for (auto mgr : conferenceMgrs) {
+				LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+				BC_ASSERT_PTR_NOT_NULL(pconference);
+				if (pconference) {
+					const LinphoneConferenceParams *conference_params =
+					    linphone_conference_get_current_params(pconference);
+					int no_participants = 0;
+					if (start_time >= 0) {
+						BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+						                (long long)start_time, long long, "%lld");
+					}
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+					                (long long)end_time, long long, "%lld");
+
+					bctbx_list_t *participant_device_list =
+					    linphone_conference_get_participant_device_list(pconference);
+					BC_ASSERT_EQUAL(bctbx_list_size(participant_device_list), 2, size_t, "%zu");
+					for (bctbx_list_t *d_it = participant_device_list; d_it; d_it = bctbx_list_next(d_it)) {
+						LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(d_it);
+						BC_ASSERT_PTR_NOT_NULL(d);
+						if (d) {
+							BC_ASSERT_TRUE((!!linphone_participant_device_get_is_muted(d)) ==
+							               (linphone_address_weak_equal(linphone_participant_device_get_address(d),
+							                                            laure.getCMgr()->identity)));
+							linphone_participant_device_set_user_data(d, mgr->lc);
+							LinphoneParticipantDeviceCbs *cbs =
+							    linphone_factory_create_participant_device_cbs(linphone_factory_get());
+							linphone_participant_device_cbs_set_is_muted(cbs, on_muted_notified);
+							linphone_participant_device_add_callbacks(d, cbs);
+							linphone_participant_device_cbs_unref(cbs);
+						}
+					}
+					bctbx_list_free_with_data(participant_device_list,
+					                          (void (*)(void *))linphone_participant_device_unref);
+
+					if (mgr == focus.getCMgr()) {
+						no_participants = 2;
+						BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+					} else {
+						no_participants = 1;
+						BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+						LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+						BC_ASSERT_PTR_NOT_NULL(current_call);
+						if (current_call) {
+							BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+							                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+						}
+
+						LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(mgr->lc);
+						bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+						linphone_video_activation_policy_unref(pol);
+
+						int no_streams_audio = 1;
+						int no_streams_video = 3;
+						int no_active_streams_video = no_streams_video;
+						int no_streams_text = 0;
+
+						LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+						BC_ASSERT_PTR_NOT_NULL(pcall);
+						if (pcall) {
+							_linphone_call_check_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text);
+							_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
+							                                       no_streams_text);
+							const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+							const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+							const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+						}
+						LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+						BC_ASSERT_PTR_NOT_NULL(ccall);
+						if (ccall) {
+							_linphone_call_check_nb_streams(ccall, no_streams_audio, no_streams_video, no_streams_text);
+							_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_active_streams_video,
+							                                       no_streams_text);
+							const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+							const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+							const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+							BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+						}
+					}
+					BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int,
+					                "%0d");
+					BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+					LinphoneParticipant *me = linphone_conference_get_me(pconference);
+					BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+					               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+					BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+					bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+					for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+						LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+						BC_ASSERT_TRUE(linphone_participant_is_admin(p) ==
+						               linphone_address_weak_equal(linphone_participant_get_address(p),
+						                                           marie.getCMgr()->identity));
+					}
+					bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+					if (mgr != focus.getCMgr()) {
+						check_conference_ssrc(fconference, pconference);
+					}
+				}
+			}
+		}
+
+		if (server_restart) {
+			ms_message("%s is restarting", linphone_core_get_identity(focus.getLc()));
+			coresList = bctbx_list_remove(coresList, focus.getLc());
+			// Restart flexisip
+			focus.reStart();
+
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(focus.getLc(), pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_enable_video_capture(focus.getLc(), TRUE);
+			linphone_core_enable_video_display(focus.getLc(), TRUE);
+			coresList = bctbx_list_append(coresList, focus.getLc());
+		}
+
+		bool_t add = TRUE;
+		const char *subject = "Test characters: <S-F12><S-F11><S-F6> £$%§ (+edits)";
+		const char *description2 = "Testing characters (+edits)";
+
+		LinphoneAccount *editing_account = NULL;
+		if (use_default_account) {
+			editing_account = linphone_core_get_default_account(manager_editing->lc);
+		} else {
+			editing_account = linphone_core_lookup_known_account(manager_editing->lc, alternative_address);
+		}
+		BC_ASSERT_PTR_NOT_NULL(editing_account);
+		if (editing_account) {
+			LinphoneAccountParams *account_params =
+			    linphone_account_params_clone(linphone_account_get_params(editing_account));
+			linphone_account_params_enable_rtp_bundle(account_params, enable_bundle_mode);
+			linphone_account_set_params(editing_account, account_params);
+			linphone_account_params_unref(account_params);
+		}
+
+		for (int attempt = 0; attempt < 3; attempt++) {
+			ms_message("%s is trying to update conference %s - attempt %0d - %s %s",
+			           linphone_core_get_identity(manager_editing->lc), conference_address_str, attempt,
+			           (add) ? "adding" : "removing", linphone_core_get_identity(michelle.getLc()));
+
+			stats focus_stat = focus.getStats();
+			stats manager_editing_stat = manager_editing->stat;
+
+			std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr(), lise.getCMgr()};
+			LinphoneConferenceInfo *conf_info =
+			    linphone_core_find_conference_information_from_uri(manager_editing->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(conf_info);
+			if (conf_info) {
+				linphone_conference_info_set_subject(conf_info, subject);
+				linphone_conference_info_set_description(conf_info, description2);
+				if (add) {
+					linphone_conference_info_add_participant(conf_info, michelle.getCMgr()->identity);
+					participants.push_back(michelle.getCMgr());
+				} else {
+					linphone_conference_info_remove_participant(conf_info, michelle.getCMgr()->identity);
+				}
+
+				const auto ics_participant_number = ((add) ? 4 : 3) + ((join) ? 1 : 0);
+				const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+				BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number, size_t, "%zu");
+
+				std::list<stats> participant_stats;
+				for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(),
+				                 michelle.getCMgr(), lise.getCMgr()}) {
+					participant_stats.push_back(mgr->stat);
+				}
+
+				LinphoneConferenceScheduler *conference_scheduler =
+				    linphone_core_create_conference_scheduler(manager_editing->lc);
+				linphone_conference_scheduler_set_account(conference_scheduler, editing_account);
+				LinphoneConferenceSchedulerCbs *cbs =
+				    linphone_factory_create_conference_scheduler_cbs(linphone_factory_get());
+				linphone_conference_scheduler_cbs_set_state_changed(cbs, conference_scheduler_state_changed);
+				linphone_conference_scheduler_cbs_set_invitations_sent(cbs, conference_scheduler_invitations_sent);
+				linphone_conference_scheduler_add_callbacks(conference_scheduler, cbs);
+				linphone_conference_scheduler_cbs_unref(cbs);
+				linphone_conference_scheduler_set_info(conference_scheduler, conf_info);
+
+				if (use_default_account) {
+					BC_ASSERT_TRUE(wait_for_list(coresList,
+					                             &manager_editing->stat.number_of_ConferenceSchedulerStateUpdating,
+					                             manager_editing_stat.number_of_ConferenceSchedulerStateUpdating + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList,
+					                             &manager_editing->stat.number_of_ConferenceSchedulerStateReady,
+					                             manager_editing_stat.number_of_ConferenceSchedulerStateReady + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+					                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+					                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+					                             focus_stat.number_of_LinphoneCallEnd + 1,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+					                             focus_stat.number_of_LinphoneCallReleased + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					LinphoneChatRoomParams *chat_room_params =
+					    linphone_core_create_default_chat_room_params(manager_editing->lc);
+					linphone_chat_room_params_set_backend(chat_room_params, LinphoneChatRoomBackendBasic);
+					linphone_conference_scheduler_send_invitations(conference_scheduler, chat_room_params);
+					linphone_chat_room_params_unref(chat_room_params);
+
+					BC_ASSERT_TRUE(wait_for_list(coresList,
+					                             &manager_editing->stat.number_of_ConferenceSchedulerInvitationsSent,
+					                             manager_editing_stat.number_of_ConferenceSchedulerInvitationsSent + 1,
+					                             liblinphone_tester_sip_timeout));
+
+					for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(),
+					                 michelle.getCMgr(), lise.getCMgr()}) {
+						auto old_stats = participant_stats.front();
+						if ((mgr != focus.getCMgr()) && (mgr != manager_editing)) {
+							BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceived,
+							                             old_stats.number_of_LinphoneMessageReceived + 1,
+							                             liblinphone_tester_sip_timeout));
+							if (!linphone_core_conference_ics_in_message_body_enabled(manager_editing->lc)) {
+								BC_ASSERT_TRUE(wait_for_list(coresList,
+								                             &mgr->stat.number_of_LinphoneMessageReceivedWithFile,
+								                             old_stats.number_of_LinphoneMessageReceivedWithFile + 1,
+								                             liblinphone_tester_sip_timeout));
+							}
+
+							BC_ASSERT_PTR_NOT_NULL(mgr->stat.last_received_chat_message);
+							if (mgr->stat.last_received_chat_message != NULL) {
+								const string expected = ContentType::Icalendar.getMediaType();
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_chat_message_get_content_type(mgr->stat.last_received_chat_message),
+								    expected.c_str());
+							}
+
+							bctbx_list_t *participant_chat_room_participants =
+							    bctbx_list_append(NULL, manager_editing->identity);
+							LinphoneChatRoom *pcr = linphone_core_search_chat_room(mgr->lc, NULL, mgr->identity, NULL,
+							                                                       participant_chat_room_participants);
+							bctbx_list_free(participant_chat_room_participants);
+							BC_ASSERT_PTR_NOT_NULL(pcr);
+							bctbx_list_t *chat_room_participants = bctbx_list_append(NULL, mgr->identity);
+
+							LinphoneChatRoom *cr = linphone_core_search_chat_room(
+							    manager_editing->lc, NULL, manager_editing->identity, NULL, chat_room_participants);
+							bctbx_list_free(chat_room_participants);
+							BC_ASSERT_PTR_NOT_NULL(cr);
+
+							int number_chat_rooms = 0;
+							if (mgr == marie.getCMgr()) {
+								number_chat_rooms = 3;
+							} else if (from_organizer || (mgr == michelle.getCMgr())) {
+								number_chat_rooms = 1;
+							} else {
+								number_chat_rooms = 2;
+							}
+							BC_ASSERT_EQUAL((int)bctbx_list_size(linphone_core_get_chat_rooms(mgr->lc)),
+							                number_chat_rooms, int, "%d");
+
+							if (cr) {
+								LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
+								BC_ASSERT_PTR_NOT_NULL(msg);
+
+								const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
+								BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
+								LinphoneContent *original_content =
+								    (LinphoneContent *)bctbx_list_get_data(original_contents);
+								if (BC_ASSERT_PTR_NOT_NULL(original_content)) {
+									LinphoneConferenceInfo *conf_info_from_original_content =
+									    linphone_factory_create_conference_info_from_icalendar_content(
+									        linphone_factory_get(), original_content);
+									if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) {
+										BC_ASSERT_TRUE(linphone_address_weak_equal(
+										    marie.getCMgr()->identity,
+										    linphone_conference_info_get_organizer(conf_info_from_original_content)));
+										BC_ASSERT_TRUE(linphone_address_weak_equal(
+										    confAddr,
+										    linphone_conference_info_get_uri(conf_info_from_original_content)));
+
+										const bctbx_list_t *ics_participants =
+										    linphone_conference_info_get_participants(conf_info_from_original_content);
+										BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number,
+										                size_t, "%zu");
+
+										if (start_time > 0) {
+											BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(
+											                    conf_info_from_original_content),
+											                (long long)start_time, long long, "%lld");
+											if (end_time > 0) {
+												const int duration_m = linphone_conference_info_get_duration(
+												    conf_info_from_original_content);
+												const int duration_s = duration_m * 60;
+												BC_ASSERT_EQUAL(duration_s, (int)(end_time - start_time), int, "%d");
+												BC_ASSERT_EQUAL(duration_m, duration, int, "%d");
+											}
+										}
+										if (subject) {
+											BC_ASSERT_STRING_EQUAL(
+											    linphone_conference_info_get_subject(conf_info_from_original_content),
+											    subject);
+										} else {
+											BC_ASSERT_PTR_NULL(
+											    linphone_conference_info_get_subject(conf_info_from_original_content));
+										}
+										if (description2) {
+											BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(
+											                           conf_info_from_original_content),
+											                       description2);
+										} else {
+											BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(
+											    conf_info_from_original_content));
+										}
+										BC_ASSERT_STRING_EQUAL(
+										    linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid);
+										const unsigned int ics_sequence =
+										    linphone_conference_info_get_ics_sequence(conf_info_from_original_content);
+										int exp_sequence = 0;
+										if (mgr == michelle.getCMgr()) {
+											if (add) {
+												exp_sequence = 0;
+											} else {
+												exp_sequence = 1;
+											}
+										} else if (mgr == lise.getCMgr()) {
+											exp_sequence = (sequence + attempt + 1);
+										} else {
+											exp_sequence = (sequence + attempt + 2);
+										}
+
+										BC_ASSERT_EQUAL(ics_sequence, exp_sequence, int, "%d");
+
+										LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
+
+										if (mgr == michelle.getCMgr()) {
+											if (add) {
+												exp_state = LinphoneConferenceInfoStateNew;
+											} else {
+												exp_state = LinphoneConferenceInfoStateCancelled;
+											}
+										} else {
+											exp_state = LinphoneConferenceInfoStateUpdated;
+										}
+										BC_ASSERT_EQUAL(
+										    (int)linphone_conference_info_get_state(conf_info_from_original_content),
+										    (int)exp_state, int, "%d");
+
+										linphone_conference_info_unref(conf_info_from_original_content);
+									}
+								}
+								linphone_chat_message_unref(msg);
+							}
+						}
+						participant_stats.pop_front();
+					}
+				} else {
+					BC_ASSERT_TRUE(wait_for_list(coresList,
+					                             &manager_editing->stat.number_of_ConferenceSchedulerStateError,
+					                             manager_editing_stat.number_of_ConferenceSchedulerStateError + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+				linphone_conference_scheduler_unref(conference_scheduler);
+
+				for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(),
+				                 michelle.getCMgr(), lise.getCMgr()}) {
+					LinphoneConferenceInfo *info =
+					    linphone_core_find_conference_information_from_uri(mgr->lc, confAddr);
+					if (!use_default_account && (mgr == michelle.getCMgr())) {
+						BC_ASSERT_PTR_NULL(info);
+					} else if (BC_ASSERT_PTR_NOT_NULL(info)) {
+
+						const char *exp_subject = NULL;
+						if (use_default_account) {
+							exp_subject = subject;
+						} else {
+							exp_subject = initialSubject;
+						}
+
+						const char *exp_description = NULL;
+						if (mgr != focus.getCMgr()) {
+							if (use_default_account) {
+								exp_description = description2;
+							} else {
+								exp_description = description;
+							}
+						}
+
+						unsigned int exp_sequence = 0;
+						LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
+						if (mgr == focus.getCMgr()) {
+							exp_sequence = 0;
+							exp_state = LinphoneConferenceInfoStateUpdated;
+						} else {
+							if (mgr == michelle.getCMgr()) {
+								if (add) {
+									exp_state = LinphoneConferenceInfoStateNew;
+								} else {
+									exp_state = LinphoneConferenceInfoStateCancelled;
+								}
+							} else if (mgr == lise.getCMgr()) {
+								exp_state = use_default_account ? LinphoneConferenceInfoStateUpdated
+								                                : LinphoneConferenceInfoStateNew;
+							} else {
+								exp_state = LinphoneConferenceInfoStateUpdated;
+							}
+							if (mgr == michelle.getCMgr()) {
+								if (add) {
+									exp_sequence = 0;
+								} else {
+									exp_sequence = 1;
+								}
+							} else if (mgr == lise.getCMgr()) {
+								exp_sequence = use_default_account ? (sequence + attempt + 1) : 0;
+							} else {
+								exp_sequence = use_default_account ? (sequence + attempt + 2) : 1;
+							}
+						}
+						check_conference_info(
+						    mgr, confAddr, marie.getCMgr(),
+						    ((use_default_account && add) ? 4 : 3) + ((join || (mgr == focus.getCMgr())) ? 1 : 0),
+						    start_time, duration, exp_subject, exp_description, exp_sequence, exp_state);
+
+						if (mgr != focus.getCMgr()) {
+							for (auto &p : participants) {
+								int exp_participant_sequence = 0;
+								// If not using the default account (which was used to create the conference), the
+								// conference scheduler errors out and Michelle is not added
+								if ((use_default_account) || (p != michelle.getCMgr())) {
+									if (!use_default_account) {
+										exp_participant_sequence = (p == lise.getCMgr()) ? 0 : 1;
+									} else if (p == michelle.getCMgr()) {
+										exp_participant_sequence = 0;
+									} else if (p == lise.getCMgr()) {
+										exp_participant_sequence = attempt + 1;
+									} else {
+										exp_participant_sequence = attempt + 2;
+									}
+									linphone_conference_info_check_participant(info, p->identity,
+									                                           exp_participant_sequence);
+								}
+							}
+							int exp_organizer_sequence = 0;
+							if (use_default_account) {
+								exp_organizer_sequence = attempt + 2;
+							} else {
+								exp_organizer_sequence = 1;
+							}
+							linphone_conference_info_check_organizer(info, exp_organizer_sequence);
+						}
+					}
+					if (info) {
+						linphone_conference_info_unref(info);
+					}
+				}
+				linphone_conference_info_unref(conf_info);
+			}
+			add = !add;
+		}
+		ms_free(conference_address_str);
+		ms_free(uid);
+		linphone_address_unref(alternative_address);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void organizer_edits_simple_conference(void) {
+	edit_simple_conference_base(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE);
+}
+static void organizer_edits_simple_conference_using_different_account(void) {
+	edit_simple_conference_base(TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE);
+}
+
+static void organizer_edits_simple_conference_while_active(void) {
+	edit_simple_conference_base(TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE);
+}
+
+static void participant_edits_simple_conference(void) {
+	edit_simple_conference_base(FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE);
+}
+
+static void participant_edits_simple_conference_using_different_account(void) {
+	edit_simple_conference_base(FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
+}
+
+static void organizer_edits_simple_conference_with_server_restart(void) {
+	edit_simple_conference_base(TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE);
+}
+
+static void conference_edition_with_participant_role_changed(void) {
+	edit_simple_conference_base(TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE);
+}
+
+static void conference_edition_with_simultaneous_participant_add_remove_base(bool_t codec_mismatch) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		linphone_core_enable_lime_x3dh(focus.getLc(), true);
+
+		ClientConference marie("marie_rc", focus.getIdentity(), true);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), true);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), true);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), true);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+
+		setup_conference_info_cbs(marie.getCMgr());
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_X3dhUserCreationSuccess, 1,
+		                             x3dhServer_creationTimeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_X3dhUserCreationSuccess, 1,
+		                             x3dhServer_creationTimeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_X3dhUserCreationSuccess, 1,
+		                             x3dhServer_creationTimeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_X3dhUserCreationSuccess, 1,
+		                             x3dhServer_creationTimeout));
+
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie.getLc()));
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(pauline.getLc()));
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(laure.getLc()));
+		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle.getLc()));
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr()}) {
+			if (codec_mismatch) {
+				if (mgr == marie.getCMgr()) {
+					disable_all_audio_codecs_except_one(mgr->lc, "pcmu", -1);
+				} else {
+					disable_all_audio_codecs_except_one(mgr->lc, "pcma", -1);
+				}
+			}
+		}
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), marie.getCMgr(), laure.getCMgr()};
+
+		time_t start_time = time(NULL) + 600; // Start in 10 minutes
+		int duration = 60;                    // minutes
+		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		const char *initialSubject = "Test characters: <S-F12><S-F11><S-F6> £$%§";
+		const char *description = "Testing characters";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		const char *subject = "Test characters: <S-F12><S-F11><S-F6> £$%§ (+edits)";
+		const char *description2 = "Testing characters (+edits)";
+
+		stats marie_stat = marie.getStats();
+		LinphoneAccount *editing_account = linphone_core_get_default_account(marie.getLc());
+		BC_ASSERT_PTR_NOT_NULL(editing_account);
+
+		char *uid = NULL;
+		unsigned int sequence = 0;
+		LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
+		if (BC_ASSERT_PTR_NOT_NULL(info)) {
+			uid = ms_strdup(linphone_conference_info_get_ics_uid(info));
+			BC_ASSERT_PTR_NOT_NULL(uid);
+			sequence = linphone_conference_info_get_ics_sequence(info);
+			linphone_conference_info_unref(info);
+		}
+
+		char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
+		ms_message("%s is trying to update conference %s - adding %s and removing %s",
+		           linphone_core_get_identity(marie.getLc()), conference_address_str,
+		           linphone_core_get_identity(michelle.getLc()), linphone_core_get_identity(laure.getLc()));
+		ms_free(conference_address_str);
+
+		stats focus_stat = focus.getStats();
+
+		LinphoneConferenceInfo *conf_info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
+		linphone_conference_info_set_subject(conf_info, subject);
+		linphone_conference_info_set_description(conf_info, description2);
+		linphone_conference_info_add_participant(conf_info, michelle.getCMgr()->identity);
+		linphone_conference_info_remove_participant(conf_info, laure.getCMgr()->identity);
+
+		const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+		BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participants.size(), size_t, "%zu");
+
+		std::list<stats> participant_stats;
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+			participant_stats.push_back(mgr->stat);
+		}
+
+		LinphoneConferenceScheduler *conference_scheduler = linphone_core_create_conference_scheduler(marie.getLc());
+		linphone_conference_scheduler_set_account(conference_scheduler, editing_account);
+		LinphoneConferenceSchedulerCbs *cbs = linphone_factory_create_conference_scheduler_cbs(linphone_factory_get());
+		linphone_conference_scheduler_cbs_set_state_changed(cbs, conference_scheduler_state_changed);
+		linphone_conference_scheduler_cbs_set_invitations_sent(cbs, conference_scheduler_invitations_sent);
+		linphone_conference_scheduler_add_callbacks(conference_scheduler, cbs);
+		linphone_conference_scheduler_cbs_unref(cbs);
+		linphone_conference_scheduler_set_info(conference_scheduler, conf_info);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateUpdating,
+		                             marie_stat.number_of_ConferenceSchedulerStateUpdating + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateReady,
+		                             marie_stat.number_of_ConferenceSchedulerStateReady + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                             focus_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                             focus_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
+
+		LinphoneChatRoomParams *chat_room_params = linphone_core_create_default_chat_room_params(marie.getLc());
+		linphone_chat_room_params_set_subject(chat_room_params, "Conference");
+		linphone_chat_room_params_enable_encryption(chat_room_params, TRUE);
+		linphone_chat_room_params_set_backend(chat_room_params, LinphoneChatRoomBackendFlexisipChat);
+		linphone_conference_scheduler_send_invitations(conference_scheduler, chat_room_params);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerInvitationsSent,
+		                             marie_stat.number_of_ConferenceSchedulerInvitationsSent + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+			auto old_stats = participant_stats.front();
+			if ((mgr != focus.getCMgr()) && (mgr != marie.getCMgr())) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceived,
+				                             old_stats.number_of_LinphoneMessageReceived + 1,
+				                             liblinphone_tester_sip_timeout));
+				if (!linphone_core_conference_ics_in_message_body_enabled(marie.getLc())) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceivedWithFile,
+					                             old_stats.number_of_LinphoneMessageReceivedWithFile + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				BC_ASSERT_PTR_NOT_NULL(mgr->stat.last_received_chat_message);
+				if (mgr->stat.last_received_chat_message != NULL) {
+					const string expected = ContentType::Icalendar.getMediaType();
+					BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_content_type(mgr->stat.last_received_chat_message),
+					                       expected.c_str());
+				}
+
+				bctbx_list_t *participant_chat_room_participants = bctbx_list_append(NULL, marie.getCMgr()->identity);
+				LinphoneChatRoom *pcr = linphone_core_search_chat_room(mgr->lc, chat_room_params, mgr->identity, NULL,
+				                                                       participant_chat_room_participants);
+				bctbx_list_free(participant_chat_room_participants);
+				BC_ASSERT_PTR_NOT_NULL(pcr);
+				bctbx_list_t *chat_room_participants = bctbx_list_append(NULL, mgr->identity);
+
+				LinphoneChatRoom *cr = linphone_core_search_chat_room(
+				    marie.getLc(), chat_room_params, marie.getCMgr()->identity, NULL, chat_room_participants);
+				bctbx_list_free(chat_room_participants);
+				BC_ASSERT_PTR_NOT_NULL(cr);
+
+				BC_ASSERT_EQUAL((int)bctbx_list_size(linphone_core_get_chat_rooms(mgr->lc)),
+				                (mgr == michelle.getCMgr()) ? 1 : 2, int, "%d");
+
+				if (cr) {
+					LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
+					BC_ASSERT_PTR_NOT_NULL(msg);
+
+					const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
+					BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
+					LinphoneContent *original_content = (LinphoneContent *)bctbx_list_get_data(original_contents);
+					if (BC_ASSERT_PTR_NOT_NULL(original_content)) {
+						LinphoneConferenceInfo *conf_info_from_original_content =
+						    linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(),
+						                                                                   original_content);
+						if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) {
+							BC_ASSERT_TRUE(linphone_address_weak_equal(
+							    marie.getCMgr()->identity,
+							    linphone_conference_info_get_organizer(conf_info_from_original_content)));
+							BC_ASSERT_TRUE(linphone_address_weak_equal(
+							    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
+
+							const bctbx_list_t *ics_participants =
+							    linphone_conference_info_get_participants(conf_info_from_original_content);
+							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participants.size(), size_t, "%zu");
+
+							if (start_time > 0) {
+								BC_ASSERT_EQUAL(
+								    (long long)linphone_conference_info_get_date_time(conf_info_from_original_content),
+								    (long long)start_time, long long, "%lld");
+								if (end_time > 0) {
+									const int duration_m =
+									    linphone_conference_info_get_duration(conf_info_from_original_content);
+									const int duration_s = duration_m * 60;
+									BC_ASSERT_EQUAL(duration_s, (int)(end_time - start_time), int, "%d");
+									BC_ASSERT_EQUAL(duration_m, duration, int, "%d");
+								}
+							}
+							if (subject) {
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_subject(conf_info_from_original_content), subject);
+							} else {
+								BC_ASSERT_PTR_NULL(
+								    linphone_conference_info_get_subject(conf_info_from_original_content));
+							}
+							if (description2) {
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_description(conf_info_from_original_content),
+								    description2);
+							} else {
+								BC_ASSERT_PTR_NULL(
+								    linphone_conference_info_get_description(conf_info_from_original_content));
+							}
+							BC_ASSERT_STRING_EQUAL(
+							    linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid);
+							const unsigned int ics_sequence =
+							    linphone_conference_info_get_ics_sequence(conf_info_from_original_content);
+							BC_ASSERT_EQUAL(ics_sequence, (mgr == michelle.getCMgr()) ? 0 : (sequence + 1), int, "%d");
+
+							LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
+							if (mgr == laure.getCMgr()) {
+								exp_state = LinphoneConferenceInfoStateCancelled;
+							} else if (mgr == michelle.getCMgr()) {
+								exp_state = LinphoneConferenceInfoStateNew;
+							} else {
+								exp_state = LinphoneConferenceInfoStateUpdated;
+							}
+							BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(conf_info_from_original_content),
+							                (int)exp_state, int, "%d");
+
+							linphone_conference_info_unref(conf_info_from_original_content);
+						}
+					}
+					linphone_chat_message_unref(msg);
+				}
+			}
+			participant_stats.pop_front();
+		}
+		linphone_chat_room_params_unref(chat_room_params);
+		linphone_conference_scheduler_unref(conference_scheduler);
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+			LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr);
+			if (BC_ASSERT_PTR_NOT_NULL(info)) {
+
+				const char *exp_subject = subject;
+
+				const char *exp_description = NULL;
+				if (mgr != focus.getCMgr()) {
+					exp_description = description2;
+				}
+
+				unsigned int exp_sequence = 0;
+				LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
+				if (mgr == focus.getCMgr()) {
+					exp_sequence = 0;
+					exp_state = LinphoneConferenceInfoStateUpdated;
+				} else {
+					exp_sequence = (mgr == michelle.getCMgr()) ? 0 : (sequence + 1);
+					if (mgr == laure.getCMgr()) {
+						exp_state = LinphoneConferenceInfoStateCancelled;
+					} else if (mgr == michelle.getCMgr()) {
+						exp_state = LinphoneConferenceInfoStateNew;
+					} else {
+						exp_state = LinphoneConferenceInfoStateUpdated;
+					}
+				}
+				check_conference_info(mgr, confAddr, marie.getCMgr(), participants.size(), start_time, duration,
+				                      exp_subject, exp_description, exp_sequence, exp_state);
+			}
+			if (info) {
+				linphone_conference_info_unref(info);
+			}
+		}
+		linphone_conference_info_unref(conf_info);
+		ms_free(uid);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void conference_edition_with_simultaneous_participant_add_remove(void) {
+	conference_edition_with_simultaneous_participant_add_remove_base(FALSE);
+}
+
+static void conference_edition_with_organizer_codec_mismatch(void) {
+	conference_edition_with_simultaneous_participant_add_remove_base(TRUE);
+}
+
+static void conference_cancelled_through_edit_base(bool_t server_restart) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+
+		setup_conference_info_cbs(marie.getCMgr());
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+
+		std::list<LinphoneCoreManager *> participants{michelle.getCMgr(), pauline.getCMgr(), laure.getCMgr()};
+
+		time_t start_time = time(NULL) + 600; // Start in 10 minutes
+		int duration = 60;                    // minutes
+		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		const char *initialSubject = "Test characters: <S-F12><S-F11><S-F6> £$%§";
+		const char *description = "Testing characters";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		char *uid = NULL;
+		unsigned int sequence = 0;
+		LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
+		if (BC_ASSERT_PTR_NOT_NULL(info)) {
+			uid = ms_strdup(linphone_conference_info_get_ics_uid(info));
+			BC_ASSERT_PTR_NOT_NULL(uid);
+			sequence = linphone_conference_info_get_ics_sequence(info);
+			linphone_conference_info_unref(info);
+		}
+
+		stats focus_stat = focus.getStats();
+		stats manager_editing_stat = marie.getStats();
+
+		std::list<stats> participant_stats;
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+			participant_stats.push_back(mgr->stat);
+		}
+
+		char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
+		ms_message("%s is trying to change duration of conference %s", linphone_core_get_identity(marie.getLc()),
+		           conference_address_str);
+		LinphoneConferenceInfo *conf_info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
+		unsigned int new_duration = 2000;
+		linphone_conference_info_set_duration(conf_info, new_duration);
+
+		LinphoneConferenceScheduler *conference_scheduler = linphone_core_create_conference_scheduler(marie.getLc());
+		LinphoneAccount *editing_account = linphone_core_get_default_account(marie.getLc());
+		BC_ASSERT_PTR_NOT_NULL(editing_account);
+		linphone_conference_scheduler_set_account(conference_scheduler, editing_account);
+		LinphoneConferenceSchedulerCbs *cbs = linphone_factory_create_conference_scheduler_cbs(linphone_factory_get());
+		linphone_conference_scheduler_cbs_set_state_changed(cbs, conference_scheduler_state_changed);
+		linphone_conference_scheduler_cbs_set_invitations_sent(cbs, conference_scheduler_invitations_sent);
+		linphone_conference_scheduler_add_callbacks(conference_scheduler, cbs);
+		linphone_conference_scheduler_cbs_unref(cbs);
+		cbs = nullptr;
+		linphone_conference_scheduler_set_info(conference_scheduler, conf_info);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateUpdating,
+		                             manager_editing_stat.number_of_ConferenceSchedulerStateUpdating + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateReady,
+		                             manager_editing_stat.number_of_ConferenceSchedulerStateReady + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                             focus_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                             focus_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
+
+		LinphoneChatRoomParams *chat_room_params = linphone_core_create_default_chat_room_params(marie.getLc());
+		linphone_chat_room_params_set_backend(chat_room_params, LinphoneChatRoomBackendBasic);
+		linphone_conference_scheduler_send_invitations(conference_scheduler, chat_room_params);
+		linphone_chat_room_params_unref(chat_room_params);
+		chat_room_params = nullptr;
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerInvitationsSent,
+		                             manager_editing_stat.number_of_ConferenceSchedulerInvitationsSent + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+			auto old_stats = participant_stats.front();
+			if ((mgr != focus.getCMgr()) && (mgr != marie.getCMgr())) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceived,
+				                             old_stats.number_of_LinphoneMessageReceived + 1,
+				                             liblinphone_tester_sip_timeout));
+				if (!linphone_core_conference_ics_in_message_body_enabled(marie.getLc())) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceivedWithFile,
+					                             old_stats.number_of_LinphoneMessageReceivedWithFile + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				BC_ASSERT_PTR_NOT_NULL(mgr->stat.last_received_chat_message);
+				if (mgr->stat.last_received_chat_message != NULL) {
+					const string expected = ContentType::Icalendar.getMediaType();
+					BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_content_type(mgr->stat.last_received_chat_message),
+					                       expected.c_str());
+				}
+
+				bctbx_list_t *participant_chat_room_participants = bctbx_list_append(NULL, marie.getCMgr()->identity);
+				LinphoneChatRoom *pcr = linphone_core_search_chat_room(mgr->lc, NULL, mgr->identity, NULL,
+				                                                       participant_chat_room_participants);
+				bctbx_list_free(participant_chat_room_participants);
+				BC_ASSERT_PTR_NOT_NULL(pcr);
+				bctbx_list_t *chat_room_participants = bctbx_list_append(NULL, mgr->identity);
+
+				LinphoneChatRoom *cr = linphone_core_search_chat_room(marie.getLc(), NULL, marie.getCMgr()->identity,
+				                                                      NULL, chat_room_participants);
+				bctbx_list_free(chat_room_participants);
+				BC_ASSERT_PTR_NOT_NULL(cr);
+
+				BC_ASSERT_EQUAL((int)bctbx_list_size(linphone_core_get_chat_rooms(mgr->lc)), 1, int, "%d");
+
+				if (cr) {
+					LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
+					BC_ASSERT_PTR_NOT_NULL(msg);
+
+					const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
+					BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
+					LinphoneContent *original_content = (LinphoneContent *)bctbx_list_get_data(original_contents);
+					if (BC_ASSERT_PTR_NOT_NULL(original_content)) {
+						LinphoneConferenceInfo *conf_info_from_original_content =
+						    linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(),
+						                                                                   original_content);
+						if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) {
+							BC_ASSERT_TRUE(linphone_address_weak_equal(
+							    marie.getCMgr()->identity,
+							    linphone_conference_info_get_organizer(conf_info_from_original_content)));
+							BC_ASSERT_TRUE(linphone_address_weak_equal(
+							    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
+
+							const bctbx_list_t *ics_participants =
+							    linphone_conference_info_get_participants(conf_info_from_original_content);
+							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 3, size_t, "%zu");
+
+							if (start_time > 0) {
+								BC_ASSERT_EQUAL(
+								    (long long)linphone_conference_info_get_date_time(conf_info_from_original_content),
+								    (long long)start_time, long long, "%lld");
+								if (end_time > 0) {
+									const int duration_m =
+									    linphone_conference_info_get_duration(conf_info_from_original_content);
+									BC_ASSERT_EQUAL(duration_m, new_duration, int, "%d");
+								}
+							}
+							if (initialSubject) {
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_subject(conf_info_from_original_content),
+								    initialSubject);
+							} else {
+								BC_ASSERT_PTR_NULL(
+								    linphone_conference_info_get_subject(conf_info_from_original_content));
+							}
+							if (description) {
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_description(conf_info_from_original_content),
+								    description);
+							} else {
+								BC_ASSERT_PTR_NULL(
+								    linphone_conference_info_get_description(conf_info_from_original_content));
+							}
+							BC_ASSERT_STRING_EQUAL(
+							    linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid);
+							const unsigned int ics_sequence =
+							    linphone_conference_info_get_ics_sequence(conf_info_from_original_content);
+							BC_ASSERT_EQUAL(ics_sequence, (sequence + 1), int, "%d");
+
+							LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateUpdated;
+							BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(conf_info_from_original_content),
+							                (int)exp_state, int, "%d");
+
+							linphone_conference_info_unref(conf_info_from_original_content);
+						}
+					}
+					linphone_chat_message_unref(msg);
+				}
+			}
+			participant_stats.pop_front();
+		}
+		linphone_conference_scheduler_unref(conference_scheduler);
+		conference_scheduler = nullptr;
+		linphone_conference_info_unref(conf_info);
+		conf_info = nullptr;
+
+		if (server_restart) {
+			ms_message("%s is restarting", linphone_core_get_identity(focus.getLc()));
+			coresList = bctbx_list_remove(coresList, focus.getLc());
+			// Restart flexisip
+			focus.reStart();
+
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(focus.getLc(), pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_enable_video_capture(focus.getLc(), TRUE);
+			linphone_core_enable_video_display(focus.getLc(), TRUE);
+			coresList = bctbx_list_append(coresList, focus.getLc());
+		}
+
+		const char *subject = "Test characters: <S-F12><S-F11><S-F6> £$%§ (+cancelled)";
+		const char *description2 = "Testing characters (+cancelled)";
+
+		info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
+		if (BC_ASSERT_PTR_NOT_NULL(info)) {
+			sequence = linphone_conference_info_get_ics_sequence(info);
+			linphone_conference_info_unref(info);
+		}
+
+		ms_message("%s is trying to cancel conference %s", linphone_core_get_identity(marie.getLc()),
+		           conference_address_str);
+		ms_free(conference_address_str);
+
+		focus_stat = focus.getStats();
+		manager_editing_stat = marie.getStats();
+
+		participant_stats.clear();
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+			participant_stats.push_back(mgr->stat);
+		}
+
+		conf_info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
+		linphone_conference_info_set_subject(conf_info, subject);
+		linphone_conference_info_set_description(conf_info, description2);
+
+		const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+		BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 3, size_t, "%zu");
+
+		conference_scheduler = linphone_core_create_conference_scheduler(marie.getLc());
+		linphone_conference_scheduler_set_account(conference_scheduler, editing_account);
+		cbs = linphone_factory_create_conference_scheduler_cbs(linphone_factory_get());
+		linphone_conference_scheduler_cbs_set_state_changed(cbs, conference_scheduler_state_changed);
+		linphone_conference_scheduler_cbs_set_invitations_sent(cbs, conference_scheduler_invitations_sent);
+		linphone_conference_scheduler_add_callbacks(conference_scheduler, cbs);
+		linphone_conference_scheduler_cbs_unref(cbs);
+		linphone_conference_scheduler_cancel_conference(conference_scheduler, conf_info);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateUpdating,
+		                             manager_editing_stat.number_of_ConferenceSchedulerStateUpdating + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerStateReady,
+		                             manager_editing_stat.number_of_ConferenceSchedulerStateReady + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                             focus_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                             focus_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             focus_stat.number_of_LinphoneConferenceStateTerminationPending + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             focus_stat.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                             focus_stat.number_of_LinphoneConferenceStateDeleted + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		chat_room_params = linphone_core_create_default_chat_room_params(marie.getLc());
+		linphone_chat_room_params_set_backend(chat_room_params, LinphoneChatRoomBackendBasic);
+		linphone_conference_scheduler_send_invitations(conference_scheduler, chat_room_params);
+		linphone_chat_room_params_unref(chat_room_params);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_ConferenceSchedulerInvitationsSent,
+		                             manager_editing_stat.number_of_ConferenceSchedulerInvitationsSent + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+			auto old_stats = participant_stats.front();
+			if ((mgr != focus.getCMgr()) && (mgr != marie.getCMgr())) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceived,
+				                             old_stats.number_of_LinphoneMessageReceived + 1,
+				                             liblinphone_tester_sip_timeout));
+				if (!linphone_core_conference_ics_in_message_body_enabled(marie.getLc())) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneMessageReceivedWithFile,
+					                             old_stats.number_of_LinphoneMessageReceivedWithFile + 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				BC_ASSERT_PTR_NOT_NULL(mgr->stat.last_received_chat_message);
+				if (mgr->stat.last_received_chat_message != NULL) {
+					const string expected = ContentType::Icalendar.getMediaType();
+					BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_content_type(mgr->stat.last_received_chat_message),
+					                       expected.c_str());
+				}
+
+				bctbx_list_t *participant_chat_room_participants = bctbx_list_append(NULL, marie.getCMgr()->identity);
+				LinphoneChatRoom *pcr = linphone_core_search_chat_room(mgr->lc, NULL, mgr->identity, NULL,
+				                                                       participant_chat_room_participants);
+				bctbx_list_free(participant_chat_room_participants);
+				BC_ASSERT_PTR_NOT_NULL(pcr);
+				bctbx_list_t *chat_room_participants = bctbx_list_append(NULL, mgr->identity);
+
+				LinphoneChatRoom *cr = linphone_core_search_chat_room(marie.getLc(), NULL, marie.getCMgr()->identity,
+				                                                      NULL, chat_room_participants);
+				bctbx_list_free(chat_room_participants);
+				BC_ASSERT_PTR_NOT_NULL(cr);
+
+				BC_ASSERT_EQUAL((int)bctbx_list_size(linphone_core_get_chat_rooms(mgr->lc)), 1, int, "%d");
+
+				if (cr) {
+					LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(cr);
+					BC_ASSERT_PTR_NOT_NULL(msg);
+
+					const bctbx_list_t *original_contents = linphone_chat_message_get_contents(msg);
+					BC_ASSERT_EQUAL((int)bctbx_list_size(original_contents), 1, int, "%d");
+					LinphoneContent *original_content = (LinphoneContent *)bctbx_list_get_data(original_contents);
+					if (BC_ASSERT_PTR_NOT_NULL(original_content)) {
+						LinphoneConferenceInfo *conf_info_from_original_content =
+						    linphone_factory_create_conference_info_from_icalendar_content(linphone_factory_get(),
+						                                                                   original_content);
+						if (BC_ASSERT_PTR_NOT_NULL(conf_info_from_original_content)) {
+							BC_ASSERT_TRUE(linphone_address_weak_equal(
+							    marie.getCMgr()->identity,
+							    linphone_conference_info_get_organizer(conf_info_from_original_content)));
+							BC_ASSERT_TRUE(linphone_address_weak_equal(
+							    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
+
+							const bctbx_list_t *ics_participants =
+							    linphone_conference_info_get_participants(conf_info_from_original_content);
+							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 0, size_t, "%zu");
+
+							if (start_time > 0) {
+								BC_ASSERT_EQUAL(
+								    (long long)linphone_conference_info_get_date_time(conf_info_from_original_content),
+								    (long long)start_time, long long, "%lld");
+								if (end_time > 0) {
+									const int duration_m =
+									    linphone_conference_info_get_duration(conf_info_from_original_content);
+									BC_ASSERT_EQUAL(duration_m, new_duration, int, "%d");
+								}
+							}
+							if (subject) {
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_subject(conf_info_from_original_content), subject);
+							} else {
+								BC_ASSERT_PTR_NULL(
+								    linphone_conference_info_get_subject(conf_info_from_original_content));
+							}
+							if (description2) {
+								BC_ASSERT_STRING_EQUAL(
+								    linphone_conference_info_get_description(conf_info_from_original_content),
+								    description2);
+							} else {
+								BC_ASSERT_PTR_NULL(
+								    linphone_conference_info_get_description(conf_info_from_original_content));
+							}
+							BC_ASSERT_STRING_EQUAL(
+							    linphone_conference_info_get_ics_uid(conf_info_from_original_content), uid);
+							const unsigned int ics_sequence =
+							    linphone_conference_info_get_ics_sequence(conf_info_from_original_content);
+							BC_ASSERT_EQUAL(ics_sequence, (sequence + 1), int, "%d");
+
+							LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
+							if (mgr == focus.getCMgr()) {
+								exp_state = LinphoneConferenceInfoStateUpdated;
+							} else {
+								exp_state = LinphoneConferenceInfoStateCancelled;
+							}
+							BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(conf_info_from_original_content),
+							                (int)exp_state, int, "%d");
+
+							linphone_conference_info_unref(conf_info_from_original_content);
+						}
+					}
+					linphone_chat_message_unref(msg);
+				}
+			}
+			participant_stats.pop_front();
+		}
+		linphone_conference_scheduler_unref(conference_scheduler);
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+			LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr);
+			if (BC_ASSERT_PTR_NOT_NULL(info)) {
+
+				const char *exp_subject = subject;
+
+				const char *exp_description = NULL;
+				if (mgr != focus.getCMgr()) {
+					exp_description = description2;
+				}
+
+				unsigned int exp_sequence = 0;
+				LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateCancelled;
+				unsigned int exp_participant_number = 0;
+				if (mgr == focus.getCMgr()) {
+					exp_sequence = 0;
+				} else {
+					exp_sequence = (sequence + 1);
+				}
+				check_conference_info(mgr, confAddr, marie.getCMgr(), exp_participant_number, start_time, new_duration,
+				                      exp_subject, exp_description, exp_sequence, exp_state);
+			}
+			if (info) {
+				linphone_conference_info_unref(info);
+			}
+		}
+		linphone_conference_info_unref(conf_info);
+		ms_free(uid);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void conference_cancelled_through_edit(void) {
+	conference_cancelled_through_edit_base(FALSE);
+}
+
+static void create_conference_with_server_restart_conference_cancelled(void) {
+	conference_cancelled_through_edit_base(TRUE);
+}
+
+#if 0
+static void conference_with_participant_added_outside_valid_time_slot (bool_t before_start) {
+	Focus focus("chloe_rc");
+	{//to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+		linphone_core_set_conference_participant_list_type(focus.getLc(), LinphoneConferenceParticipantListTypeOpen);
+
+		bctbx_list_t * coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
+		time_t start_time = (time_t)-1;
+		time_t end_time = (time_t)-1;
+
+		if (before_start) {
+			start_time = ms_time(NULL) + 600;
+		} else {
+			start_time = ms_time(NULL) - 60;
+		}
+		end_time = start_time + 60;
+		const char *initialSubject = "Colleagues";
+		const char *description = "Tom Black";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress* confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2, liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+		}
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1, liblinphone_tester_sip_timeout));
+		}
+
+		//wait bit more to detect side effect if any
+		CoreManagerAssert({focus,marie,pauline,laure}).waitUntil(chrono::seconds(2),[] {
+			return false;
+		});
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+
+	}
+}
+
+static void conference_with_participants_added_after_end (void) {
+	conference_with_participant_added_outside_valid_time_slot(FALSE);
+}
+
+static void conference_with_participants_added_before_start (void) {
+	conference_with_participant_added_outside_valid_time_slot(TRUE);
+}
+#endif
+
+static void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(berthe);
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+		setup_conference_info_cbs(marie.getCMgr());
+		if (!same_organizer) {
+			linphone_core_set_file_transfer_server(michelle.getLc(), file_transfer_url);
+			setup_conference_info_cbs(michelle.getCMgr());
+		}
+
+		linphone_core_set_conference_participant_list_type(focus.getLc(), LinphoneConferenceParticipantListTypeOpen);
+		linphone_core_set_default_conference_layout(focus.getLc(), LinphoneConferenceLayoutGrid);
+
+		int i = 0;
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                 berthe.getCMgr()}) {
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			linphone_core_set_default_conference_layout(mgr->lc, (i % 2) ? LinphoneConferenceLayoutGrid
+			                                                             : LinphoneConferenceLayoutActiveSpeaker);
+		}
+
+		stats focus_stat = focus.getStats();
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		coresList = bctbx_list_append(coresList, berthe.getLc());
+
+		std::list<LinphoneCoreManager *> participants1{pauline.getCMgr(), laure.getCMgr()};
+		time_t start_time1 = ms_time(NULL);
+		time_t end_time1 = (start_time1 + 600);
+		const char *subject1 = "Colleagues";
+		const char *description1 = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList1;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants1) {
+			participantList1.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr1 = create_conference_on_server(focus, marie, participantList1, start_time1, end_time1,
+		                                                         subject1, description1, TRUE);
+		char *conference1_address_str = (confAddr1) ? linphone_address_as_string(confAddr1) : ms_strdup("<unknown>");
+		BC_ASSERT_PTR_NOT_NULL(confAddr1);
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			ms_message("%s is entering conference %s", linphone_core_get_identity(mgr->lc), conference1_address_str);
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			linphone_core_invite_address_with_params_2(mgr->lc, confAddr1, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+		}
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1,
+			                             liblinphone_tester_sip_timeout));
+			LinphoneCall *currentCall = linphone_core_get_current_call(mgr->lc);
+			BC_ASSERT_PTR_NOT_NULL(currentCall);
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr1, NULL);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			linphone_address_unref(uri);
+			if (currentCall && pconference) {
+				BC_ASSERT_PTR_EQUAL(linphone_call_get_conference(currentCall), pconference);
+			}
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 6,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + 3,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + 3, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 3,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneAddress *focus_uri1 = linphone_address_new(linphone_core_get_identity(focus.getLc()));
+		LinphoneConference *fconference1 =
+		    linphone_core_search_conference(focus.getLc(), NULL, focus_uri1, confAddr1, NULL);
+		linphone_address_unref(focus_uri1);
+		BC_ASSERT_PTR_NOT_NULL(fconference1);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr1, NULL);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference);
+				int no_participants = 0;
+				if (start_time1 >= 0) {
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+					                (long long)start_time1, long long, "%lld");
+				}
+				BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+				                (long long)end_time1, long long, "%lld");
+				if (mgr == focus.getCMgr()) {
+					no_participants = 3;
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = 2;
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 3, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), subject1);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference1, pconference);
+				}
+			}
+		}
+
+		time_t start_time2 = (dialout) ? -1 : ms_time(NULL);
+		time_t end_time2 = (dialout) ? -1 : (start_time2 + 600);
+		const char *subject2 = "All Hands Q3 FY2021 - Attendance Mandatory";
+		const char *description2 = "Financial result - Internal only - Strictly confidential";
+		std::list<LinphoneCoreManager *> participants2{pauline.getCMgr()};
+		std::list<LinphoneCoreManager *> mgr_having_two_confs{};
+		std::list<LinphoneCoreManager *> mgr_in_conf2{focus.getCMgr(), michelle.getCMgr()};
+		ClientConference &confCreator2 = (same_organizer) ? marie : michelle;
+
+		if (same_organizer) {
+			participants2.push_back(michelle.getCMgr());
+			mgr_having_two_confs.push_back(marie.getCMgr());
+		} else {
+			participants2.push_back(marie.getCMgr());
+			if (!dialout) {
+				mgr_having_two_confs.push_back(marie.getCMgr());
+				mgr_in_conf2.push_back(marie.getCMgr());
+			}
+		}
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList2;
+		for (auto &p : participants2) {
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+			participantList2.insert(std::make_pair(p, role));
+		}
+
+		LinphoneAddress *confAddr2 = create_conference_on_server(focus, confCreator2, participantList2, start_time2,
+		                                                         end_time2, subject2, description2, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr2);
+		char *conference2_address_str = (confAddr2) ? linphone_address_as_string(confAddr2) : ms_strdup("<unknown>");
+
+		// Chat room creation to send ICS
+		if (same_organizer) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 3,
+			                             liblinphone_tester_sip_timeout));
+		} else {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated, 2,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		if (confAddr2) {
+			if (dialout) {
+				for (auto mgr : participants2) {
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr2);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					auto it = std::find(participants1.cbegin(), participants1.cend(), mgr);
+					if (pcall && (it == participants1.cend())) {
+						LinphoneCallLog *call_log = linphone_call_get_call_log(pcall);
+						BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+						ms_message("%s is entering conference %s", linphone_core_get_identity(mgr->lc),
+						           conference2_address_str);
+						linphone_call_accept(pcall);
+						BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,
+						                             liblinphone_tester_sip_timeout));
+					}
+				}
+			} else {
+				mgr_having_two_confs.push_back(pauline.getCMgr());
+				mgr_in_conf2.push_back(pauline.getCMgr());
+				for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
+					ms_message("%s is entering conference %s", linphone_core_get_identity(mgr->lc),
+					           conference2_address_str);
+					LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+					linphone_core_invite_address_with_params_2(mgr->lc, confAddr2, new_params, NULL, nullptr);
+					linphone_call_params_unref(new_params);
+				}
+
+				for (auto mgr : {marie.getCMgr(), pauline.getCMgr()}) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 2,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				for (auto mgr : {michelle.getCMgr()}) {
+					BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+					                             liblinphone_tester_sip_timeout));
+				}
+
+				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+				                             focus_stat.number_of_LinphoneCallIncomingReceived + 6,
+				                             liblinphone_tester_sip_timeout));
+			}
+		}
+
+		for (auto mgr : mgr_having_two_confs) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 3,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallPaused, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+			                             ((mgr == marie.getCMgr()) ? 4 : 3), liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 2,
+			                             liblinphone_tester_sip_timeout));
+			LinphoneCall *currentCall = linphone_core_get_current_call(mgr->lc);
+			BC_ASSERT_PTR_NOT_NULL(currentCall);
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr2, NULL);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			linphone_address_unref(uri);
+			if (currentCall && pconference) {
+				BC_ASSERT_PTR_EQUAL(linphone_call_get_conference(currentCall), pconference);
+			}
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, 2, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 4,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		for (auto mgr : {michelle.getCMgr()}) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+			                             ((same_organizer) ? 2 : 3), liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1,
+			                             liblinphone_tester_sip_timeout));
+			LinphoneCall *currentCall = linphone_core_get_current_call(mgr->lc);
+			BC_ASSERT_PTR_NOT_NULL(currentCall);
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr2, NULL);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			linphone_address_unref(uri);
+			if (currentCall && pconference) {
+				BC_ASSERT_PTR_EQUAL(linphone_call_get_conference(currentCall), pconference);
+			}
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		const int subscription = (dialout) ? ((same_organizer) ? 5 : 4) : 6;
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + subscription,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 2 * subscription,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + subscription,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + subscription,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + subscription,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + subscription,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + subscription,
+		                             liblinphone_tester_sip_timeout));
+
+		// Marie and Pauline leave conference1
+		const int onhold = (dialout) ? ((same_organizer) ? 1 : 0) : 2;
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_on_hold,
+		                             focus_stat.number_of_participant_devices_on_hold + onhold,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList,
+		                             &laure.getStats().number_of_participant_devices_media_capability_changed, onhold,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_on_hold, onhold,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList,
+		                             &marie.getStats().number_of_participant_devices_media_capability_changed,
+		                             onhold - 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_on_hold, onhold - 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList,
+		                             &pauline.getStats().number_of_participant_devices_media_capability_changed, onhold,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_on_hold, onhold,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneAddress *focus_uri2 = linphone_address_new(linphone_core_get_identity(focus.getLc()));
+		LinphoneConference *fconference2 =
+		    linphone_core_search_conference(focus.getLc(), NULL, focus_uri2, confAddr2, NULL);
+		linphone_address_unref(focus_uri2);
+		BC_ASSERT_PTR_NOT_NULL(fconference2);
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr1, NULL);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				if (mgr == focus.getCMgr()) {
+					BC_ASSERT_EQUAL(bctbx_list_size(devices), 3, size_t, "%zu");
+					BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), 3, int, "%0d");
+				} else {
+					BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), 2, int, "%0d");
+					if ((mgr == laure.getCMgr()) ||
+					    (dialout && ((mgr == pauline.getCMgr()) || (!same_organizer && (mgr == marie.getCMgr()))))) {
+						BC_ASSERT_EQUAL(bctbx_list_size(devices), 3, size_t, "%zu");
+						BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					} else {
+						BC_ASSERT_EQUAL(bctbx_list_size(devices), 2, size_t, "%zu");
+						BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+					}
+				}
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		auto &organizer2 = (same_organizer) ? marie : michelle;
+		for (auto mgr : mgr_in_conf2) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr2);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference);
+				int no_participants = 0;
+				if (start_time2 >= 0) {
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+					                (long long)start_time2, long long, "%lld");
+				}
+				BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+				                (long long)end_time2, long long, "%lld");
+				if (mgr == focus.getCMgr()) {
+					no_participants = 3;
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = 2;
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), (dialout) ? ((same_organizer) ? 2 : 1) : 3, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), subject2);
+
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == organizer2.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(linphone_participant_is_admin(p) ==
+					               linphone_address_weak_equal(linphone_participant_get_address(p),
+					                                           organizer2.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference2, pconference);
+				}
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		focus_stat = focus.getStats();
+		stats pauline_stat = pauline.getStats();
+
+		std::list<LinphoneCoreManager *> mgr_conf2_to_remove{michelle.getCMgr()};
+		if (!dialout || same_organizer) {
+			mgr_conf2_to_remove.push_back(marie.getCMgr());
+		}
+		// Marie and Michelle leave conference2
+		for (auto mgr : mgr_conf2_to_remove) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr2, NULL);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				ms_message("%s is terminating conference %s", linphone_core_get_identity(mgr->lc),
+				           conference2_address_str);
+				linphone_conference_terminate(pconference);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				LinphoneConference *pconference1 = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr2, NULL);
+				BC_ASSERT_PTR_NULL(pconference1);
+			}
+			auto it_having_two_confs = std::find(mgr_having_two_confs.begin(), mgr_having_two_confs.end(), mgr);
+			if (it_having_two_confs != mgr_having_two_confs.end()) {
+				mgr_having_two_confs.erase(it_having_two_confs);
+			}
+
+			auto it_conf2 = std::find(mgr_in_conf2.begin(), mgr_in_conf2.end(), mgr);
+			if (it_conf2 != mgr_in_conf2.end()) {
+				mgr_in_conf2.erase(it_conf2);
+			}
+			linphone_address_unref(uri);
+		}
+
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                  focus_stat.number_of_participants_removed + static_cast<int>(mgr_conf2_to_remove.size()),
+		                  liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed +
+		                                 static_cast<int>(mgr_conf2_to_remove.size()),
+		                             liblinphone_tester_sip_timeout));
+
+		if (!dialout) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participants_removed,
+			                             pauline_stat.number_of_participants_removed +
+			                                 static_cast<int>(mgr_conf2_to_remove.size()),
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_removed,
+			                             pauline_stat.number_of_participant_devices_removed +
+			                                 static_cast<int>(mgr_conf2_to_remove.size()),
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                pauline_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneConferenceStateTerminated,
+		                pauline_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneConferenceStateDeleted,
+		                pauline_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		for (auto mgr : mgr_in_conf2) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr2, NULL);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			linphone_address_unref(uri);
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+				                ((mgr == focus.getCMgr()) ? ((!dialout || same_organizer) ? 1 : 2) : 0), int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), mgr_in_conf2.size() - 1, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), subject2);
+			}
+		}
+
+		// Marie and Pauline rejoin conference1 (Pauline leaves conference2)
+		focus_stat = focus.getStats();
+		pauline_stat = pauline.getStats();
+		stats marie_stat = marie.getStats();
+		std::list<LinphoneCoreManager *> mgr_rejoining{marie.getCMgr()};
+		if (!dialout) {
+			mgr_rejoining.push_back(pauline.getCMgr());
+		}
+
+		for (auto mgr : mgr_rejoining) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr1, NULL);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			linphone_address_unref(uri);
+			if (pconference) {
+				ms_message("%s is joining conference %s", linphone_core_get_identity(mgr->lc), conference1_address_str);
+				linphone_conference_enter(pconference);
+			}
+		}
+
+		LinphoneAddress *focusUri = linphone_address_new(linphone_core_get_identity(focus.getLc()));
+		LinphoneConference *conference1 =
+		    linphone_core_search_conference(focus.getLc(), NULL, focusUri, confAddr1, NULL);
+
+		if (!dialout) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallPaused,
+			                             pauline_stat.number_of_LinphoneCallPaused + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+			                             pauline_stat.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+		if (!dialout || same_organizer) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+			                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                pauline_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneConferenceStateTerminated,
+		                pauline_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneConferenceStateDeleted,
+		                pauline_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		if (!dialout) {
+			// Pauline leaves conference2
+			// Pauline and Marie enter conference1
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_on_hold,
+			                             focus_stat.number_of_participant_devices_on_hold + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+			                             focus_stat.number_of_participant_devices_joined + 2,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		for (auto mgr : mgr_in_conf2) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr2, NULL);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			linphone_address_unref(uri);
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+				                ((mgr == focus.getCMgr()) ? ((!dialout || same_organizer) ? 1 : 2) : 0), int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), ((mgr == focus.getCMgr() && !dialout) ? 1 : 0), size_t,
+				                "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), subject2);
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		// Laure and Pauline are removed from conference1
+		focus_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		pauline_stat = pauline.getStats();
+		stats laure_stat = laure.getStats();
+		int cnt = 0;
+		for (auto mgr : {laure.getCMgr(), pauline.getCMgr()}) {
+			cnt++;
+			LinphoneParticipant *participant = linphone_conference_find_participant(conference1, mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(participant);
+			if (participant) {
+				char *conference1_me = linphone_address_as_string(
+				    linphone_participant_get_address(linphone_conference_get_me(conference1)));
+				ms_message("%s is removing participant %s from conference %s", conference1_me,
+				           linphone_core_get_identity(mgr->lc), conference1_address_str);
+				ms_free(conference1_me);
+				linphone_conference_remove_participant_2(conference1, participant);
+			}
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+			                             focus_stat.number_of_LinphoneCallEnd + cnt, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+			                             focus_stat.number_of_LinphoneCallReleased + cnt,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+			                             focus_stat.number_of_participants_removed + cnt,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+			                             focus_stat.number_of_participant_devices_removed + cnt,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+			                             marie_stat.number_of_participants_removed + cnt,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+			                             marie_stat.number_of_participant_devices_removed + cnt,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallEnd,
+		                             laure_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallReleased,
+		                             laure_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallEnd,
+		                             pauline_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallReleased,
+		                             pauline_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneSubscriptionTerminated,
+		                             laure_stat.number_of_LinphoneSubscriptionTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             laure_stat.number_of_LinphoneConferenceStateTerminationPending + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             laure_stat.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateDeleted,
+		                             laure_stat.number_of_LinphoneConferenceStateDeleted + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneSubscriptionTerminated,
+		                             pauline_stat.number_of_LinphoneSubscriptionTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             pauline_stat.number_of_LinphoneConferenceStateTerminationPending + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             pauline_stat.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateDeleted,
+		                             pauline_stat.number_of_LinphoneConferenceStateDeleted + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                marie_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateTerminated,
+		                marie_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateDeleted,
+		                marie_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		if (!dialout) {
+			// Pauline rejoins and leaves conference2 (conference2 is destroyed on the server)
+			focus_stat = focus.getStats();
+			pauline_stat = pauline.getStats();
+			for (auto mgr : {pauline.getCMgr()}) {
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr2, NULL);
+				BC_ASSERT_PTR_NOT_NULL(pconference);
+				linphone_address_unref(uri);
+				if (pconference) {
+					ms_message("%s is entering conference %s", linphone_core_get_identity(mgr->lc),
+					           conference2_address_str);
+					linphone_conference_enter(pconference);
+				}
+			}
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+			                             pauline_stat.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneConferenceStateTerminationPending,
+			                pauline_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+			BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneConferenceStateTerminated,
+			                pauline_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+			BC_ASSERT_EQUAL(pauline.getStats().number_of_LinphoneConferenceStateDeleted,
+			                pauline_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+			// Pauline enters conference2
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+			                             focus_stat.number_of_participant_devices_joined + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			for (auto mgr : mgr_in_conf2) {
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr2, NULL);
+				BC_ASSERT_PTR_NOT_NULL(pconference);
+				linphone_address_unref(uri);
+				if (pconference) {
+					BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+					                ((mgr == focus.getCMgr()) ? 1 : 0), int, "%0d");
+					bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+					BC_ASSERT_EQUAL(bctbx_list_size(devices), 1, size_t, "%zu");
+					if (devices) {
+						bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+					}
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference) == (mgr != focus.getCMgr()));
+					BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), subject2);
+				}
+			}
+
+			// wait bit more to detect side effect if any
+			CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] {
+				return false;
+			});
+
+			// Pauline leaves conference2
+			focus_stat = focus.getStats();
+			pauline_stat = pauline.getStats();
+			for (auto mgr : {pauline.getCMgr()}) {
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr2, NULL);
+				BC_ASSERT_PTR_NOT_NULL(pconference);
+				if (pconference) {
+					ms_message("%s is terminating conference %s", linphone_core_get_identity(mgr->lc),
+					           conference2_address_str);
+					linphone_conference_terminate(pconference);
+				}
+				linphone_address_unref(uri);
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallEnd,
+			                             pauline_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallReleased,
+			                             pauline_stat.number_of_LinphoneCallReleased + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneSubscriptionTerminated,
+			                             pauline_stat.number_of_LinphoneSubscriptionTerminated + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(
+			    coresList, &pauline.getStats().number_of_LinphoneConferenceStateTerminationPending,
+			    pauline_stat.number_of_LinphoneConferenceStateTerminationPending + 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateTerminated,
+			                             pauline_stat.number_of_LinphoneConferenceStateTerminated + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneConferenceStateDeleted,
+			                             pauline_stat.number_of_LinphoneConferenceStateDeleted + 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		// Explicitely terminate conference as those on server are static by default
+		LinphoneConference *conference2 =
+		    linphone_core_search_conference(focus.getLc(), NULL, focusUri, confAddr2, NULL);
+		linphone_conference_terminate(conference2);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             focus_stat.number_of_LinphoneConferenceStateTerminationPending + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             focus_stat.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                             focus_stat.number_of_LinphoneConferenceStateDeleted + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Marie terminates conference1 (conference1 is destroyed on the server)
+		focus_stat = focus.getStats();
+		marie_stat = marie.getStats();
+		for (auto mgr : {marie.getCMgr()}) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr1, NULL);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				char *conference_address_str =
+				    (confAddr1) ? linphone_address_as_string(confAddr1) : ms_strdup("<unknown>");
+				ms_message("%s is terminating conference %s", linphone_core_get_identity(mgr->lc),
+				           conference_address_str);
+				ms_free(conference_address_str);
+				linphone_conference_terminate(pconference);
+			}
+			linphone_address_unref(uri);
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd,
+		                             marie_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased,
+		                             marie_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionTerminated,
+		                             marie_stat.number_of_LinphoneSubscriptionTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             marie_stat.number_of_LinphoneConferenceStateTerminationPending + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             marie_stat.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateDeleted,
+		                             marie_stat.number_of_LinphoneConferenceStateDeleted + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                             focus_stat.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                             focus_stat.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
+
+		// Explicitely terminate conference as those on server are static by default
+		linphone_conference_terminate(conference1);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             focus_stat.number_of_LinphoneConferenceStateTerminationPending + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                             focus_stat.number_of_LinphoneConferenceStateTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                             focus_stat.number_of_LinphoneConferenceStateDeleted + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		ms_free(conference1_address_str);
+		ms_free(conference2_address_str);
+		linphone_address_unref(focusUri);
+		linphone_address_unref(confAddr1);
+		linphone_address_unref(confAddr2);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void organizer_schedule_two_conferences(void) {
+	two_overlapping_conferences_base(TRUE, FALSE);
+}
+
+static void two_overlapping_scheduled_conferences_from_different_organizers(void) {
+	two_overlapping_conferences_base(FALSE, FALSE);
+}
+
+static void organizer_creates_two_dialout_conferences(void) {
+	two_overlapping_conferences_base(TRUE, TRUE);
+}
+
+static void two_overlapping_dialout_conferences_from_different_organizers(void) {
+	two_overlapping_conferences_base(FALSE, TRUE);
+}
+
+static void create_simple_conference_merging_calls_base(bool_t enable_ice,
+                                                        LinphoneConferenceLayout layout,
+                                                        bool_t toggle_video,
+                                                        bool_t toggle_all_mananger_video,
+                                                        bool_t change_layout) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		auto focus_proxy_config = focus.getDefaultProxyConfig();
+		const char *focus_uri = linphone_proxy_config_get_identity(focus_proxy_config);
+
+		auto marie_proxy = marie.getDefaultProxyConfig();
+		linphone_proxy_config_edit(marie_proxy);
+		linphone_proxy_config_set_conference_factory_uri(marie_proxy, focus_uri);
+		linphone_proxy_config_done(marie_proxy);
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			if (toggle_video) {
+				LinphoneVideoActivationPolicy *pol =
+				    linphone_factory_create_video_activation_policy(linphone_factory_get());
+				linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+				linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+				linphone_core_set_video_activation_policy(mgr->lc, pol);
+				linphone_video_activation_policy_unref(pol);
+
+				linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+				linphone_core_enable_video_capture(mgr->lc, TRUE);
+				linphone_core_enable_video_display(mgr->lc, TRUE);
+			}
+
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, layout);
+			}
+		}
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+
+		BC_ASSERT_TRUE(call(marie.getCMgr(), pauline.getCMgr()));
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			enable_stun_in_core(mgr, enable_ice, enable_ice);
+		}
+
+		LinphoneCall *marie_call_pauline = linphone_core_get_current_call(marie.getLc());
+		BC_ASSERT_PTR_NOT_NULL(marie_call_pauline);
+		LinphoneCall *pauline_called_by_marie = linphone_core_get_current_call(pauline.getLc());
+		BC_ASSERT_PTR_NOT_NULL(pauline_called_by_marie);
+		// linphone_call_set_microphone_muted (pauline_called_by_marie, TRUE);
+		BC_ASSERT_TRUE(pause_call_1(marie.getCMgr(), marie_call_pauline, pauline.getCMgr(), pauline_called_by_marie));
+
+		BC_ASSERT_TRUE(call(marie.getCMgr(), laure.getCMgr()));
+		LinphoneCall *marie_call_laure = linphone_core_get_current_call(marie.getLc());
+		BC_ASSERT_PTR_NOT_NULL(marie_call_laure);
+
+		// marie creates the conference
+		LinphoneConferenceParams *conf_params = linphone_core_create_conference_params_2(marie.getLc(), NULL);
+		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
+		linphone_conference_params_set_subject(conf_params, initialSubject);
+		LinphoneConference *conf = linphone_core_create_conference_with_params(marie.getLc(), conf_params);
+		linphone_conference_params_unref(conf_params);
+		BC_ASSERT_PTR_NOT_NULL(conf);
+
+		std::list<stats> participant_stats;
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			participant_stats.push_back(mgr->stat);
+		}
+
+		if (conf) {
+			const bctbx_list_t *calls = linphone_core_get_calls(marie.getLc());
+			for (const bctbx_list_t *it = calls; it; it = bctbx_list_next(it)) {
+				LinphoneCall *call = (LinphoneCall *)it->data;
+				linphone_conference_add_participant(conf, call);
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreationPending, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 1, 20000));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_added, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneAddress *confAddr =
+		    conf ? linphone_address_clone(linphone_conference_get_conference_address(conf)) : NULL;
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		int counter = 0;
+		for (auto mgr : {pauline.getCMgr(), laure.getCMgr()}) {
+			counter++;
+			auto old_stats = participant_stats.front();
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreationPending,
+			                             old_stats.number_of_LinphoneConferenceStateCreationPending + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+			                             old_stats.number_of_LinphoneConferenceStateCreated + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress,
+			                             old_stats.number_of_LinphoneSubscriptionOutgoingProgress + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive,
+			                             old_stats.number_of_LinphoneSubscriptionActive + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning, counter + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneTransferCallConnected, counter,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning,
+			                             old_stats.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			// End of call between conference and participant
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd, counter,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd,
+			                             old_stats.number_of_LinphoneCallEnd + 1, liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased, counter,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased,
+			                             old_stats.number_of_LinphoneCallReleased + 1, liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+			participant_stats.pop_front();
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added, 3,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+				                (mgr == focus.getCMgr()) ? 3 : 2, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 3, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+			}
+
+			if (mgr != focus.getCMgr()) {
+				// Local conference
+				LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->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));
+					_linphone_call_check_nb_active_streams(focus_call, 1, (toggle_video) ? 4 : 0, 0);
+				}
+
+				// Remote  conference
+				LinphoneCall *participant_call =
+				    linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->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));
+					// BC_ASSERT_TRUE(linphone_call_get_microphone_muted(participant_call) == (mgr ==
+					// pauline.getCMgr()));
+					_linphone_call_check_nb_active_streams(participant_call, 1, (toggle_video) ? 4 : 0, 0);
+				}
+			}
+
+			if (confAddr) {
+				check_conference_info(mgr, confAddr, marie.getCMgr(), 3, 0, 0, initialSubject, NULL, 0,
+				                      LinphoneConferenceInfoStateNew);
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		participant_stats.clear();
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			participant_stats.push_back(mgr->stat);
+		}
+
+		stats focus_stat = focus.getStats();
+		stats pauline_stat = pauline.getStats();
+		stats laure_stat = laure.getStats();
+		const char *newSubject = "Let's go drink a beer";
+		linphone_conference_set_subject(conf, newSubject);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_subject_changed,
+		                             focus_stat.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_subject_changed,
+		                             pauline_stat.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_subject_changed,
+		                             laure_stat.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			auto old_stats = participant_stats.front();
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_subject_changed,
+			                             old_stats.number_of_subject_changed + 1, liblinphone_tester_sip_timeout));
+			if (confAddr) {
+				check_conference_info(mgr, confAddr, marie.getCMgr(), 3, 0, 0, newSubject, NULL, 0,
+				                      LinphoneConferenceInfoStateNew);
+			}
+			participant_stats.pop_front();
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		LinphoneAddress *focus_addr = linphone_address_new(linphone_core_get_identity(focus.getLc()));
+		LinphoneConference *fconference =
+		    linphone_core_search_conference(focus.getLc(), NULL, focus_addr, confAddr, NULL);
+		linphone_address_unref(focus_addr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			// Explicitely terminate conference as those on server are static by default
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			check_conference_ssrc(fconference, pconference);
+		}
+
+		focus_stat = focus.getStats();
+		pauline_stat = pauline.getStats();
+		stats marie_stat = marie.getStats();
+
+		// Laure's core suddenly stops
+		ms_message("%s core suddently loses network and restarts", linphone_core_get_identity(laure.getLc()));
+		linphone_core_set_network_reachable(laure.getLc(), FALSE);
+		coresList = bctbx_list_remove(coresList, laure.getLc());
+
+		laure.reStart(false);
+
+		if (toggle_video) {
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(laure.getLc(), pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_enable_video_capture(laure.getLc(), TRUE);
+			linphone_core_enable_video_display(laure.getLc(), TRUE);
+		}
+
+		linphone_core_set_default_conference_layout(laure.getLc(), layout);
+		coresList = bctbx_list_append(coresList, laure.getLc());
+
+		linphone_core_set_network_reachable(laure.getLc(), TRUE);
+
+		LinphoneCallParams *laure_params = linphone_core_create_call_params(laure.getLc(), nullptr);
+		linphone_core_invite_address_with_params_2(laure.getLc(), confAddr, laure_params, NULL, nullptr);
+		linphone_call_params_unref(laure_params);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneRegistrationOk, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreationPending, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreated, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneSubscriptionOutgoingProgress, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneSubscriptionActive, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &laure.getStats().number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallUpdating, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallStreamsRunning, 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_added,
+		                             marie_stat.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_added,
+		                             pauline_stat.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_joined,
+		                             marie_stat.number_of_participant_devices_joined + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_joined,
+		                             pauline_stat.number_of_participant_devices_joined + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+		                             marie_stat.number_of_participant_devices_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_participant_devices_removed,
+		                             pauline_stat.number_of_participant_devices_removed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_removed, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		if (toggle_video) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+			                             marie_stat.number_of_LinphoneCallUpdating + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallUpdating,
+			                             pauline_stat.number_of_LinphoneCallUpdating + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallUpdating, 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+			                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 6,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+			                             marie_stat.number_of_LinphoneCallStreamsRunning + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+			                             pauline_stat.number_of_LinphoneCallStreamsRunning + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallStreamsRunning, 3,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat.number_of_LinphoneCallStreamsRunning + 7,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+				                (mgr == focus.getCMgr()) ? 3 : 2, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 3, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), newSubject);
+			}
+
+			if (mgr != focus.getCMgr()) {
+				// Local conference
+				LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->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));
+				}
+
+				// Remote  conference
+				LinphoneCall *participant_call =
+				    linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->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));
+					// BC_ASSERT_TRUE(linphone_call_get_microphone_muted(participant_call) == (mgr ==
+					// pauline.getCMgr()));
+				}
+			}
+
+			if (confAddr) {
+				check_conference_info(mgr, confAddr, marie.getCMgr(), 3, 0, 0, newSubject, NULL, 0,
+				                      LinphoneConferenceInfoStateNew);
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(5), [] { return false; });
+
+		std::list<LinphoneCoreManager *> mgrList = {pauline.getCMgr()};
+		if (toggle_all_mananger_video) {
+			mgrList.push_back(marie.getCMgr());
+			mgrList.push_back(laure.getCMgr());
+		}
+
+		if (toggle_video) {
+			for (int i = 0; i < 4; i++) {
+				for (auto mgr : mgrList) {
+					LinphoneMediaDirection video_direction = LinphoneMediaDirectionSendRecv;
+
+					LinphoneCall *participant_call = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(participant_call);
+					if (participant_call) {
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(participant_call);
+						BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+						video_direction = linphone_call_params_get_video_direction(call_lparams);
+
+						if (video_direction == LinphoneMediaDirectionRecvOnly) {
+							video_direction = LinphoneMediaDirectionSendRecv;
+						} else if (video_direction == LinphoneMediaDirectionSendRecv) {
+							video_direction = LinphoneMediaDirectionRecvOnly;
+						}
+					}
+
+					set_video_settings_in_conference(focus.getCMgr(), mgr, mgrList, confAddr, TRUE, video_direction,
+					                                 TRUE, video_direction);
+
+					LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+					LinphoneConference *pconference =
+					    linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+					linphone_address_unref(uri);
+					BC_ASSERT_PTR_NOT_NULL(pconference);
+
+					if (pconference) {
+						bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+						for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+							LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+							LinphoneMediaDirection video_dir =
+							    linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo);
+							if (linphone_conference_is_me(pconference, linphone_participant_device_get_address(d))) {
+								BC_ASSERT_TRUE(
+								    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) ==
+								    (video_direction == LinphoneMediaDirectionSendRecv));
+							} else {
+								BC_ASSERT_TRUE(
+								    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo) ==
+								    ((video_dir == LinphoneMediaDirectionSendRecv) ||
+								     (video_dir == LinphoneMediaDirectionSendOnly)));
+							}
+						}
+
+						if (devices) {
+							bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+						}
+
+						if (change_layout) {
+							stats mgr_stat2 = mgr->stat;
+							stats focus_stat2 = focus.getStats();
+
+							LinphoneConferenceLayout new_layout = LinphoneConferenceLayoutActiveSpeaker;
+							LinphoneCall *pcall2 = linphone_conference_get_call(pconference);
+							BC_ASSERT_PTR_NOT_NULL(pcall2);
+							if (pcall2) {
+								const LinphoneCallParams *pcall2_local_params = linphone_call_get_params(pcall2);
+								const LinphoneConferenceLayout conference_layout =
+								    linphone_call_params_get_conference_video_layout(pcall2_local_params);
+
+								if (conference_layout == LinphoneConferenceLayoutGrid) {
+									new_layout = LinphoneConferenceLayoutActiveSpeaker;
+								} else {
+									new_layout = LinphoneConferenceLayoutGrid;
+								}
+
+								LinphoneCallParams *call_params = linphone_core_create_call_params(mgr->lc, pcall2);
+								linphone_call_params_set_conference_video_layout(call_params, new_layout);
+								linphone_call_update(pcall2, call_params);
+								linphone_call_params_unref(call_params);
+							}
+
+							BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating,
+							                             mgr_stat2.number_of_LinphoneCallUpdating + 1,
+							                             liblinphone_tester_sip_timeout));
+							BC_ASSERT_TRUE(wait_for_list(
+							    coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+							    focus_stat2.number_of_LinphoneCallUpdatedByRemote + 1, liblinphone_tester_sip_timeout));
+							BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning,
+							                             mgr_stat2.number_of_LinphoneCallStreamsRunning + 1,
+							                             liblinphone_tester_sip_timeout));
+							BC_ASSERT_TRUE(wait_for_list(
+							    coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+							    focus_stat2.number_of_LinphoneCallStreamsRunning + 1, liblinphone_tester_sip_timeout));
+							if (pcall2) {
+								const LinphoneCallParams *pcall2_local_params = linphone_call_get_params(pcall2);
+								const LinphoneConferenceLayout remote_conf_layout =
+								    linphone_call_params_get_conference_video_layout(pcall2_local_params);
+								BC_ASSERT_EQUAL(new_layout, remote_conf_layout, int, "%d");
+							}
+							LinphoneConference *fconference =
+							    linphone_core_search_conference(focus.getLc(), NULL, NULL, confAddr, NULL);
+							LinphoneParticipant *participant =
+							    linphone_conference_find_participant(fconference, mgr->identity);
+							BC_ASSERT_PTR_NOT_NULL(participant);
+							if (participant) {
+								bctbx_list_t *devices = linphone_participant_get_devices(participant);
+
+								for (bctbx_list_t *it_d = devices; it_d != NULL; it_d = it_d->next) {
+									LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)it_d->data;
+									BC_ASSERT_PTR_NOT_NULL(d);
+									LinphoneCall *participant_call = linphone_core_get_call_by_remote_address2(
+									    focus.getLc(), linphone_participant_device_get_address(d));
+									BC_ASSERT_PTR_NOT_NULL(participant_call);
+									if (participant_call) {
+										const LinphoneCallParams *call_remote_params =
+										    linphone_call_get_remote_params(participant_call);
+										const LinphoneConferenceLayout device_layout =
+										    linphone_call_params_get_conference_video_layout(call_remote_params);
+										BC_ASSERT_EQUAL(device_layout, new_layout, int, "%d");
+									}
+								}
+								bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+							}
+
+							LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+							BC_ASSERT_PTR_NOT_NULL(pcall);
+							if (pcall) {
+								const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+								BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+								const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+								BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams));
+								const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+								BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams));
+							}
+
+							LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+							LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), uri);
+							BC_ASSERT_PTR_NOT_NULL(ccall);
+							if (ccall) {
+								const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+								BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+								const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+								BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams));
+								const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+								BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams));
+							}
+						}
+					}
+
+					// Wait a little bit
+					wait_for_list(coresList, NULL, 0, 1000);
+				}
+			}
+		}
+
+		const int total_marie_calls =
+		    marie.getStats().number_of_LinphoneCallEnd + (int)bctbx_list_size(linphone_core_get_calls(marie.getLc()));
+		const int total_focus_calls =
+		    focus.getStats().number_of_LinphoneCallEnd + (int)bctbx_list_size(linphone_core_get_calls(focus.getLc()));
+		const int total_pauline_calls = pauline.getStats().number_of_LinphoneCallEnd +
+		                                (int)bctbx_list_size(linphone_core_get_calls(pauline.getLc()));
+		const int total_laure_calls =
+		    laure.getStats().number_of_LinphoneCallEnd + (int)bctbx_list_size(linphone_core_get_calls(laure.getLc()));
+
+		linphone_core_terminate_all_calls(pauline.getLc());
+		linphone_core_terminate_all_calls(laure.getLc());
+		linphone_core_terminate_all_calls(marie.getLc());
+
+		// Wait for calls to be terminated
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd, total_marie_calls, 30000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallEnd, total_pauline_calls, 30000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallEnd, total_laure_calls, 30000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd, total_focus_calls, 40000));
+
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased, total_marie_calls, 30000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallReleased, total_pauline_calls, 30000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &laure.getStats().number_of_LinphoneCallReleased, total_laure_calls, 30000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased, total_focus_calls, 40000));
+
+		if (confAddr && fconference) {
+			linphone_conference_terminate(fconference);
+		}
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+
+			// Wait for all conferences to be terminated
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated,
+			                             (mgr == focus.getCMgr()) ? 3 : 1, liblinphone_tester_sip_timeout));
+
+			if (mgr && (mgr != focus.getCMgr())) {
+				LinphoneCall *participant_call =
+				    linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+				BC_ASSERT_PTR_NULL(participant_call);
+				LinphoneCall *conference_call = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+				BC_ASSERT_PTR_NULL(conference_call);
+
+				const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs),
+				                (((mgr == marie.getCMgr()) || (mgr == laure.getCMgr())) ? 3 : 2), unsigned int, "%u");
+
+				bctbx_list_t *mgr_focus_call_log =
+				    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+				BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+				if (mgr_focus_call_log) {
+					BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), (mgr == laure.getCMgr()) ? 2 : 1,
+					                unsigned int, "%u");
+					for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+						LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+						BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+					}
+					bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+				}
+			}
+		}
+
+		linphone_conference_unref(conf);
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_simple_conference_merging_calls(void) {
+	create_simple_conference_merging_calls_base(FALSE, LinphoneConferenceLayoutActiveSpeaker, FALSE, FALSE, FALSE);
+}
+
+static void create_simple_conference_merging_calls_with_video_toggling(void) {
+	create_simple_conference_merging_calls_base(FALSE, LinphoneConferenceLayoutGrid, TRUE, TRUE, TRUE);
+}
+
+static void create_simple_ice_conference_merging_calls(void) {
+	create_simple_conference_merging_calls_base(TRUE, LinphoneConferenceLayoutActiveSpeaker, TRUE, FALSE, TRUE);
+}
+
+static void create_simple_conference_with_update_deferred(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr()}) {
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, FALSE);
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, LinphoneConferenceLayoutGrid);
+			}
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, laure.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+
+		stats marie_stat = marie.getStats();
+		stats focus_stat = focus.getStats();
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
+		std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()};
+
+		time_t start_time = ms_time(NULL) + 10;
+		time_t end_time = (start_time + 300);
+		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
+		const char *description = "Paris Baker";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : members) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+		}
+
+		for (auto mgr : members) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			int no_streams_running = 2;
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, (no_streams_running - 1),
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, no_streams_running,
+			                             liblinphone_tester_sip_timeout));
+			// Update to add to conference.
+			// If ICE is enabled, the addition to a conference may go through a resume of the call
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+			                             ((mgr == marie.getCMgr()) ? 3 : 2), liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 3,
+		                             liblinphone_tester_sip_timeout));
+		int focus_no_streams_running = 6;
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + (focus_no_streams_running - 3),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + 3,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + 3, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 3,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + 3,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference);
+				int no_participants = 0;
+				if (start_time >= 0) {
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+					                (long long)start_time, long long, "%lld");
+				}
+				BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+				                (long long)end_time, long long, "%lld");
+				if (mgr == focus.getCMgr()) {
+					no_participants = 3;
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = 2;
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+
+					LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(mgr->lc);
+					bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+					linphone_video_activation_policy_unref(pol);
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 3, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+			}
+		}
+
+		// Wait a little bit
+		wait_for_list(coresList, NULL, 0, 3000);
+
+		LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(pauline_call);
+
+		LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(pauline.getLc());
+		bool_t enable = !!!linphone_video_activation_policy_get_automatically_initiate(pol);
+		linphone_video_activation_policy_unref(pol);
+
+		if (pauline_call) {
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(pauline_call);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pauline_call);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_rparams));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pauline_call);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_cparams));
+		}
+		Address paulineIdentity = pauline.getIdentity();
+		LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineIdentity.toC());
+		BC_ASSERT_PTR_NOT_NULL(focus_call);
+		if (focus_call) {
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(focus_call);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(focus_call);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_rparams));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(focus_call);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_cparams));
+		}
+
+		LinphoneAddress *paulineUri = linphone_address_new(linphone_core_get_identity(pauline.getLc()));
+		LinphoneConference *paulineConference =
+		    linphone_core_search_conference(pauline.getLc(), NULL, paulineUri, confAddr, NULL);
+		linphone_address_unref(paulineUri);
+		BC_ASSERT_PTR_NOT_NULL(paulineConference);
+
+		linphone_config_set_int(linphone_core_get_config(focus.getLc()), "sip", "defer_update_default", TRUE);
+
+		for (int i = 0; i < 4; i++) {
+			set_video_settings_in_conference(focus.getCMgr(), pauline.getCMgr(), members, confAddr, enable,
+			                                 LinphoneMediaDirectionSendRecv, !enable, LinphoneMediaDirectionSendRecv);
+
+			// Wait a little bit
+			wait_for_list(coresList, NULL, 0, 1000);
+
+			enable = !enable;
+		}
+
+		linphone_config_set_int(linphone_core_get_config(focus.getLc()), "sip", "defer_update_default", FALSE);
+
+		if (paulineConference) {
+
+			stats focus_stat2 = focus.getStats();
+			stats marie_stat2 = marie.getStats();
+			stats pauline_stat2 = pauline.getStats();
+			stats laure_stat2 = laure.getStats();
+
+			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pcall);
+			bool_t video_enabled = FALSE;
+			if (pcall) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+				video_enabled = linphone_call_params_video_enabled(call_cparams);
+			}
+
+			linphone_conference_leave(paulineConference);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallPausing,
+			                             pauline_stat2.number_of_LinphoneCallPausing + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallPaused,
+			                             pauline_stat2.number_of_LinphoneCallPaused + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallPausedByRemote,
+			                             focus_stat2.number_of_LinphoneCallPausedByRemote + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_on_hold,
+			                             focus_stat2.number_of_participant_devices_on_hold + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_on_hold,
+			                             laure_stat2.number_of_participant_devices_on_hold + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &laure.getStats().number_of_participant_devices_media_capability_changed,
+			                             laure_stat2.number_of_participant_devices_media_capability_changed + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_on_hold,
+			                             marie_stat2.number_of_participant_devices_on_hold + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &marie.getStats().number_of_participant_devices_media_capability_changed,
+			                             marie_stat2.number_of_participant_devices_media_capability_changed + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			linphone_conference_enter(paulineConference);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallResuming,
+			                             pauline_stat2.number_of_LinphoneCallResuming + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneCallStreamsRunning,
+			                             pauline_stat2.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat2.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+			                             focus_stat2.number_of_participant_devices_joined + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_participant_devices_joined,
+			                             laure_stat2.number_of_participant_devices_joined + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &laure.getStats().number_of_participant_devices_media_capability_changed,
+			                             laure_stat2.number_of_participant_devices_media_capability_changed + 2,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_joined,
+			                             marie_stat2.number_of_participant_devices_joined + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &marie.getStats().number_of_participant_devices_media_capability_changed,
+			                             marie_stat2.number_of_participant_devices_media_capability_changed + 2,
+			                             liblinphone_tester_sip_timeout));
+
+			if (pcall) {
+				const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+				BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), video_enabled, int, "%0d");
+			}
+		}
+
+		std::list<LinphoneCoreManager *> mgrsToRemove{pauline.getCMgr()};
+		mgrsToRemove.push_back(laure.getCMgr());
+
+		for (auto mgr : mgrsToRemove) {
+			LinphoneCall *call = linphone_core_get_current_call(mgr->lc);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				linphone_call_terminate(call);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				BC_ASSERT_PTR_NULL(pconference);
+				linphone_address_unref(uri);
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                             focus_stat.number_of_participants_removed + 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed,
+		                             marie_stat.number_of_participants_removed + 2, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participant_devices_removed,
+		                             marie_stat.number_of_participant_devices_removed + 2,
+		                             liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                marie_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateTerminated,
+		                marie_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(marie.getStats().number_of_LinphoneConferenceStateDeleted,
+		                marie_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr()}) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
+				                ((mgr == focus.getCMgr()) ? 1 : 0), int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 1, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+			}
+		}
+
+		const bctbx_list_t *calls = linphone_core_get_calls(marie.getLc());
+		BC_ASSERT_EQUAL(bctbx_list_size(calls), 1, size_t, "%zu");
+
+		LinphoneCall *call = linphone_core_get_call_by_remote_address2(marie.getLc(), focus.getCMgr()->identity);
+		BC_ASSERT_PTR_NOT_NULL(call);
+		if (call) {
+			linphone_call_terminate(call);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &marie.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			// Explicitely terminate conference as those on server are static by default
+			LinphoneConference *pconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				linphone_conference_terminate(pconference);
+			}
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &focus.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+			BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 1, unsigned int, "%u");
+
+			bctbx_list_t *mgr_focus_call_log =
+			    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+			if (mgr_focus_call_log) {
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u");
+				for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+					LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				}
+				bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void change_active_speaker(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity()); // audio only
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+		std::list<LinphoneCoreManager *> invitesList{pauline.getCMgr(), laure.getCMgr()};
+		std::list<LinphoneCoreManager *> participantsList{pauline.getCMgr(), laure.getCMgr(), marie.getCMgr()};
+		std::list<LinphoneCoreManager *> cmgrsList{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(),
+		                                           laure.getCMgr()};
+		for (LinphoneCoreManager *mgr : cmgrsList) {
+			if (mgr != pauline.getCMgr()) {
+				LinphoneVideoActivationPolicy *pol =
+				    linphone_factory_create_video_activation_policy(linphone_factory_get());
+				linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+				linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+				linphone_core_set_video_activation_policy(mgr->lc, pol);
+				linphone_video_activation_policy_unref(pol);
+			}
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+			linphone_core_set_video_display_filter(mgr->lc, "MSAnalyseDisplay");
+
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, LinphoneConferenceLayoutActiveSpeaker);
+			}
+
+			enable_stun_in_core(mgr, TRUE, FALSE);
+			linphone_core_manager_wait_for_stun_resolution(mgr);
+
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+		stats focus_stat = focus.getStats();
+
+		time_t start_time = ms_time(NULL);
+		int duration = -1;
+		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		const char *initialSubject = "Test group";
+		const char *description = "hello";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : invitesList) {
+			participantList.insert(std::make_pair(p, role));
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		for (LinphoneCoreManager *mgr : participantsList) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionSendRecv);
+			if (mgr != pauline.getCMgr()) {
+				linphone_call_params_enable_video(new_params, TRUE);
+			}
+			linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			int nbStreamsRunning = 2;
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, (nbStreamsRunning - 1),
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, nbStreamsRunning,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+			                             ((mgr == marie.getCMgr()) ? 3 : 2), liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+		}
+
+		{
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+			                             focus_stat.number_of_LinphoneCallIncomingReceived + 3,
+			                             liblinphone_tester_sip_timeout));
+			int focusNbStreamsRunning = 2;
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+			                  focus_stat.number_of_LinphoneCallUpdatedByRemote + 3 * (focusNbStreamsRunning - 1),
+			                  liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+			                             focus_stat.number_of_LinphoneCallStreamsRunning + 3 * focusNbStreamsRunning,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+			                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+			                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 3,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+			                             focus_stat.number_of_LinphoneSubscriptionActive + 3,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+			                             focus_stat.number_of_participants_added + 3, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+			                             focus_stat.number_of_participant_devices_added + 3,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+			                             focus_stat.number_of_participant_devices_joined + 3,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		int nbStreamsAudio = 1;
+		int nbStreamsVideo = 0;
+		int nbStreamsText = 0;
+
+		for (LinphoneCoreManager *mgr : cmgrsList) {
+			nbStreamsVideo = ((mgr != pauline.getCMgr()) ? 3 : 0);
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference);
+				int nbParticipants = 0;
+				if (start_time >= 0) {
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+					                (long long)start_time, long long, "%lld");
+				}
+				BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+				                (long long)end_time, long long, "%lld");
+				if (mgr == focus.getCMgr()) {
+					nbParticipants = 3;
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					nbParticipants = 2;
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						_linphone_call_check_nb_streams(pcall, nbStreamsAudio, nbStreamsVideo, nbStreamsText);
+					}
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						_linphone_call_check_nb_streams(ccall, nbStreamsAudio, nbStreamsVideo, nbStreamsText);
+					}
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), nbParticipants, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 3, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+			}
+		}
+
+		// need time to decode video
+		wait_for_list(coresList, NULL, 1, liblinphone_tester_sip_timeout);
+		_linphone_conference_video_change(coresList, marie.getCMgr(), pauline.getCMgr(), laure.getCMgr());
+
+		// end
+		for (LinphoneCoreManager *mgr : participantsList) {
+			LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				linphone_call_terminate(call);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+		}
+
+		// Explicitely terminate conference as those on server are static by default
+		LinphoneConference *pconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(pconference);
+		if (pconference) {
+			linphone_conference_terminate(pconference);
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : cmgrsList) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			if (mgr && (mgr != focus.getCMgr())) {
+				LinphoneCall *participant_call =
+				    linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+				BC_ASSERT_PTR_NULL(participant_call);
+				LinphoneCall *conference_call = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+				BC_ASSERT_PTR_NULL(conference_call);
+
+				const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 1, unsigned int, "%u");
+
+				bctbx_list_t *mgr_focus_call_log =
+				    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+				BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+				if (mgr_focus_call_log) {
+					BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u");
+					for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+						LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+						BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+					}
+					bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+				}
+			}
+		}
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_one_participant_conference_toggle_video_base(LinphoneConferenceLayout layout,
+                                                                bool_t enable_ice,
+                                                                bool_t enable_stun) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+			LinphoneVideoActivationPolicy *pol =
+			    linphone_factory_create_video_activation_policy(linphone_factory_get());
+			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+			linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+			linphone_core_set_video_activation_policy(mgr->lc, pol);
+			linphone_video_activation_policy_unref(pol);
+
+			linphone_core_set_video_device(mgr->lc, liblinphone_tester_mire_id);
+			linphone_core_enable_video_capture(mgr->lc, TRUE);
+			linphone_core_enable_video_display(mgr->lc, TRUE);
+
+			if (mgr != focus.getCMgr()) {
+				linphone_core_set_default_conference_layout(mgr->lc, layout);
+			}
+
+			enable_stun_in_core(mgr, enable_stun, enable_ice);
+			linphone_core_manager_wait_for_stun_resolution(mgr);
+
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		stats focus_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr()};
+
+		time_t start_time = ms_time(NULL);
+		int duration = -1;
+		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
+		const char *description = "- <F2><F3>\n\\çà";
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
+		                                                        initialSubject, description, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : {marie.getCMgr()}) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+			linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionSendRecv);
+			linphone_call_params_enable_video(new_params, TRUE);
+			linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+			linphone_call_params_unref(new_params);
+		}
+
+		for (auto mgr : {marie.getCMgr()}) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			int no_streams_running = ((enable_ice) ? 3 : 2);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating, (no_streams_running - 1),
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, no_streams_running,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated,
+			                             ((mgr == marie.getCMgr()) ? 3 : 2), liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		int focus_no_streams_running = ((enable_ice) ? 3 : 2);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + (focus_no_streams_running - 1),
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		int no_streams_audio = 1;
+		int no_streams_video = 2;
+		int no_active_streams_video = (layout == LinphoneConferenceLayoutGrid) ? 0 : 1;
+		int no_streams_text = 0;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr()}) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(pconference);
+				int no_participants = 0;
+				if (start_time >= 0) {
+					BC_ASSERT_EQUAL((long long)linphone_conference_params_get_start_time(conference_params),
+					                (long long)start_time, long long, "%lld");
+				}
+				BC_ASSERT_EQUAL((long long)linphone_conference_params_get_end_time(conference_params),
+				                (long long)end_time, long long, "%lld");
+				if (mgr == focus.getCMgr()) {
+					no_participants = 1;
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = 0;
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+					if (enable_ice) {
+						BC_ASSERT_TRUE(check_ice(mgr, focus.getCMgr(), LinphoneIceStateHostConnection));
+					}
+
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						_linphone_call_check_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams));
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams));
+					}
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						_linphone_call_check_nb_streams(ccall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+						BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+						BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams));
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams));
+					}
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 1, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+			}
+		}
+
+		focus_stat = focus.getStats();
+		marie_stat = marie.getStats();
+
+		LinphoneCall *marie_calls_focus = linphone_core_get_call_by_remote_address2(marie.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(marie_calls_focus);
+		LinphoneCall *focus_called_by_marie =
+		    linphone_core_get_call_by_remote_address2(focus.getLc(), marie.getCMgr()->identity);
+		BC_ASSERT_PTR_NOT_NULL(focus_called_by_marie);
+
+		LinphoneParticipant *marie_participant =
+		    linphone_conference_find_participant(fconference, marie.getCMgr()->identity);
+		BC_ASSERT_PTR_NOT_NULL(marie_participant);
+		if (marie_participant) {
+			bctbx_list_t *devices = linphone_participant_get_devices(marie_participant);
+			for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+				LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+				LinphoneMediaDirection video_direction = (layout == LinphoneConferenceLayoutGrid)
+				                                             ? LinphoneMediaDirectionSendOnly
+				                                             : LinphoneMediaDirectionSendRecv;
+				BC_ASSERT_TRUE(linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+				               video_direction);
+				BC_ASSERT_TRUE(linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+			}
+			if (devices) {
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			}
+		}
+
+		if (marie_calls_focus) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(marie.getLc(), marie_calls_focus);
+			linphone_call_params_enable_video(new_params, TRUE);
+			linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionRecvOnly);
+			linphone_call_update(marie_calls_focus, new_params);
+			linphone_call_params_unref(new_params);
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+		                             marie_stat.number_of_LinphoneCallUpdating + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(
+		    coresList, &marie.getStats().number_of_participant_devices_media_capability_changed,
+		    marie_stat.number_of_participant_devices_media_capability_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(
+		    coresList, &focus.getStats().number_of_participant_devices_media_capability_changed,
+		    focus_stat.number_of_participant_devices_media_capability_changed + 1, liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		if (marie_calls_focus) {
+			_linphone_call_check_nb_streams(marie_calls_focus, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(marie_calls_focus, no_streams_audio, no_active_streams_video,
+			                                       no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+		}
+		if (focus_called_by_marie) {
+			_linphone_call_check_nb_streams(focus_called_by_marie, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(focus_called_by_marie, no_streams_audio, no_active_streams_video,
+			                                       no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+		}
+
+		if (marie_participant) {
+			bctbx_list_t *devices = linphone_participant_get_devices(marie_participant);
+			for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+				LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+				LinphoneMediaDirection video_direction = (layout == LinphoneConferenceLayoutGrid)
+				                                             ? LinphoneMediaDirectionInactive
+				                                             : LinphoneMediaDirectionRecvOnly;
+				BC_ASSERT_TRUE(linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+				               video_direction);
+				BC_ASSERT_FALSE(linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+			}
+			if (devices) {
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			}
+		}
+
+		focus_stat = focus.getStats();
+		marie_stat = marie.getStats();
+
+		if (marie_calls_focus) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(marie.getLc(), marie_calls_focus);
+			linphone_call_params_enable_video(new_params, TRUE);
+			linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionSendRecv);
+			linphone_call_update(marie_calls_focus, new_params);
+			linphone_call_params_unref(new_params);
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+		                             marie_stat.number_of_LinphoneCallUpdating + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(
+		    coresList, &marie.getStats().number_of_participant_devices_media_capability_changed,
+		    marie_stat.number_of_participant_devices_media_capability_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(
+		    coresList, &focus.getStats().number_of_participant_devices_media_capability_changed,
+		    focus_stat.number_of_participant_devices_media_capability_changed + 1, liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		if (marie_calls_focus) {
+			_linphone_call_check_nb_streams(marie_calls_focus, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(marie_calls_focus, no_streams_audio, no_streams_video,
+			                                       no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams));
+		}
+		if (focus_called_by_marie) {
+			_linphone_call_check_nb_streams(focus_called_by_marie, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(focus_called_by_marie, no_streams_audio, no_streams_video,
+			                                       no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams));
+		}
+
+		if (marie_participant) {
+			bctbx_list_t *devices = linphone_participant_get_devices(marie_participant);
+			for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+				LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+				LinphoneMediaDirection video_direction = (layout == LinphoneConferenceLayoutGrid)
+				                                             ? LinphoneMediaDirectionSendOnly
+				                                             : LinphoneMediaDirectionSendRecv;
+				BC_ASSERT_TRUE(linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+				               video_direction);
+				BC_ASSERT_TRUE(linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+			}
+			if (devices) {
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			}
+		}
+
+		focus_stat = focus.getStats();
+		marie_stat = marie.getStats();
+
+		if (marie_calls_focus) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(marie.getLc(), marie_calls_focus);
+			linphone_call_params_enable_video(new_params, FALSE);
+			linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionRecvOnly);
+			linphone_call_update(marie_calls_focus, new_params);
+			linphone_call_params_unref(new_params);
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+		                             marie_stat.number_of_LinphoneCallUpdating + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(
+		    coresList, &marie.getStats().number_of_participant_devices_media_capability_changed,
+		    marie_stat.number_of_participant_devices_media_capability_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(
+		    coresList, &focus.getStats().number_of_participant_devices_media_capability_changed,
+		    focus_stat.number_of_participant_devices_media_capability_changed + 1, liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		if (marie_calls_focus) {
+			_linphone_call_check_nb_streams(marie_calls_focus, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(marie_calls_focus, no_streams_audio, 0, no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(marie_calls_focus);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(marie_calls_focus);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_rparams));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(marie_calls_focus);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_cparams));
+		}
+		if (focus_called_by_marie) {
+			_linphone_call_check_nb_streams(focus_called_by_marie, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(focus_called_by_marie, no_streams_audio, 0, no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(focus_called_by_marie);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(focus_called_by_marie);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_rparams));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(focus_called_by_marie);
+			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_cparams));
+		}
+
+		if (marie_participant) {
+			bctbx_list_t *devices = linphone_participant_get_devices(marie_participant);
+			for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+				LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+				LinphoneMediaDirection video_direction = LinphoneMediaDirectionInactive;
+				BC_ASSERT_TRUE(linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+				               video_direction);
+				BC_ASSERT_FALSE(linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+			}
+			if (devices) {
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			}
+		}
+
+		focus_stat = focus.getStats();
+		marie_stat = marie.getStats();
+
+		if (marie_calls_focus) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(marie.getLc(), marie_calls_focus);
+			linphone_call_params_enable_video(new_params, TRUE);
+			linphone_call_update(marie_calls_focus, new_params);
+			linphone_call_params_unref(new_params);
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+		                             marie_stat.number_of_LinphoneCallUpdating + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		if (layout == LinphoneConferenceLayoutGrid) {
+			BC_ASSERT_FALSE(wait_for_list(coresList,
+			                              &marie.getStats().number_of_participant_devices_media_capability_changed,
+			                              marie_stat.number_of_participant_devices_media_capability_changed + 1, 2000));
+		} else {
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &marie.getStats().number_of_participant_devices_media_capability_changed,
+			                             marie_stat.number_of_participant_devices_media_capability_changed + 1, 2000));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		if (layout == LinphoneConferenceLayoutGrid) {
+			BC_ASSERT_FALSE(wait_for_list(coresList,
+			                              &focus.getStats().number_of_participant_devices_media_capability_changed,
+			                              focus_stat.number_of_participant_devices_media_capability_changed + 1, 2000));
+		} else {
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &focus.getStats().number_of_participant_devices_media_capability_changed,
+			                             focus_stat.number_of_participant_devices_media_capability_changed + 1, 2000));
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		if (marie_calls_focus) {
+			_linphone_call_check_nb_streams(marie_calls_focus, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(marie_calls_focus, no_streams_audio, no_active_streams_video,
+			                                       no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+		}
+		if (focus_called_by_marie) {
+			_linphone_call_check_nb_streams(focus_called_by_marie, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(focus_called_by_marie, no_streams_audio, no_active_streams_video,
+			                                       no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams) !=
+			               (layout == LinphoneConferenceLayoutGrid));
+		}
+
+		if (marie_participant) {
+			bctbx_list_t *devices = linphone_participant_get_devices(marie_participant);
+			for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+				LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+				LinphoneMediaDirection video_direction = (layout == LinphoneConferenceLayoutGrid)
+				                                             ? LinphoneMediaDirectionInactive
+				                                             : LinphoneMediaDirectionRecvOnly;
+				BC_ASSERT_TRUE(linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+				               video_direction);
+				BC_ASSERT_FALSE(linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+			}
+			if (devices) {
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			}
+		}
+
+		focus_stat = focus.getStats();
+		marie_stat = marie.getStats();
+
+		if (marie_calls_focus) {
+			LinphoneCallParams *new_params = linphone_core_create_call_params(marie.getLc(), marie_calls_focus);
+			linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionSendRecv);
+			linphone_call_update(marie_calls_focus, new_params);
+			linphone_call_params_unref(new_params);
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallUpdating,
+		                             marie_stat.number_of_LinphoneCallUpdating + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+		                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(
+		    coresList, &marie.getStats().number_of_participant_devices_media_capability_changed,
+		    marie_stat.number_of_participant_devices_media_capability_changed + 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+		                             focus_stat.number_of_LinphoneCallUpdatedByRemote + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(
+		    coresList, &focus.getStats().number_of_participant_devices_media_capability_changed,
+		    focus_stat.number_of_participant_devices_media_capability_changed + 1, liblinphone_tester_sip_timeout));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
+
+		if (marie_calls_focus) {
+			_linphone_call_check_nb_streams(marie_calls_focus, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(marie_calls_focus, no_streams_audio, no_streams_video,
+			                                       no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(marie_calls_focus);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams));
+		}
+		if (focus_called_by_marie) {
+			_linphone_call_check_nb_streams(focus_called_by_marie, no_streams_audio, no_streams_video, no_streams_text);
+			_linphone_call_check_nb_active_streams(focus_called_by_marie, no_streams_audio, no_streams_video,
+			                                       no_streams_text);
+			const LinphoneCallParams *call_lparams = linphone_call_get_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_lparams));
+			const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_rparams));
+			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(focus_called_by_marie);
+			BC_ASSERT_TRUE(linphone_call_params_video_enabled(call_cparams));
+		}
+
+		if (marie_participant) {
+			bctbx_list_t *devices = linphone_participant_get_devices(marie_participant);
+			for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+				LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+				LinphoneMediaDirection video_direction = (layout == LinphoneConferenceLayoutGrid)
+				                                             ? LinphoneMediaDirectionSendOnly
+				                                             : LinphoneMediaDirectionSendRecv;
+				BC_ASSERT_TRUE(linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeVideo) ==
+				               video_direction);
+				BC_ASSERT_TRUE(linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+			}
+			if (devices) {
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			}
+		}
+
+		LinphoneCall *call = linphone_core_get_call_by_remote_address2(marie.getLc(), focus.getCMgr()->identity);
+		BC_ASSERT_PTR_NOT_NULL(call);
+		if (call) {
+			linphone_call_terminate(call);
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallEnd, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallReleased, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &marie.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			// Explicitely terminate conference as those on server are static by default
+			LinphoneConference *pconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				linphone_conference_terminate(pconference);
+			}
+			BC_ASSERT_TRUE(wait_for_list(coresList,
+			                             &focus.getStats().number_of_LinphoneConferenceStateTerminationPending, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+			                             liblinphone_tester_sip_timeout));
+		}
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr()}) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+			                             liblinphone_tester_sip_timeout));
+
+			if (mgr && (mgr != focus.getCMgr())) {
+				LinphoneCall *participant_call =
+				    linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+				BC_ASSERT_PTR_NULL(participant_call);
+				LinphoneCall *conference_call = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+				BC_ASSERT_PTR_NULL(conference_call);
+
+				const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 1, unsigned int, "%u");
+
+				bctbx_list_t *mgr_focus_call_log =
+				    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+				BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+				if (mgr_focus_call_log) {
+					BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u");
+					for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+						LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+						BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+					}
+					bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+				}
+			}
+		}
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void one_participant_conference_toggles_video_grid(void) {
+	create_one_participant_conference_toggle_video_base(LinphoneConferenceLayoutGrid, FALSE, FALSE);
+}
+
+static void one_participant_conference_toggles_video_active_speaker(void) {
+	create_one_participant_conference_toggle_video_base(LinphoneConferenceLayoutActiveSpeaker, FALSE, FALSE);
+}
+
+static void create_conference_with_active_call_base(bool_t dialout) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(laure);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(berthe);
+
+		setup_conference_info_cbs(marie.getCMgr());
+
+		bctbx_list_t *coresList = NULL;
+
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
+		                 berthe.getCMgr()}) {
+			coresList = bctbx_list_append(coresList, mgr->lc);
+		}
+
+		linphone_core_set_file_transfer_server(marie.getLc(), file_transfer_url);
+
+		stats focus_stat = focus.getStats();
+		stats marie_stat = marie.getStats();
+		stats berthe_stat = berthe.getStats();
+
+		std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(),
+		                                                laure.getCMgr(), michelle.getCMgr()};
+		std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(),
+		                                         michelle.getCMgr()};
+		std::list<LinphoneCoreManager *> participants{pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr()};
+
+		const char *initialSubject = "Schedule of the trip towards the top of Europe";
+		const char *description = "To the top of the Mont Blanc!!!! :-)";
+
+		time_t start_time = (dialout) ? -1 : (ms_time(NULL) + 10);
+		bool_t send_ics = TRUE;
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleListener));
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, -1,
+		                                                        initialSubject, description, send_ics);
+		BC_ASSERT_PTR_NOT_NULL(confAddr);
+
+		// the conference server calls Berthe  - who knows why......
+		LinphoneCallParams *new_params = linphone_core_create_call_params(berthe.getLc(), NULL);
+
+		LinphoneContent *content = linphone_core_create_content(berthe.getLc());
+		linphone_content_set_type(content, "application");
+		linphone_content_set_subtype(content, "resource-lists+xml");
+
+		static const char *info_content = "<p1:resource-lists xmlns:p1=\"urn:ietf:params:xml:ns:resource-lists\">\n\
+<p1:list>\n\
+  <p1:entry uri=\"sip:laure@sip.example.org\"/>\n\
+  <p1:entry uri=\"sip:michelle@sip.example.org\"/>\n\
+  <p1:entry uri=\"sip:pauline@sip.example.org\"/>\n\
+</p1:list>\n\
+</p1:resource-lists>";
+		linphone_content_set_buffer(content, (const uint8_t *)info_content, strlen(info_content));
+		linphone_call_params_add_custom_content(new_params, content);
+
+		LinphoneCall *berthe_focus_call =
+		    linphone_core_invite_address_with_params_2(berthe.getLc(), confAddr, new_params, NULL, nullptr);
+		BC_ASSERT_PTR_NOT_NULL(berthe_focus_call);
+		linphone_content_unref(content);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallOutgoingInit,
+		                             berthe_stat.number_of_LinphoneCallOutgoingInit + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+		                             focus_stat.number_of_LinphoneCallIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallStreamsRunning,
+		                             berthe_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                             focus_stat.number_of_LinphoneCallStreamsRunning + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		if (dialout) {
+			BC_ASSERT_PTR_NULL(linphone_core_get_current_call(focus.getLc()));
+		} else {
+			BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(focus.getLc()));
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 1, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionTerminated,
+		                             focus_stat.number_of_LinphoneSubscriptionTerminated + 1, 5000));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionError, 1, 5000));
+		if (dialout) {
+			// Chat room creation to send ICS
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+			                             (send_ics ? 2 : 1), liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallOutgoingInit,
+			                             marie_stat.number_of_LinphoneCallOutgoingInit + 1,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallOutgoingInit,
+			                             focus_stat.number_of_LinphoneCallOutgoingInit + 3,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
+			                             focus_stat.number_of_LinphoneCallIncomingReceived + 2,
+			                             liblinphone_tester_sip_timeout));
+
+			for (auto mgr : participants) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+			                             marie_stat.number_of_LinphoneCallStreamsRunning + 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallStreamsRunning,
+			                             marie_stat.number_of_LinphoneCallStreamsRunning + 2,
+			                             liblinphone_tester_sip_timeout));
+
+			LinphoneConference *oconference = linphone_core_search_conference_2(marie.getLc(), confAddr);
+			if (BC_ASSERT_PTR_NOT_NULL(oconference)) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(oconference), 3, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(oconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), 4, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+			}
+
+			if (confAddr) {
+				for (auto mgr : participants) {
+					LinphoneConferenceInfo *info =
+					    linphone_core_find_conference_information_from_uri(mgr->lc, confAddr);
+					if (BC_ASSERT_PTR_NOT_NULL(info)) {
+						BC_ASSERT_TRUE(linphone_address_weak_equal(marie.getCMgr()->identity,
+						                                           linphone_conference_info_get_organizer(info)));
+						BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
+
+						const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+						BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu");
+
+						BC_ASSERT_NOT_EQUAL((long long)linphone_conference_info_get_date_time(info), 0, long long,
+						                    "%lld");
+						const int duration_m = linphone_conference_info_get_duration(info);
+						BC_ASSERT_EQUAL(duration_m, 0, int, "%d");
+						if (initialSubject) {
+							BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(info), initialSubject);
+						} else {
+							BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(info));
+						}
+						if (send_ics) {
+							BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(info), description);
+						} else {
+							BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(info));
+						}
+						linphone_conference_info_unref(info);
+					}
+
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						LinphoneCallLog *call_log = linphone_call_get_call_log(pcall);
+						BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+						linphone_call_accept(pcall);
+					}
+				}
+			}
+		} else {
+			for (auto mgr : members) {
+				LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
+				linphone_core_invite_address_with_params_2(mgr->lc, confAddr, new_params, NULL, nullptr);
+				linphone_call_params_unref(new_params);
+			}
+
+			for (auto mgr : members) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
+				                             liblinphone_tester_sip_timeout));
+				int no_streams_running = 2;
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallUpdating,
+				                             (no_streams_running - 1), liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning,
+				                             no_streams_running, liblinphone_tester_sip_timeout));
+			}
+		}
+		linphone_call_params_unref(new_params);
+
+		for (auto mgr : participants) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,
+			                             liblinphone_tester_sip_timeout));
+
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, 5000));
+			BC_ASSERT_TRUE(
+			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+
+			LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr);
+			if (BC_ASSERT_PTR_NOT_NULL(info)) {
+				BC_ASSERT_TRUE(linphone_address_weak_equal(marie.getCMgr()->identity,
+				                                           linphone_conference_info_get_organizer(info)));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
+
+				const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+				// Original participants + Marie who joined the conference
+				BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu");
+
+				BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld");
+				const int duration_m = linphone_conference_info_get_duration(info);
+				BC_ASSERT_EQUAL(duration_m, 0, int, "%d");
+				if (initialSubject) {
+					BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(info), initialSubject);
+				} else {
+					BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(info));
+				}
+				if (send_ics) {
+					BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(info), description);
+				} else {
+					BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(info));
+				}
+				linphone_conference_info_unref(info);
+			}
+
+			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pcall);
+			if (pcall) {
+				LinphoneCallLog *call_log = linphone_call_get_call_log(pcall);
+				BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log);
+				if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) {
+					BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_conference_info_get_organizer(call_log_info),
+					                                           marie.getCMgr()->identity));
+					BC_ASSERT_TRUE(
+					    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
+
+					const bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
+					// Original participants + Marie who joined the conference
+					BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu");
+					BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0,
+					                         long long, "%lld");
+					const int duration_m = linphone_conference_info_get_duration(call_log_info);
+					BC_ASSERT_EQUAL(duration_m, 0, int, "%d");
+					if (initialSubject) {
+						BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(call_log_info), initialSubject);
+					} else {
+						BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(call_log_info));
+					}
+					if (send_ics) {
+						BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(call_log_info), description);
+					} else {
+						BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(call_log_info));
+					}
+				}
+			}
+		}
+
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+		                  focus_stat.number_of_LinphoneCallStreamsRunning + static_cast<int>(participants.size() + 1),
+		                  liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
+		                             marie_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionOutgoingProgress,
+		                             marie_stat.number_of_LinphoneSubscriptionOutgoingProgress + 1, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
+		                             marie_stat.number_of_LinphoneSubscriptionActive + 1, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_NotifyReceived,
+		                             marie_stat.number_of_NotifyReceived + 1, liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
+		                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 5, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + 4, 5000));
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
+		                             focus_stat.number_of_participants_added + 4, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_added,
+		                             focus_stat.number_of_participant_devices_added + 4,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_joined,
+		                             focus_stat.number_of_participant_devices_joined + 4,
+		                             liblinphone_tester_sip_timeout));
+
+		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
+		BC_ASSERT_PTR_NOT_NULL(fconference);
+
+		for (auto mgr : conferenceMgrs) {
+			// wait bit more to detect side effect if any
+			CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe})
+			    .waitUntil(chrono::seconds(50), [mgr, &focus, &members, confAddr, &participantList] {
+				    size_t nb_audio_streams = 1;
+				    size_t nb_video_streams = 0;
+				    size_t nb_text_streams = 0;
+				    std::list<LinphoneCall *> calls;
+
+				    if (mgr == focus.getCMgr()) {
+					    for (auto m : members) {
+						    LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, m->identity);
+						    BC_ASSERT_PTR_NOT_NULL(call);
+						    if (call) {
+							    calls.push_back(call);
+						    } else {
+							    return false;
+						    }
+					    }
+				    } else {
+					    LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					    BC_ASSERT_PTR_NOT_NULL(call);
+					    if (call) {
+						    calls.push_back(call);
+					    } else {
+						    return false;
+					    }
+				    }
+
+				    for (auto call : calls) {
+					    if (call) {
+						    const SalMediaDescription *call_result_desc = _linphone_call_get_result_desc(call);
+						    if (!((call_result_desc->getNbStreams() ==
+						           nb_audio_streams + nb_video_streams + nb_text_streams) &&
+						          (call_result_desc->nbStreamsOfType(SalAudio) == nb_audio_streams) &&
+						          (call_result_desc->nbStreamsOfType(SalVideo) == nb_video_streams) &&
+						          (call_result_desc->nbStreamsOfType(SalText) == nb_text_streams) &&
+						          (linphone_call_get_state(call) == LinphoneCallStateStreamsRunning))) {
+							    return false;
+						    }
+					    }
+				    }
+
+				    bool video_check = true;
+				    LinphoneConference *conference = linphone_core_search_conference_2(mgr->lc, confAddr);
+				    BC_ASSERT_PTR_NOT_NULL(conference);
+				    if (conference) {
+					    bctbx_list_t *devices = linphone_conference_get_participant_device_list(conference);
+					    for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+						    LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+						    video_check &=
+						        !linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo);
+					    }
+
+					    if (devices) {
+						    bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+					    }
+				    }
+				    if (!video_check) {
+					    return false;
+				    }
+
+				    bool role_check = true;
+				    for (auto m : participantList) {
+					    LinphoneCoreManager *mMgr = m.first;
+					    LinphoneParticipantRole role = m.second;
+					    LinphoneParticipant *p = linphone_conference_is_me(conference, mMgr->identity)
+					                                 ? linphone_conference_get_me(conference)
+					                                 : linphone_conference_find_participant(conference, mMgr->identity);
+					    role_check &= (p != nullptr);
+					    if (p) {
+						    role_check &= (linphone_participant_get_role(p) == role);
+					    }
+				    }
+				    return role_check;
+			    });
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(15), [] {
+			return false;
+		});
+
+		for (auto mgr : conferenceMgrs) {
+			LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			linphone_address_unref(uri);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				int no_participants = 0;
+				if (mgr == focus.getCMgr()) {
+					no_participants = (dialout) ? 4 : 5;
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+
+					int focus_no_streams_running = 8;
+					int focus_no_updating = focus_no_streams_running - 4;
+					BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallUpdatedByRemote,
+					                             focus_stat.number_of_LinphoneCallUpdatedByRemote + focus_no_updating,
+					                             liblinphone_tester_sip_timeout));
+					BC_ASSERT_TRUE(
+					    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
+					                  focus_stat.number_of_LinphoneCallStreamsRunning + focus_no_streams_running,
+					                  liblinphone_tester_sip_timeout));
+				} else {
+					no_participants = (dialout) ? 3 : 4;
+					BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
+					LinphoneCall *current_call = linphone_core_get_current_call(mgr->lc);
+					BC_ASSERT_PTR_NOT_NULL(current_call);
+					if (current_call) {
+						BC_ASSERT_EQUAL((int)linphone_call_get_state(current_call),
+						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
+					}
+
+					bool_t enabled = FALSE;
+					int no_streams_audio = 1;
+					int no_streams_video = 0;
+					int no_active_streams_video = 0;
+					int no_streams_text = 0;
+
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
+					BC_ASSERT_PTR_NOT_NULL(pcall);
+					if (pcall) {
+						_linphone_call_check_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+
+					LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
+					BC_ASSERT_PTR_NOT_NULL(ccall);
+					if (ccall) {
+						_linphone_call_check_nb_streams(ccall, no_streams_audio, no_streams_video, no_streams_text);
+						_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_active_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_lparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_rparams), enabled, int, "%0d");
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_EQUAL(linphone_call_params_video_enabled(call_cparams), enabled, int, "%0d");
+					}
+				}
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), no_participants, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), (dialout) ? 4 : 5, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+				LinphoneParticipant *me = linphone_conference_get_me(pconference);
+				BC_ASSERT_TRUE(linphone_participant_is_admin(me) ==
+				               ((mgr == marie.getCMgr()) || (mgr == focus.getCMgr())));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_get_address(me), mgr->identity));
+				bctbx_list_t *participants = linphone_conference_get_participant_list(pconference);
+				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
+					BC_ASSERT_TRUE(
+					    linphone_participant_is_admin(p) ==
+					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
+				}
+				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_ssrc(fconference, pconference);
+				}
+
+				LinphoneConference *conference = linphone_core_search_conference_2(mgr->lc, confAddr);
+				BC_ASSERT_PTR_NOT_NULL(conference);
+				if (conference) {
+					bctbx_list_t *devices = linphone_conference_get_participant_device_list(conference);
+					for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+						LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+						BC_ASSERT_FALSE(
+						    linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo));
+					}
+
+					if (devices) {
+						bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+					}
+				}
+			}
+		}
+
+		focus_stat = focus.getStats();
+		for (auto mgr : members) {
+			LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, focus.getCMgr()->identity);
+			BC_ASSERT_PTR_NOT_NULL(call);
+			if (call) {
+				ms_message("%s is terminating call with %s", linphone_core_get_identity(mgr->lc),
+				           linphone_core_get_identity(focus.getLc()));
+				linphone_call_terminate(call);
+				BC_ASSERT_TRUE(
+				    wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallReleased, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending,
+				                             1, liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminated, 1,
+				                             liblinphone_tester_sip_timeout));
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateDeleted, 1,
+				                             liblinphone_tester_sip_timeout));
+
+				LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
+				LinphoneConference *pconference = linphone_core_search_conference(mgr->lc, NULL, uri, confAddr, NULL);
+				BC_ASSERT_PTR_NULL(pconference);
+				linphone_address_unref(uri);
+			}
+		}
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                             focus_stat.number_of_LinphoneCallEnd + 4, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                             focus_stat.number_of_LinphoneCallReleased + 4, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionTerminated,
+		                             focus_stat.number_of_LinphoneSubscriptionTerminated + 4,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+		                             focus_stat.number_of_participants_removed + 4, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+		                             focus_stat.number_of_participant_devices_removed + 4,
+		                             liblinphone_tester_sip_timeout));
+
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                focus_stat.number_of_LinphoneConferenceStateTerminationPending, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateTerminated,
+		                focus_stat.number_of_LinphoneConferenceStateTerminated, int, "%d");
+		BC_ASSERT_EQUAL(focus.getStats().number_of_LinphoneConferenceStateDeleted,
+		                focus_stat.number_of_LinphoneConferenceStateDeleted, int, "%d");
+
+		for (auto mgr : {focus.getCMgr()}) {
+			LinphoneConference *pconference = linphone_core_search_conference_2(mgr->lc, confAddr);
+			BC_ASSERT_PTR_NOT_NULL(pconference);
+			if (pconference) {
+				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference), (dialout) ? 0 : 1, int, "%0d");
+				bctbx_list_t *devices = linphone_conference_get_participant_device_list(pconference);
+				BC_ASSERT_EQUAL(bctbx_list_size(devices), (dialout) ? 0 : 1, size_t, "%zu");
+				if (devices) {
+					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+				}
+				BC_ASSERT_STRING_EQUAL(linphone_conference_get_subject(pconference), initialSubject);
+			}
+		}
+
+		const bctbx_list_t *calls = linphone_core_get_calls(focus.getLc());
+		BC_ASSERT_EQUAL(bctbx_list_size(calls), 1, size_t, "%zu");
+
+		LinphoneCall *focus_berthe_call =
+		    linphone_core_get_call_by_remote_address2(focus.getLc(), berthe.getCMgr()->identity);
+		BC_ASSERT_PTR_NOT_NULL(focus_berthe_call);
+		if (focus_berthe_call) {
+			linphone_call_terminate(focus_berthe_call);
+		}
+
+		if (!dialout) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_removed,
+			                             focus_stat.number_of_participants_removed + 5,
+			                             liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participant_devices_removed,
+			                             focus_stat.number_of_participant_devices_removed + 5,
+			                             liblinphone_tester_sip_timeout));
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd,
+		                             focus_stat.number_of_LinphoneCallEnd + 5, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased,
+		                             focus_stat.number_of_LinphoneCallReleased + 5, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallEnd, 1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneCallReleased, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		// Explicitely terminate conference as those on server are static by default
+		if (fconference) {
+			linphone_conference_terminate(fconference);
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminationPending,
+		                             1, liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateTerminated, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
+		                             liblinphone_tester_sip_timeout));
+
+		for (auto mgr : members) {
+			const bctbx_list_t *call_logs = linphone_core_get_call_logs(mgr->lc);
+			BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(call_logs), 1, unsigned int, "%u");
+
+			bctbx_list_t *mgr_focus_call_log =
+			    linphone_core_get_call_history_2(mgr->lc, focus.getCMgr()->identity, mgr->identity);
+			BC_ASSERT_PTR_NOT_NULL(mgr_focus_call_log);
+			if (mgr_focus_call_log) {
+				BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(mgr_focus_call_log), 1, unsigned int, "%u");
+				for (bctbx_list_t *it = mgr_focus_call_log; it; it = bctbx_list_next(it)) {
+					LinphoneCallLog *call_log = (LinphoneCallLog *)it->data;
+					BC_ASSERT_TRUE(linphone_call_log_was_conference(call_log));
+				}
+				bctbx_list_free_with_data(mgr_focus_call_log, (bctbx_list_free_func)linphone_call_log_unref);
+			}
+
+			LinphoneConferenceInfo *info = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr);
+			if (BC_ASSERT_PTR_NOT_NULL(info)) {
+				BC_ASSERT_TRUE(linphone_address_weak_equal(marie.getCMgr()->identity,
+				                                           linphone_conference_info_get_organizer(info)));
+				BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
+
+				const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+				// Original participants + Marie who joined the conference
+				BC_ASSERT_EQUAL(bctbx_list_size(info_participants), (dialout) ? 4 : 5, size_t, "%zu");
+
+				BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld");
+				const int duration_m = linphone_conference_info_get_duration(info);
+				BC_ASSERT_EQUAL(duration_m, 0, int, "%d");
+				if (initialSubject) {
+					BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_subject(info), initialSubject);
+				} else {
+					BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(info));
+				}
+				if (send_ics || (mgr == marie.getCMgr())) {
+					BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(info), description);
+				} else {
+					BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(info));
+				}
+				linphone_conference_info_unref(info);
+			}
+		}
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(2), [] {
+			return false;
+		});
+
+		linphone_address_unref(confAddr);
+		bctbx_list_free(coresList);
+	}
+}
+
+static void create_dial_out_conference_with_active_call(void) {
+	create_conference_with_active_call_base(TRUE);
+}
+
+static void create_scheduled_conference_with_active_call(void) {
+	create_conference_with_active_call_base(FALSE);
+}
+
+} // namespace LinphoneTest
+
+static test_t local_conference_chat_tests[] = {
+    TEST_ONE_TAG("Group chat room creation local server",
+                 LinphoneTest::group_chat_room_creation_server,
+                 "LeaksMemory"), /* beacause of coreMgr restart*/
+    TEST_NO_TAG("Group chat Server chat room deletion", LinphoneTest::group_chat_room_server_deletion),
+    TEST_ONE_TAG("Group chat with client removed added",
+                 LinphoneTest::group_chat_room_with_client_removed_added,
+                 "LeaksMemory"), /* beacause of coreMgr restart*/
+    TEST_ONE_TAG("Group chat with client restart",
+                 LinphoneTest::group_chat_room_with_client_restart,
+                 "LeaksMemory"), /* beacause of coreMgr restart*/
+    TEST_NO_TAG("Group chat room bulk notify to participant",
+                LinphoneTest::group_chat_room_bulk_notify_to_participant), /* because of network up and down*/
+    TEST_ONE_TAG("One to one chatroom exhumed while participant is offline",
+                 LinphoneTest::one_to_one_chatroom_exhumed_while_offline,
+                 "LeaksMemory"), /* because of network up and down*/
+    TEST_ONE_TAG("Group chat Server chat room deletion with remote list event handler",
+                 LinphoneTest::group_chat_room_server_deletion_with_rmt_lst_event_handler,
+                 "LeaksMemory"), /* because of coreMgr restart*/
+    TEST_ONE_TAG("One to one group chat deletion initiated by server and client",
+                 LinphoneTest::one_to_one_group_chat_room_deletion_by_server_client,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_ONE_TAG("Group chat room deletes chatroom after restart",
+                 LinphoneTest::group_chat_room_with_client_deletes_chatroom_after_restart,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_ONE_TAG("Multi domain chatroom",
+                 LinphoneTest::multidomain_group_chat_room,
+                 "LeaksMemory") /* because of coreMgr restart*/
+};
+
+static test_t local_conference_chat_error_tests[] = {
+    TEST_ONE_TAG("Group chat with INVITE session error",
+                 LinphoneTest::group_chat_room_with_invite_error,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_ONE_TAG("Group chat with SUBSCRIBE session error",
+                 LinphoneTest::group_chat_room_with_subscribe_error,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_NO_TAG("Group chat Add participant with invalid address",
+                LinphoneTest::group_chat_room_add_participant_with_invalid_address),
+    TEST_NO_TAG("Group chat Only participant with invalid address",
+                LinphoneTest::group_chat_room_with_only_participant_with_invalid_address),
+
+};
+
+static test_t local_conference_chat_imdn_tests[] = {
+    TEST_ONE_TAG("Group chat with client IMDN after restart",
+                 LinphoneTest::group_chat_room_with_client_idmn_after_restart,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_NO_TAG("Group chat Lime Server chat room send imdn error",
+                LinphoneTest::group_chat_room_lime_session_corrupted),
+    TEST_ONE_TAG("Secure one to one group chat deletion initiated by server and client",
+                 LinphoneTest::secure_one_to_one_group_chat_room_deletion_by_server_client,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_ONE_TAG("Secure group chat with client IMDN sent after restart",
+                 LinphoneTest::secure_group_chat_room_with_client_idmn_sent_after_restart,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_ONE_TAG("Secure group chat with client IMDN sent after restart and participant added",
+                 LinphoneTest::secure_group_chat_room_with_client_idmn_sent_after_restart_and_participant_added,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_ONE_TAG(
+        "Secure group chat with client IMDN sent after restart and participant added and core stopped before sending "
+        "IMDN",
+        LinphoneTest::secure_group_chat_room_with_client_idmn_sent_after_restart_and_participant_added_and_core_stopped,
+        "LeaksMemory"), /* because of network up and down */
+    TEST_NO_TAG("Group chat Lime Server chat room clear message",
+                LinphoneTest::group_chat_room_lime_server_clear_message)};
+
+static test_t local_conference_ephemeral_chat_tests[] = {
+    TEST_NO_TAG("Unencrypted group chat server chat room with admin managed ephemeral messages",
+                LinphoneTest::group_chat_room_server_admin_managed_messages_unencrypted),
+    TEST_ONE_TAG("Group chat Server chat room with admin managed ephemeral messages disabled after creation",
+                 LinphoneTest::group_chat_room_server_admin_managed_messages_ephemeral_disabled_after_creation,
+                 "LeaksMemory"), /* because of coreMgr restart*/
+    TEST_ONE_TAG("Group chat Server chat room with admin managed ephemeral messages enabled after creation",
+                 LinphoneTest::group_chat_room_server_admin_managed_messages_ephemeral_enabled_after_creation,
+                 "LeaksMemory"), /* because of coreMgr restart*/
+    TEST_ONE_TAG("Group chat Server chat room with admin managed ephemeral messages with lifetime update",
+                 LinphoneTest::group_chat_room_server_admin_managed_messages_ephemeral_lifetime_update,
+                 "LeaksMemory"), /* because of coreMgr restart*/
+    TEST_NO_TAG(
+        "Group chat Server chat room with admin managed ephemeral messages with lifetime toggle",
+        LinphoneTest::group_chat_room_server_admin_managed_messages_ephemeral_lifetime_toggle_using_different_methods),
+    TEST_NO_TAG("Group chat Server chat room with ephemeral message mode changed",
+                LinphoneTest::group_chat_room_server_ephemeral_mode_changed)};
+
+static test_t local_conference_secure_chat_tests[] = {
+    TEST_ONE_TAG("Secure Group chat with client restart",
+                 LinphoneTest::secure_group_chat_room_with_client_restart,
+                 "LeaksMemory"), /* beacause of coreMgr restart*/
+    TEST_ONE_TAG("Secure group chat with INVITE session error",
+                 LinphoneTest::secure_group_chat_room_with_invite_error,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_ONE_TAG("Secure group chat with SUBSCRIBE session error",
+                 LinphoneTest::secure_group_chat_room_with_subscribe_error,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_ONE_TAG("Secure group chat with chat room deleted before server restart",
+                 LinphoneTest::secure_group_chat_room_with_chat_room_deleted_before_server_restart,
+                 "LeaksMemory"), /* because of network up and down */
+    TEST_NO_TAG("Group chat Lime Server chat room encrypted message",
+                LinphoneTest::group_chat_room_lime_server_encrypted_message)};
+
+static test_t local_conference_scheduled_conference_basic_tests[] = {
+
+    TEST_NO_TAG("Call to inexisting conference address", LinphoneTest::call_to_inexisting_conference_address),
+    TEST_NO_TAG("Create simple conference", LinphoneTest::create_simple_conference),
+    TEST_NO_TAG("Create conference with uninvited participant",
+                LinphoneTest::create_conference_with_uninvited_participant),
+    TEST_NO_TAG("Create simple conference with server restart",
+                LinphoneTest::create_simple_conference_with_server_restart),
+    TEST_NO_TAG("Create simple conference with client restart",
+                LinphoneTest::create_simple_conference_with_client_restart),
+    TEST_NO_TAG("Create simple conference with audio only participant",
+                LinphoneTest::create_simple_conference_with_audio_only_participant),
+    TEST_NO_TAG("Create conference with late participant addition",
+                LinphoneTest::create_conference_with_late_participant_addition),
+    TEST_NO_TAG("Organizer schedules 2 conferences", LinphoneTest::organizer_schedule_two_conferences),
+    TEST_NO_TAG("Create conference starting immediately", LinphoneTest::create_conference_starting_immediately),
+    TEST_NO_TAG("Create conference starting in the past", LinphoneTest::create_conference_starting_in_the_past),
+    TEST_NO_TAG("Create conference with participant codec mismatch",
+                LinphoneTest::create_conference_with_participant_codec_mismatch),
+    TEST_NO_TAG("Create conference with organizer codec mismatch",
+                LinphoneTest::create_conference_with_organizer_codec_mismatch)};
+
+static test_t local_conference_scheduled_conference_advanced_tests[] = {
+    TEST_NO_TAG("Create simple SRTP conference", LinphoneTest::create_simple_srtp_conference),
+    TEST_NO_TAG("Create simple ZRTP conference", LinphoneTest::create_simple_zrtp_conference),
+    TEST_NO_TAG("Create simple DTLS conference", LinphoneTest::create_simple_dtls_conference),
+    TEST_NO_TAG("Create conference with server restart (participant first)",
+                LinphoneTest::create_conference_with_server_restart_participant_first),
+    TEST_NO_TAG("Create conference with server restart (organizer first)",
+                LinphoneTest::create_conference_with_server_restart_organizer_first),
+    TEST_NO_TAG("Create simple conference with update deferred",
+                LinphoneTest::create_simple_conference_with_update_deferred),
+    TEST_NO_TAG("Create conference with uninvited participant not allowed",
+                LinphoneTest::create_conference_with_uninvited_participant_not_allowed),
+    TEST_NO_TAG("Create conference with late participant addition declined",
+                LinphoneTest::create_conference_with_late_participant_addition_declined),
+#if 0
+	TEST_NO_TAG("Conference with participants added after conference end", LinphoneTest::conference_with_participants_added_after_end),
+	TEST_NO_TAG("Conference with participants added before conference start", LinphoneTest::conference_with_participants_added_before_start),
+#endif
+    TEST_NO_TAG("Create conference with audio only and uninvited participant",
+                LinphoneTest::create_conference_with_audio_only_and_uninvited_participant),
+    TEST_NO_TAG("Create simple conference with audio only participant enabling video",
+                LinphoneTest::create_simple_conference_with_audio_only_participant_enabling_video),
+    TEST_NO_TAG("Create one participant conference toggles video in grid layout",
+                LinphoneTest::one_participant_conference_toggles_video_grid),
+    TEST_NO_TAG("Create one participant conference toggles video in active speaker layout",
+                LinphoneTest::one_participant_conference_toggles_video_active_speaker),
+    TEST_NO_TAG("2 overlapping conferences from different organizers",
+                LinphoneTest::two_overlapping_scheduled_conferences_from_different_organizers),
+    TEST_NO_TAG("Create scheduled conference with active call",
+                LinphoneTest::create_scheduled_conference_with_active_call),
+    TEST_NO_TAG("Change active speaker", LinphoneTest::change_active_speaker)};
+
+static test_t local_conference_conference_edition_tests[] = {
+    TEST_NO_TAG("Organizer edits simple conference", LinphoneTest::organizer_edits_simple_conference),
+    TEST_NO_TAG("Organizer edits simple conference using different account",
+                LinphoneTest::organizer_edits_simple_conference_using_different_account),
+    TEST_NO_TAG("Organizer edits simple conference while it is active",
+                LinphoneTest::organizer_edits_simple_conference_while_active),
+    TEST_NO_TAG("Organizer edits simple conference with server restart",
+                LinphoneTest::organizer_edits_simple_conference_with_server_restart),
+    TEST_NO_TAG("Participant edits simple conference", LinphoneTest::participant_edits_simple_conference),
+    TEST_NO_TAG("Participant edits simple conference using different account",
+                LinphoneTest::participant_edits_simple_conference_using_different_account),
+    TEST_NO_TAG("Conference cancelled through edit", LinphoneTest::conference_cancelled_through_edit),
+    TEST_NO_TAG("Conference edition with simultanoues participant added removed",
+                LinphoneTest::conference_edition_with_simultaneous_participant_add_remove),
+    TEST_NO_TAG("Conference edition with participant role changed",
+                LinphoneTest::conference_edition_with_participant_role_changed),
+    TEST_NO_TAG("Conference edition with organizer codec mismatch",
+                LinphoneTest::conference_edition_with_organizer_codec_mismatch),
+    TEST_NO_TAG("Create conference with server restart (conference cancelled)",
+                LinphoneTest::create_conference_with_server_restart_conference_cancelled)};
+
+static test_t local_conference_scheduled_ice_conference_tests[] = {
+    TEST_NO_TAG("Create simple ICE conference", LinphoneTest::create_simple_ice_conference),
+    TEST_NO_TAG("Create simple STUN+ICE conference", LinphoneTest::create_simple_stun_ice_conference),
+    TEST_NO_TAG("Create simple ICE SRTP conference", LinphoneTest::create_simple_ice_srtp_conference),
+    TEST_NO_TAG("Create simple ICE DTLS conference", LinphoneTest::create_simple_ice_dtls_conference),
+    TEST_NO_TAG("Create simple STUN+ICE SRTP conference", LinphoneTest::create_simple_stun_ice_srtp_conference),
+    TEST_NO_TAG("Create simple ICE conference with audio only participant",
+                LinphoneTest::create_simple_ice_conference_with_audio_only_participant),
+    TEST_NO_TAG("Create simple STUN+ICE conference with audio only participant",
+                LinphoneTest::create_simple_stun_ice_conference_with_audio_only_participant),
+    TEST_NO_TAG("Create simple STUN+ICE SRTP conference with audio only participant",
+                LinphoneTest::create_simple_stun_ice_srtp_conference_with_audio_only_participant),
+    TEST_ONE_TAG("Abort call to ICE conference",
+                 LinphoneTest::abort_call_to_ice_conference,
+                 "LeaksMemory") /* because of aborted calls*/
+};
+
+static test_t local_conference_inpromptu_conference_tests[] = {
+    TEST_NO_TAG("Create simple dial out conference", LinphoneTest::create_simple_conference_dial_out),
+    TEST_NO_TAG("Create simple dial out conference and ICS sent",
+                LinphoneTest::create_simple_conference_dial_out_and_ics),
+    TEST_NO_TAG("Create simple dial out conference with late participant addition",
+                LinphoneTest::create_simple_conference_dial_out_with_late_participant_addition),
+    TEST_NO_TAG("Create simple dial out conference with many late participant additions",
+                LinphoneTest::create_simple_conference_dial_out_with_many_late_participant_additions),
+    TEST_NO_TAG("Create simple conference by merging calls", LinphoneTest::create_simple_conference_merging_calls),
+    TEST_ONE_TAG("Create simple conference by merging calls with video toggling",
+                 LinphoneTest::create_simple_conference_merging_calls_with_video_toggling,
+                 "LeaksMemory"), /* because of aborted calls*/
+    TEST_ONE_TAG("Create simple ICE conference by merging calls",
+                 LinphoneTest::create_simple_ice_conference_merging_calls,
+                 "LeaksMemory"), /* because of aborted calls*/
+    TEST_NO_TAG("Create dial out conference with active call",
+                LinphoneTest::create_dial_out_conference_with_active_call),
+    TEST_NO_TAG("Organizer creates 2 dialout conferences", LinphoneTest::organizer_creates_two_dialout_conferences),
+    TEST_NO_TAG("2 overlapping dialout conferences from different organizers",
+                LinphoneTest::two_overlapping_dialout_conferences_from_different_organizers)};
+
+static test_t local_conference_inpromptu_mismatch_conference_tests[] = {
+    TEST_NO_TAG("Create simple dial out conference with calls declined",
+                LinphoneTest::create_simple_conference_dial_out_with_calls_declined),
+    TEST_NO_TAG("Create simple dial out conference with some calls declined",
+                LinphoneTest::create_simple_conference_dial_out_with_some_calls_declined),
+    TEST_NO_TAG("Create simple dial out conference with some calls busy",
+                LinphoneTest::create_simple_conference_dial_out_with_some_calls_busy),
+    TEST_NO_TAG("Create simple dial out conference with participant codec mismatch",
+                LinphoneTest::create_simple_conference_dial_out_participant_codec_mismatch),
+    TEST_NO_TAG("Create simple dial out conference with organizer codec mismatch",
+                LinphoneTest::create_simple_conference_dial_out_organizer_codec_mismatch),
+    TEST_NO_TAG("Create simple dial out conference with video not initiated",
+                LinphoneTest::create_simple_conference_dial_out_with_video_not_initiated),
+    TEST_NO_TAG("Create simple dial out conference with video not accepted",
+                LinphoneTest::create_simple_conference_dial_out_with_video_not_accepted),
+    TEST_NO_TAG("Simple dial out conference with no payloads",
+                LinphoneTest::simple_dial_out_conference_with_no_payloads)};
+
+test_suite_t local_conference_test_suite_chat = {"Local conference tester (Chat)",
+                                                 NULL,
+                                                 NULL,
+                                                 liblinphone_tester_before_each,
+                                                 liblinphone_tester_after_each,
+                                                 sizeof(local_conference_chat_tests) /
+                                                     sizeof(local_conference_chat_tests[0]),
+                                                 local_conference_chat_tests};
+
+test_suite_t local_conference_test_suite_chat_error = {"Local conference tester (Chat error)",
+                                                       NULL,
+                                                       NULL,
+                                                       liblinphone_tester_before_each,
+                                                       liblinphone_tester_after_each,
+                                                       sizeof(local_conference_chat_error_tests) /
+                                                           sizeof(local_conference_chat_error_tests[0]),
+                                                       local_conference_chat_error_tests};
+
+test_suite_t local_conference_test_suite_chat_imdn = {"Local conference tester (Chat IMDN)",
+                                                      NULL,
+                                                      NULL,
+                                                      liblinphone_tester_before_each,
+                                                      liblinphone_tester_after_each,
+                                                      sizeof(local_conference_chat_imdn_tests) /
+                                                          sizeof(local_conference_chat_imdn_tests[0]),
+                                                      local_conference_chat_imdn_tests};
+
+test_suite_t local_conference_test_suite_ephemeral_chat = {"Local conference tester (Ephemeral Chat)",
+                                                           NULL,
+                                                           NULL,
+                                                           liblinphone_tester_before_each,
+                                                           liblinphone_tester_after_each,
+                                                           sizeof(local_conference_ephemeral_chat_tests) /
+                                                               sizeof(local_conference_ephemeral_chat_tests[0]),
+                                                           local_conference_ephemeral_chat_tests};
+
+test_suite_t local_conference_test_suite_secure_chat = {"Local conference tester (Secure Chat)",
+                                                        NULL,
+                                                        NULL,
+                                                        liblinphone_tester_before_each,
+                                                        liblinphone_tester_after_each,
+                                                        sizeof(local_conference_secure_chat_tests) /
+                                                            sizeof(local_conference_secure_chat_tests[0]),
+                                                        local_conference_secure_chat_tests};
+
+test_suite_t local_conference_test_suite_conference_edition = {"Local conference tester (Conference edition)",
+                                                               NULL,
+                                                               NULL,
+                                                               liblinphone_tester_before_each,
+                                                               liblinphone_tester_after_each,
+                                                               sizeof(local_conference_conference_edition_tests) /
+                                                                   sizeof(local_conference_conference_edition_tests[0]),
+                                                               local_conference_conference_edition_tests};
+
+test_suite_t local_conference_test_suite_scheduled_conference_basic = {
+    "Local conference tester (Scheduled Conference Basic)",
+    NULL,
+    NULL,
+    liblinphone_tester_before_each,
+    liblinphone_tester_after_each,
+    sizeof(local_conference_scheduled_conference_basic_tests) /
+        sizeof(local_conference_scheduled_conference_basic_tests[0]),
+    local_conference_scheduled_conference_basic_tests};
+
+test_suite_t local_conference_test_suite_scheduled_conference_advanced = {
+    "Local conference tester (Scheduled Conference Advanced)",
+    NULL,
+    NULL,
+    liblinphone_tester_before_each,
+    liblinphone_tester_after_each,
+    sizeof(local_conference_scheduled_conference_advanced_tests) /
+        sizeof(local_conference_scheduled_conference_advanced_tests[0]),
+    local_conference_scheduled_conference_advanced_tests};
+
+test_suite_t local_conference_test_suite_scheduled_ice_conference = {
+    "Local conference tester (Scheduled ICE Conference)",
+    NULL,
+    NULL,
+    liblinphone_tester_before_each,
+    liblinphone_tester_after_each,
+    sizeof(local_conference_scheduled_ice_conference_tests) /
+        sizeof(local_conference_scheduled_ice_conference_tests[0]),
+    local_conference_scheduled_ice_conference_tests};
+
+test_suite_t local_conference_test_suite_inpromptu_conference = {
+    "Local conference tester (Inpromptu Conference)",
+    NULL,
+    NULL,
+    liblinphone_tester_before_each,
+    liblinphone_tester_after_each,
+    sizeof(local_conference_inpromptu_conference_tests) / sizeof(local_conference_inpromptu_conference_tests[0]),
+    local_conference_inpromptu_conference_tests};
+
+test_suite_t local_conference_test_suite_inpromptu_mismatch_conference = {
+    "Local conference tester (Inpromptu Conference with mismatch)",
+    NULL,
+    NULL,
+    liblinphone_tester_before_each,
+    liblinphone_tester_after_each,
+    sizeof(local_conference_inpromptu_mismatch_conference_tests) /
+        sizeof(local_conference_inpromptu_mismatch_conference_tests[0]),
+    local_conference_inpromptu_mismatch_conference_tests};
+
+#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
+#pragma GCC diagnostic pop
+#endif
diff --git a/tester/local_conference_tester_functions.cpp b/tester/local_conference_tester_functions.cpp
index 25cfe44cff..1148da05d0 100644
--- a/tester/local_conference_tester_functions.cpp
+++ b/tester/local_conference_tester_functions.cpp
@@ -23,9 +23,6 @@
 #include "conference/participant.h"
 #include "shared_tester_functions.h"
 
-#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
-#pragma GCC diagnostic push
-#endif
 #ifdef _MSC_VER
 #pragma warning(disable : 4996)
 #endif
@@ -1592,9 +1589,8 @@ void check_conference_info(LinphoneCoreManager *mgr,
 		BC_ASSERT_TRUE(linphone_address_weak_equal(organizer->identity, linphone_conference_info_get_organizer(info)));
 		BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
 
-		bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+		const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
 		BC_ASSERT_EQUAL(bctbx_list_size(info_participants), no_members, size_t, "%zu");
-		bctbx_list_free(info_participants);
 		BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(info), (int)security_level, int, "%0d");
 
 		if (start_time > 0) {
@@ -1638,20 +1634,21 @@ static bool have_common_audio_payload(LinphoneCoreManager *mgr1, LinphoneCoreMan
 	return found;
 }
 
-LinphoneAddress *create_conference_on_server(Focus &focus,
-                                             ClientConference &organizer,
-                                             std::list<LinphoneCoreManager *> requested_participants,
-                                             time_t start_time,
-                                             time_t end_time,
-                                             const char *subject,
-                                             const char *description,
-                                             bool_t send_ics,
-                                             LinphoneConferenceSecurityLevel security_level) {
+LinphoneAddress *
+create_conference_on_server(Focus &focus,
+                            ClientConference &organizer,
+                            std::map<LinphoneCoreManager *, LinphoneParticipantRole> requested_participants,
+                            time_t start_time,
+                            time_t end_time,
+                            const char *subject,
+                            const char *description,
+                            bool_t send_ics,
+                            LinphoneConferenceSecurityLevel security_level) {
 	bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 	coresList = bctbx_list_append(coresList, organizer.getLc());
 	std::vector<stats> participant_stats;
 	std::map<LinphoneCoreManager *, LinphoneCall *> previous_calls;
-	bctbx_list_t *participant_addresses = NULL;
+	bctbx_list_t *participant_infos = NULL;
 	std::list<LinphoneCoreManager *> participants;
 	const LinphoneConferenceInfo *updated_conf_info = NULL;
 	bool focus_organizer_common_payload = have_common_audio_payload(organizer.getCMgr(), focus.getCMgr());
@@ -1662,14 +1659,16 @@ LinphoneAddress *create_conference_on_server(Focus &focus,
 	size_t participant_expected_participant_number = 0;
 	char *uid = NULL;
 	LinphoneConferenceInfo *info = NULL;
-	for (auto &p : requested_participants) {
-		participant_addresses = bctbx_list_append(participant_addresses, p->identity);
-		if (p == organizer.getCMgr()) {
+	for (const auto &[mgr, role] : requested_participants) {
+		LinphoneParticipantInfo *participant_info = linphone_participant_info_new(mgr->identity);
+		linphone_participant_info_set_role(participant_info, role);
+		participant_infos = bctbx_list_append(participant_infos, participant_info);
+		if (mgr == organizer.getCMgr()) {
 			found_me = true;
 		} else {
-			coresList = bctbx_list_append(coresList, p->lc);
-			participant_stats.push_back(p->stat);
-			participants.push_back(p);
+			coresList = bctbx_list_append(coresList, mgr->lc);
+			participant_stats.push_back(mgr->stat);
+			participants.push_back(mgr);
 		}
 	}
 
@@ -1696,7 +1695,7 @@ LinphoneAddress *create_conference_on_server(Focus &focus,
 	                                               linphone_account_get_params(default_account)))
 	                                         : linphone_address_new(linphone_core_get_identity(organizer.getLc()));
 	linphone_conference_info_set_organizer(conf_info, organizer_address);
-	linphone_conference_info_set_participants(conf_info, participant_addresses);
+	linphone_conference_info_set_participants_2(conf_info, participant_infos);
 	if ((end_time >= 0) && (start_time >= 0) && (end_time > start_time)) {
 		linphone_conference_info_set_duration(
 		    conf_info, (int)((end_time - start_time) / 60)); // duration is expected to be set in minutes
@@ -1882,17 +1881,15 @@ LinphoneAddress *create_conference_on_server(Focus &focus,
 							    linphone_conference_info_get_uri(conf_info_in_db),
 							    linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-							bctbx_list_t *ics_participants =
+							const bctbx_list_t *ics_participants =
 							    linphone_conference_info_get_participants(conf_info_from_original_content);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participant_expected_participant_number,
 							                size_t, "%zu");
-							bctbx_list_free(ics_participants);
 
-							bctbx_list_t *ics_participants_db =
+							const bctbx_list_t *ics_participants_db =
 							    linphone_conference_info_get_participants(conf_info_in_db);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants_db),
 							                participant_expected_participant_number, size_t, "%zu");
-							bctbx_list_free(ics_participants_db);
 
 							if (start_time > 0) {
 								BC_ASSERT_EQUAL(
@@ -1963,7 +1960,7 @@ LinphoneAddress *create_conference_on_server(Focus &focus,
 					if (!BC_ASSERT_PTR_NOT_NULL(conf_info_in_db)) {
 						goto end;
 					}
-					// Encryption is None because we haven't received yet the NOTIFY full stae with this information
+					// Encryption is None because we haven't received yet the NOTIFY full state with this information
 					check_conference_info(mgr, conference_address, organizer.getCMgr(),
 					                      participant_expected_participant_number, start_time,
 					                      ((start_time > 0) && (end_time > 0)) ? (int)(end_time - start_time) / 60 : 0,
@@ -2015,7 +2012,7 @@ end:
 	if (organizer_address) linphone_address_unref(organizer_address);
 	linphone_conference_scheduler_unref(conference_scheduler);
 	bctbx_list_free(coresList);
-	bctbx_list_free(participant_addresses);
+	bctbx_list_free_with_data(participant_infos, (bctbx_list_free_func)linphone_participant_info_unref);
 
 	return conference_address;
 }
@@ -2064,24 +2061,44 @@ size_t compute_no_video_streams(bool_t enable_video, LinphoneCall *call, Linphon
 	return nb_video_streams;
 }
 
-size_t compute_no_audio_streams(LinphoneConference *conference) {
+size_t compute_no_audio_streams(LinphoneCall *call, LinphoneConference *conference) {
 	size_t nb_audio_streams = 0;
 	const LinphoneConferenceParams *conference_params = linphone_conference_get_current_params(conference);
 	if (linphone_conference_params_get_security_level(conference_params) == LinphoneConferenceSecurityLevelEndToEnd) {
-		bctbx_list_t *devices = linphone_conference_get_participant_device_list(conference);
-		nb_audio_streams = bctbx_list_size(devices);
-		bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+		const LinphoneAddress *remote_address = linphone_call_get_remote_address(call);
+		bctbx_list_t *participants = linphone_conference_get_participant_list(conference);
+		for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+			LinphoneParticipant *participant = (LinphoneParticipant *)bctbx_list_get_data(itp);
+			LinphoneParticipantRole role = linphone_participant_get_role(participant);
+			if (role == LinphoneParticipantRoleSpeaker) {
+				bctbx_list_t *devices = linphone_participant_get_devices(participant);
+				for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
+					LinphoneParticipantDevice *device = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+					if (linphone_participant_device_get_stream_availability(device, LinphoneStreamTypeAudio)) {
+						nb_audio_streams++;
+					}
+				}
+				bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
+			} else if (linphone_address_weak_equal(linphone_participant_get_address(participant), remote_address)) {
+				// Add an audio stream anyway if the participant holding the call is a listener
+				nb_audio_streams++;
+			}
+		}
+		bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+		if (!linphone_core_conference_server_enabled(linphone_conference_get_core(conference))) {
+			// Add own audio stream if the core holding the conference is not a server
+			nb_audio_streams++;
+		}
 	} else {
 		nb_audio_streams = 1;
 	}
-
 	return nb_audio_streams;
 }
 
 void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs,
                                  std::list<LinphoneCoreManager *> conferenceMgrs,
                                  LinphoneCoreManager *focus,
-                                 std::list<LinphoneCoreManager *> members,
+                                 std::map<LinphoneCoreManager *, LinphoneParticipantRole> members,
                                  const LinphoneAddress *confAddr,
                                  bool_t enable_video) {
 	for (auto mgr : conferenceMgrs) {
@@ -2092,14 +2109,17 @@ void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<Co
 			std::list<LinphoneCall *> calls;
 
 			bool video_check = false;
+			bool participant_check = false;
 			bool device_present = false;
 			bool call_ok = true;
+			bool audio_direction_ok = true;
 
 			if (mgr == focus) {
-				for (auto m : members) {
-					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(m->lc, confAddr);
+				for (const auto &m : members) {
+					LinphoneCoreManager *mMgr = m.first;
+					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mMgr->lc, confAddr);
 					call_ok &= (pcall != nullptr);
-					LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, m->identity);
+					LinphoneCall *call = linphone_core_get_call_by_remote_address2(mgr->lc, mMgr->identity);
 					call_ok &= (call != nullptr);
 					if (call) {
 						calls.push_back(call);
@@ -2120,7 +2140,7 @@ void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<Co
 			LinphoneConference *conference = linphone_core_search_conference_2(mgr->lc, confAddr);
 			for (auto call : calls) {
 				if (call) {
-					size_t nb_audio_streams = compute_no_audio_streams(conference);
+					size_t nb_audio_streams = compute_no_audio_streams(call, conference);
 					size_t nb_video_streams = compute_no_video_streams(enable_video, call, conference);
 					const SalMediaDescription *call_result_desc = _linphone_call_get_result_desc(call);
 					call_ok &= ((call_result_desc->nbActiveStreamsOfType(SalAudio) == nb_audio_streams) &&
@@ -2133,24 +2153,56 @@ void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<Co
 			if (conference) {
 				bctbx_list_t *devices = linphone_conference_get_participant_device_list(conference);
 				video_check = (bctbx_list_size(devices) > 0);
+				participant_check = (bctbx_list_size(devices) > 0);
 				device_present = (bctbx_list_size(devices) > 0);
 				LinphoneCall *call = NULL;
 				for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
 					LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
 					bool_t found = FALSE;
-					for (const auto &p : members) {
-						found |= linphone_address_weak_equal(p->identity, linphone_participant_device_get_address(d));
+					const LinphoneAddress *device_address = linphone_participant_device_get_address(d);
+					for (const auto &m : members) {
+						LinphoneCoreManager *mMgr = m.first;
+						found |= linphone_address_weak_equal(mMgr->identity, device_address);
 					}
 					if (mgr == focus) {
-						const LinphoneAddress *address = linphone_participant_device_get_address(d);
-						call = linphone_core_get_call_by_remote_address2(mgr->lc, address);
+						call = linphone_core_get_call_by_remote_address2(mgr->lc, device_address);
 					} else {
 						if (calls.front()) {
 							call = calls.front();
 						}
 					}
+					bool_t is_me = linphone_conference_is_me(conference, device_address);
+					LinphoneParticipant *p = is_me ? linphone_conference_get_me(conference)
+					                               : linphone_conference_find_participant(conference, device_address);
+					participant_check &= (p != nullptr);
+					LinphoneMediaDirection expected_audio_direction = LinphoneMediaDirectionInactive;
+					if (p) {
+						LinphoneParticipantRole role = linphone_participant_get_role(p);
+						expected_audio_direction =
+						    ((role == LinphoneParticipantRoleSpeaker) ? LinphoneMediaDirectionSendRecv
+						                                              : LinphoneMediaDirectionRecvOnly);
+						LinphoneMediaDirection audio_dir =
+						    linphone_participant_device_get_stream_capability(d, LinphoneStreamTypeAudio);
+						audio_direction_ok &= (audio_dir == expected_audio_direction);
+					} else {
+						audio_direction_ok = false;
+					}
 
+					LinphoneParticipantDeviceState expected_state = LinphoneParticipantDeviceStateJoining;
+					if (found) {
+						expected_state = LinphoneParticipantDeviceStatePresent;
+					} else {
+						expected_state = LinphoneParticipantDeviceStateLeft;
+					}
+					device_present &= (linphone_participant_device_get_state(d) == expected_state);
 					if (call) {
+						if (is_me) {
+							const LinphoneCallParams *call_current_params = linphone_call_get_current_params(call);
+							LinphoneMediaDirection call_audio_direction =
+							    linphone_call_params_get_audio_direction(call_current_params);
+							audio_direction_ok &= (call_audio_direction == expected_audio_direction);
+						}
+
 						const LinphoneCallParams *call_params = linphone_call_get_params(call);
 						bool_t call_video_enabled = linphone_call_params_video_enabled(call_params);
 						if (enable_video && ((mgr == focus) || call_video_enabled)) {
@@ -2165,20 +2217,23 @@ void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<Co
 							video_check &=
 							    !linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo);
 						}
-						LinphoneParticipantDeviceState expected_state = LinphoneParticipantDeviceStateJoining;
-						if (found) {
-							expected_state = LinphoneParticipantDeviceStatePresent;
-						} else {
-							expected_state = LinphoneParticipantDeviceStateLeft;
-						}
-						device_present &= (linphone_participant_device_get_state(d) == expected_state);
 					}
 				}
 				if (devices) {
 					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
 				}
+
+				for (const auto &[mMgr, role] : members) {
+					LinphoneParticipant *p = linphone_conference_is_me(conference, mMgr->identity)
+					                             ? linphone_conference_get_me(conference)
+					                             : linphone_conference_find_participant(conference, mMgr->identity);
+					participant_check &= (p != nullptr);
+					if (p) {
+						participant_check &= (linphone_participant_get_role(p) == role);
+					}
+				}
 			}
-			return video_check && device_present && call_ok;
+			return audio_direction_ok && video_check && device_present && call_ok && participant_check;
 		}));
 	}
 }
@@ -2565,7 +2620,14 @@ void create_conference_base(time_t start_time,
 		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
 		const char *description = "Paris Baker";
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleListener;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 		char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
@@ -2682,8 +2744,23 @@ void create_conference_base(time_t start_time,
 		                             focus_stat.number_of_participant_devices_joined + 3,
 		                             liblinphone_tester_sip_timeout));
 
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : members) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
+
 		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
-		                            members, confAddr, enable_video);
+		                            memberList, confAddr, enable_video);
 
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 		BC_ASSERT_PTR_NOT_NULL(fconference);
@@ -2811,9 +2888,8 @@ void create_conference_base(time_t start_time,
 					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 					BC_ASSERT_PTR_NOT_NULL(pcall);
 					if (pcall) {
-						no_streams_audio = static_cast<int>(compute_no_audio_streams(pconference));
-						no_active_streams_video =
-						    static_cast<int>(compute_no_video_streams(enabled, pcall, pconference));
+						no_streams_audio = compute_no_audio_streams(pcall, pconference);
+						no_active_streams_video = compute_no_video_streams(enabled, pcall, pconference);
 						video_negotiated = enabled && (no_active_streams_video > 0);
 						if (!enable_ice) {
 							_linphone_call_check_max_nb_streams(pcall, no_streams_audio, no_streams_video,
@@ -3076,9 +3152,8 @@ void create_conference_base(time_t start_time,
 						LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 						BC_ASSERT_PTR_NOT_NULL(pcall);
 						if (pcall) {
-							no_streams_audio = static_cast<int>(compute_no_audio_streams(pconference));
-							no_active_streams_video =
-							    static_cast<int>(compute_no_video_streams(enabled, pcall, pconference));
+							no_streams_audio = compute_no_audio_streams(pcall, pconference);
+							no_active_streams_video = compute_no_video_streams(enabled, pcall, pconference);
 							_linphone_call_check_max_nb_streams(pcall, no_streams_audio, no_streams_video,
 							                                    no_streams_text);
 							_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
@@ -3707,8 +3782,25 @@ void create_conference_base(time_t start_time,
 					                             liblinphone_tester_sip_timeout));
 				}
 
+				std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+				for (const auto &member : members) {
+					try {
+						const auto &participantInfo = participantList.at(member);
+						memberList.insert(std::make_pair(member, participantInfo));
+					} catch (std::out_of_range &) {
+						if (member == marie.getCMgr()) {
+							memberList.insert(std::make_pair(member, LinphoneParticipantRoleSpeaker));
+						} else if (member == michelle.getCMgr()) {
+							memberList.insert(std::make_pair(member, LinphoneParticipantRoleListener));
+						} else {
+							ms_fatal("Unable to find active participant %s in the participant list",
+							         linphone_core_get_identity(member->lc));
+						}
+					}
+				}
 				wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs,
-				                            focus.getCMgr(), members, confAddr, enable_video);
+				                            focus.getCMgr(), memberList, confAddr, enable_video);
+
 			} else if (participant_list_type == LinphoneConferenceParticipantListTypeClosed) {
 				extra_participants = 0;
 
@@ -3776,25 +3868,23 @@ void create_conference_base(time_t start_time,
 						no_participants = no_local_participants + extra_participants;
 						BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
 					} else {
-						// Substracting one because we conference server is not in the conference
+						// Substracting one because we conference server is not in the
+						// conference
 						no_participants = (no_local_participants - 1) + extra_participants;
 						BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
 
 						LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 						BC_ASSERT_PTR_NOT_NULL(pcall);
 
-						size_t no_streams_audio =
-						    (security_level == LinphoneConferenceSecurityLevelEndToEnd)
-						        ? ((participant_list_type == LinphoneConferenceParticipantListTypeOpen) ? 4 : 3)
-						        : 1;
+						size_t no_streams_audio = 0;
 						size_t no_streams_video = 0;
 						size_t no_active_streams_video = 0;
 						size_t no_streams_text = 0;
 						if (pcall) {
 							const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
 							const bool_t enabled = linphone_call_params_video_enabled(call_cparams);
-							no_active_streams_video =
-							    static_cast<int>(compute_no_video_streams(enabled, pcall, pconference));
+							no_streams_audio = compute_no_audio_streams(pcall, pconference);
+							no_active_streams_video = compute_no_video_streams(enabled, pcall, pconference);
 							no_streams_video = ((security_level == LinphoneConferenceSecurityLevelEndToEnd) &&
 							                    (layout == LinphoneConferenceLayoutActiveSpeaker))
 							                       ? 6
@@ -4124,24 +4214,24 @@ void create_conference_base(time_t start_time,
 							LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 							BC_ASSERT_PTR_NOT_NULL(pcall);
 
-							size_t no_streams_audio =
-							    (security_level == LinphoneConferenceSecurityLevelEndToEnd)
-							        ? ((participant_list_type == LinphoneConferenceParticipantListTypeOpen) ? 4 : 3)
-							        : 1;
+							size_t no_streams_audio = 0;
+							size_t no_max_streams_audio = 0;
 							size_t no_streams_video = 0;
 							size_t no_active_streams_video = 0;
 							size_t no_streams_text = 0;
 							if (pcall) {
 								const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
 								const bool_t enabled = linphone_call_params_video_enabled(call_cparams);
-								no_active_streams_video =
-								    static_cast<int>(compute_no_video_streams(enabled, pcall, pconference));
+								no_streams_audio = compute_no_audio_streams(pcall, pconference);
+								no_active_streams_video = compute_no_video_streams(enabled, pcall, pconference);
 								no_streams_video = ((security_level == LinphoneConferenceSecurityLevelEndToEnd) &&
 								                    (layout == LinphoneConferenceLayoutActiveSpeaker))
 								                       ? 6
 								                       : 4;
+								no_max_streams_audio =
+								    (security_level == LinphoneConferenceSecurityLevelEndToEnd) ? 3 : 1;
 
-								_linphone_call_check_max_nb_streams(pcall, no_streams_audio, no_streams_video,
+								_linphone_call_check_max_nb_streams(pcall, no_max_streams_audio, no_streams_video,
 								                                    no_streams_text);
 								_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
 								                                       no_streams_text);
@@ -4151,13 +4241,14 @@ void create_conference_base(time_t start_time,
 							    linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
 							BC_ASSERT_PTR_NOT_NULL(fcall);
 							if (fcall) {
-								_linphone_call_check_max_nb_streams(fcall, no_streams_audio, no_streams_video,
+								_linphone_call_check_max_nb_streams(fcall, no_max_streams_audio, no_streams_video,
 								                                    no_streams_text);
 								_linphone_call_check_nb_active_streams(fcall, no_streams_audio, no_active_streams_video,
 								                                       no_streams_text);
 							}
 
-							// Substracting one because we conference server is not in the conference
+							// Substracting one because we conference server is not in the
+							// conference
 							no_participants = (no_local_participants - 1) + extra_participants;
 							BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
 						}
@@ -4660,7 +4751,14 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 		const char *initialSubject = "Weekly recap";
 		const char *description = "What happened in the past week";
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -4770,11 +4868,10 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 					BC_ASSERT_TRUE(
 					    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
 
-					bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
+					const bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
 					// Original participants + Marie who joined the conference
 					BC_ASSERT_EQUAL(bctbx_list_size(info_participants), static_cast<int>(members.size()), size_t,
 					                "%zu");
-					bctbx_list_free(info_participants);
 
 					if (start_time > 0) {
 						BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(call_log_info), start_time,
@@ -4835,8 +4932,22 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 		BC_ASSERT_PTR_NOT_NULL(fconference);
 
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : members) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
 		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
-		                            members, confAddr, TRUE);
+		                            memberList, confAddr, TRUE);
 
 		// wait bit more to detect side effect if any
 		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(15), [] {
@@ -5003,6 +5114,7 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 
 			conferenceMgrs.push_back(berthe.getCMgr());
 			members.push_back(berthe.getCMgr());
+			memberList.insert(std::make_pair(berthe.getCMgr(), LinphoneParticipantRoleListener));
 
 			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
 			                             focus_stat.number_of_LinphoneCallStreamsRunning + 2,
@@ -5031,6 +5143,7 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 
 				conferenceMgrs.push_back(michelle.getCMgr());
 				members.push_back(michelle.getCMgr());
+				memberList.insert(std::make_pair(michelle.getCMgr(), LinphoneParticipantRoleListener));
 
 				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
 				                             focus_stat.number_of_LinphoneCallStreamsRunning + 4,
@@ -5159,7 +5272,7 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 		}
 
 		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
-		                            members, confAddr, TRUE);
+		                            memberList, confAddr, TRUE);
 
 		LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
 		BC_ASSERT_PTR_NOT_NULL(pauline_call);
@@ -5383,7 +5496,14 @@ void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) {
 		time_t end_time1 = (start_time1 + 600);
 		const char *subject1 = "Colleagues";
 		const char *description1 = NULL;
-		LinphoneAddress *confAddr1 = create_conference_on_server(focus, marie, participants1, start_time1, end_time1,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList1;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants1) {
+			participantList1.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr1 = create_conference_on_server(focus, marie, participantList1, start_time1, end_time1,
 		                                                         subject1, description1, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr1);
 		char *conference1_address_str = (confAddr1) ? linphone_address_as_string(confAddr1) : ms_strdup("<unknown>");
@@ -5520,35 +5640,41 @@ void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) {
 		time_t end_time2 = (dialout) ? -1 : (start_time2 + 600);
 		const char *subject2 = "All Hands Q3 FY2021 - Attendance Mandatory";
 		const char *description2 = "Financial result - Internal only - Strictly confidential";
-		LinphoneAddress *confAddr2 = NULL;
 		std::list<LinphoneCoreManager *> participants2{pauline.getCMgr()};
 		std::list<LinphoneCoreManager *> mgr_having_two_confs{};
 		std::list<LinphoneCoreManager *> mgr_in_conf2{focus.getCMgr(), michelle.getCMgr()};
+		ClientConference &confCreator2 = (same_organizer) ? marie : michelle;
 		if (same_organizer) {
 			participants2.push_back(michelle.getCMgr());
 			mgr_having_two_confs.push_back(marie.getCMgr());
-			confAddr2 = create_conference_on_server(focus, marie, participants2, start_time2, end_time2, subject2,
-			                                        description2, TRUE, security_level);
-
-			// Chat room creation to send ICS
-			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 3,
-			                             liblinphone_tester_sip_timeout));
-
 		} else {
 			participants2.push_back(marie.getCMgr());
 			if (!dialout) {
 				mgr_having_two_confs.push_back(marie.getCMgr());
 				mgr_in_conf2.push_back(marie.getCMgr());
 			}
-			confAddr2 = create_conference_on_server(focus, michelle, participants2, start_time2, end_time2, subject2,
-			                                        description2, TRUE, security_level);
+		}
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList2;
+		for (auto &p : participants2) {
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+			participantList2.insert(std::make_pair(p, role));
+		}
 
-			// Chat room creation to send ICS
+		LinphoneAddress *confAddr2 =
+		    create_conference_on_server(focus, confCreator2, participantList2, start_time2, end_time2, subject2,
+		                                description2, TRUE, security_level);
+		BC_ASSERT_PTR_NOT_NULL(confAddr2);
+		char *conference2_address_str = (confAddr2) ? linphone_address_as_string(confAddr2) : ms_strdup("<unknown>");
+
+		// Chat room creation to send ICS
+		if (same_organizer) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 3,
+			                             liblinphone_tester_sip_timeout));
+		} else {
 			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateCreated, 2,
 			                             liblinphone_tester_sip_timeout));
 		}
-		BC_ASSERT_PTR_NOT_NULL(confAddr2);
-		char *conference2_address_str = (confAddr2) ? linphone_address_as_string(confAddr2) : ms_strdup("<unknown>");
 
 		if (confAddr2) {
 			if (dialout) {
@@ -6264,7 +6390,14 @@ void create_one_participant_conference_toggle_video_base(LinphoneConferenceLayou
 		const char *description = "- <F2><F3>\n\\çà";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -6932,7 +7065,15 @@ void create_conference_with_active_call_base(bool_t dialout) {
 		time_t start_time = (dialout) ? -1 : (ms_time(NULL) + 10);
 		bool_t send_ics = TRUE;
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, -1,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleListener));
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, -1,
 		                                                        initialSubject, description, send_ics, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -7032,9 +7173,8 @@ void create_conference_with_active_call_base(bool_t dialout) {
 						                                           linphone_conference_info_get_organizer(info)));
 						BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
 
-						bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+						const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
 						BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu");
-						bctbx_list_free(info_participants);
 
 						BC_ASSERT_NOT_EQUAL((long long)linphone_conference_info_get_date_time(info), 0, long long,
 						                    "%lld");
@@ -7101,10 +7241,9 @@ void create_conference_with_active_call_base(bool_t dialout) {
 				                                           linphone_conference_info_get_organizer(info)));
 				BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
 
-				bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+				const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
 				// Original participants + Marie who joined the conference
 				BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu");
-				bctbx_list_free(info_participants);
 
 				BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld");
 				const int duration_m = linphone_conference_info_get_duration(info);
@@ -7134,10 +7273,9 @@ void create_conference_with_active_call_base(bool_t dialout) {
 					BC_ASSERT_TRUE(
 					    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
 
-					bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
+					const bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
 					// Original participants + Marie who joined the conference
 					BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu");
-					bctbx_list_free(info_participants);
 					BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0,
 					                         long long, "%lld");
 					const int duration_m = linphone_conference_info_get_duration(call_log_info);
@@ -7196,7 +7334,7 @@ void create_conference_with_active_call_base(bool_t dialout) {
 		for (auto mgr : conferenceMgrs) {
 			// wait bit more to detect side effect if any
 			CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe})
-			    .waitUntil(chrono::seconds(50), [mgr, &focus, &members, confAddr] {
+			    .waitUntil(chrono::seconds(50), [mgr, &focus, &members, confAddr, &participantList] {
 				    size_t nb_audio_streams = 1;
 				    size_t nb_video_streams = 0;
 				    size_t nb_text_streams = 0;
@@ -7225,29 +7363,49 @@ void create_conference_with_active_call_base(bool_t dialout) {
 				    for (auto call : calls) {
 					    if (call) {
 						    const SalMediaDescription *call_result_desc = _linphone_call_get_result_desc(call);
-						    return (call_result_desc->getNbStreams() ==
-						            nb_audio_streams + nb_video_streams + nb_text_streams) &&
-						           (call_result_desc->nbStreamsOfType(SalAudio) == nb_audio_streams) &&
-						           (call_result_desc->nbStreamsOfType(SalVideo) == nb_video_streams) &&
-						           (call_result_desc->nbStreamsOfType(SalText) == nb_text_streams) &&
-						           (linphone_call_get_state(call) == LinphoneCallStateStreamsRunning);
+						    if (!((call_result_desc->getNbStreams() ==
+						           nb_audio_streams + nb_video_streams + nb_text_streams) &&
+						          (call_result_desc->nbStreamsOfType(SalAudio) == nb_audio_streams) &&
+						          (call_result_desc->nbStreamsOfType(SalVideo) == nb_video_streams) &&
+						          (call_result_desc->nbStreamsOfType(SalText) == nb_text_streams) &&
+						          (linphone_call_get_state(call) == LinphoneCallStateStreamsRunning))) {
+							    return false;
+						    }
 					    }
 				    }
 
+				    bool video_check = true;
 				    LinphoneConference *conference = linphone_core_search_conference_2(mgr->lc, confAddr);
 				    BC_ASSERT_PTR_NOT_NULL(conference);
 				    if (conference) {
 					    bctbx_list_t *devices = linphone_conference_get_participant_device_list(conference);
 					    for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
 						    LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
-						    return !linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo);
+						    video_check &=
+						        !linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo);
 					    }
 
 					    if (devices) {
 						    bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
 					    }
 				    }
-				    return false;
+				    if (!video_check) {
+					    return false;
+				    }
+
+				    bool role_check = true;
+				    for (auto m : participantList) {
+					    LinphoneCoreManager *mMgr = m.first;
+					    LinphoneParticipantRole role = m.second;
+					    LinphoneParticipant *p = linphone_conference_is_me(conference, mMgr->identity)
+					                                 ? linphone_conference_get_me(conference)
+					                                 : linphone_conference_find_participant(conference, mMgr->identity);
+					    role_check &= (p != nullptr);
+					    if (p) {
+						    role_check &= (linphone_participant_get_role(p) == role);
+					    }
+				    }
+				    return role_check;
 			    });
 		}
 
@@ -7484,10 +7642,9 @@ void create_conference_with_active_call_base(bool_t dialout) {
 				                                           linphone_conference_info_get_organizer(info)));
 				BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
 
-				bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+				const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
 				// Original participants + Marie who joined the conference
 				BC_ASSERT_EQUAL(bctbx_list_size(info_participants), (dialout) ? 4 : 5, size_t, "%zu");
-				bctbx_list_free(info_participants);
 
 				BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld");
 				const int duration_m = linphone_conference_info_get_duration(info);
@@ -7699,8 +7856,8 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
 				if (participant_call) {
 					BC_ASSERT_PTR_NOT_NULL(linphone_call_get_conference(participant_call));
 					BC_ASSERT_FALSE(linphone_call_is_in_conference(participant_call));
-					// BC_ASSERT_TRUE(linphone_call_get_microphone_muted(participant_call) == (mgr ==
-					// pauline.getCMgr()));
+					// BC_ASSERT_TRUE(linphone_call_get_microphone_muted(participant_call)
+					// == (mgr == pauline.getCMgr()));
 					_linphone_call_check_nb_active_streams(participant_call, 1, (toggle_video) ? 4 : 0, 0);
 				}
 			}
@@ -7907,8 +8064,8 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
 				if (participant_call) {
 					BC_ASSERT_PTR_NOT_NULL(linphone_call_get_conference(participant_call));
 					BC_ASSERT_FALSE(linphone_call_is_in_conference(participant_call));
-					// BC_ASSERT_TRUE(linphone_call_get_microphone_muted(participant_call) == (mgr ==
-					// pauline.getCMgr()));
+					// BC_ASSERT_TRUE(linphone_call_get_microphone_muted(participant_call)
+					// == (mgr == pauline.getCMgr()));
 				}
 			}
 
@@ -8155,7 +8312,3 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
 }
 
 } // namespace LinphoneTest
-
-#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
-#pragma GCC diagnostic pop
-#endif
diff --git a/tester/local_conference_tester_functions.h b/tester/local_conference_tester_functions.h
index c4fb85cce1..bdce9c14cd 100644
--- a/tester/local_conference_tester_functions.h
+++ b/tester/local_conference_tester_functions.h
@@ -353,6 +353,7 @@ void sendEphemeralMessageInAdminMode(Focus &focus,
                                      LinphoneChatRoom *recipientCr,
                                      const std::string basicText,
                                      const int noMsg);
+
 bool checkChatroom(Focus &focus, const ConfCoreManager &core, const time_t baseJoiningTime);
 
 // Conference
@@ -362,6 +363,7 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
                                                  bool_t toggle_all_mananger_video,
                                                  bool_t change_layout,
                                                  LinphoneConferenceSecurityLevel security_level);
+
 void create_conference_base(time_t start_time,
                             int duration,
                             bool_t uninvited_participant_dials,
@@ -379,13 +381,16 @@ void create_conference_base(time_t start_time,
                             LinphoneMediaDirection video_direction,
                             bool_t network_restart,
                             LinphoneConferenceSecurityLevel security_level);
+
 void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs,
                                  std::list<LinphoneCoreManager *> conferenceMgrs,
                                  LinphoneCoreManager *focus,
-                                 std::list<LinphoneCoreManager *> members,
+                                 std::map<LinphoneCoreManager *, LinphoneParticipantRole> members,
                                  const LinphoneAddress *confAddr,
                                  bool_t enable_video);
+
 void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout);
+
 void create_conference_with_late_participant_addition_base(time_t start_time,
                                                            int duration,
                                                            LinphoneConferenceLayout layout,
@@ -393,19 +398,24 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
                                                            bool_t accept,
                                                            bool_t one_addition,
                                                            LinphoneConferenceSecurityLevel security_level);
+
 void create_one_participant_conference_toggle_video_base(LinphoneConferenceLayout layout,
                                                          bool_t enable_ice,
                                                          bool_t enable_stun);
+
 void create_conference_with_active_call_base(bool_t dialout);
-LinphoneAddress *create_conference_on_server(Focus &focus,
-                                             ClientConference &organizer,
-                                             std::list<LinphoneCoreManager *> requested_participants,
-                                             time_t start_time,
-                                             time_t end_time,
-                                             const char *subject,
-                                             const char *description,
-                                             bool_t send_ics,
-                                             LinphoneConferenceSecurityLevel security_level);
+
+LinphoneAddress *
+create_conference_on_server(Focus &focus,
+                            ClientConference &organizer,
+                            std::map<LinphoneCoreManager *, LinphoneParticipantRole> requested_participants,
+                            time_t start_time,
+                            time_t end_time,
+                            const char *subject,
+                            const char *description,
+                            bool_t send_ics,
+                            LinphoneConferenceSecurityLevel security_level);
+
 void set_video_settings_in_conference(LinphoneCoreManager *focus,
                                       LinphoneCoreManager *participant,
                                       std::list<LinphoneCoreManager *> members,
@@ -414,7 +424,9 @@ void set_video_settings_in_conference(LinphoneCoreManager *focus,
                                       LinphoneMediaDirection video_direction,
                                       bool_t answer_enable_video,
                                       LinphoneMediaDirection answer_video_direction);
+
 size_t compute_no_video_streams(bool_t enable_video, LinphoneCall *call, LinphoneConference *conference);
+
 void check_conference_info(LinphoneCoreManager *mgr,
                            LinphoneAddress *confAddr,
                            LinphoneCoreManager *organizer,
@@ -426,9 +438,11 @@ void check_conference_info(LinphoneCoreManager *mgr,
                            unsigned int sequence,
                            LinphoneConferenceInfoState state,
                            LinphoneConferenceSecurityLevel security_level);
-size_t compute_no_audio_streams(LinphoneConference *conference);
+
+size_t compute_no_audio_streams(LinphoneCall *call, LinphoneConference *conference);
 
 void conference_scheduler_state_changed(LinphoneConferenceScheduler *scheduler, LinphoneConferenceSchedulerState state);
+
 void conference_scheduler_invitations_sent(LinphoneConferenceScheduler *scheduler,
                                            const bctbx_list_t *failed_addresses);
 
diff --git a/tester/local_ice_conference_tester.cpp b/tester/local_ice_conference_tester.cpp
index d724542116..b1a1c0f23d 100644
--- a/tester/local_ice_conference_tester.cpp
+++ b/tester/local_ice_conference_tester.cpp
@@ -132,8 +132,16 @@ static void abort_call_to_ice_conference(void) {
 
 		stats focus_stat = focus.getStats();
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
+
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
 		// Chat room creation to send ICS
diff --git a/tester/local_inpromptu_conference_tester.cpp b/tester/local_inpromptu_conference_tester.cpp
index a9d8c70673..48cf2b81e6 100644
--- a/tester/local_inpromptu_conference_tester.cpp
+++ b/tester/local_inpromptu_conference_tester.cpp
@@ -99,7 +99,14 @@ static void create_conference_dial_out_base(bool_t send_ics,
 		const char *initialSubject = "Schedule of the trip towards the top of Europe";
 		const char *description = "To the top of the Mont Blanc!!!! :-)";
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, -1, -1, initialSubject,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, -1, -1, initialSubject,
 		                                                        description, send_ics, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -251,11 +258,11 @@ static void create_conference_dial_out_base(bool_t send_ics,
 						    linphone_conference_info_get_organizer(call_log_info), marie.getCMgr()->identity));
 						BC_ASSERT_TRUE(
 						    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
-						bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
+						const bctbx_list_t *info_participants =
+						    linphone_conference_info_get_participants(call_log_info);
 						// Original participants + Marie who joined the conference
 						BC_ASSERT_EQUAL(bctbx_list_size(info_participants), participant_conference_info_participants,
 						                size_t, "%zu");
-						bctbx_list_free(info_participants);
 						BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0,
 						                         long long, "%lld");
 						const int duration_m = linphone_conference_info_get_duration(call_log_info);
@@ -299,8 +306,6 @@ static void create_conference_dial_out_base(bool_t send_ics,
 			                             marie_stat.number_of_NotifyFullStateReceived + 1,
 			                             liblinphone_tester_sip_timeout));
 
-			// Update to add to conference.
-			// If ICE is enabled, the addition to a conference may go through a resume of the call
 			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreated,
 			                             focus_stat.number_of_LinphoneConferenceStateCreated + 1,
 			                             liblinphone_tester_sip_timeout));
@@ -324,8 +329,26 @@ static void create_conference_dial_out_base(bool_t send_ics,
 			LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 			BC_ASSERT_PTR_NOT_NULL(fconference);
 
+			std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+			for (const auto &member : members) {
+				try {
+					const auto &participantInfo = participantList.at(member);
+					auto role = participantInfo;
+					if (role == LinphoneParticipantRoleUnknown) {
+						role = LinphoneParticipantRoleSpeaker;
+					}
+					memberList.insert(std::make_pair(member, role));
+				} catch (std::out_of_range &) {
+					if (member == marie.getCMgr()) {
+						memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+					} else {
+						ms_fatal("Unable to find active participant %s in the participant list",
+						         linphone_core_get_identity(member->lc));
+					}
+				}
+			}
 			wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs,
-			                            focus.getCMgr(), members, confAddr, enable_video);
+			                            focus.getCMgr(), memberList, confAddr, enable_video);
 
 			// wait bit more to detect side effect if any
 			CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(15), [] {
@@ -375,6 +398,10 @@ static void create_conference_dial_out_base(bool_t send_ics,
 						linphone_video_activation_policy_unref(pol);
 
 						size_t no_streams_audio = 0;
+						size_t no_max_streams_audio =
+						    (security_level == LinphoneConferenceSecurityLevelEndToEnd)
+						        ? static_cast<size_t>(participant_conference_info_participants)
+						        : 1;
 						size_t no_streams_video = 0;
 						size_t no_max_streams_video = 0;
 						size_t no_streams_text = 0;
@@ -382,13 +409,12 @@ static void create_conference_dial_out_base(bool_t send_ics,
 						LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 						BC_ASSERT_PTR_NOT_NULL(pcall);
 						if (pcall) {
-							no_streams_audio = static_cast<int>(compute_no_audio_streams(pconference));
+							no_streams_audio = compute_no_audio_streams(pcall, pconference);
 							// Even if video is not enabled, the server will offer it and clients reject the video
 							// stream if they do not want to send or receive it.
-							no_streams_video =
-							    static_cast<int>(compute_no_video_streams(enable_video, pcall, pconference));
+							no_streams_video = compute_no_video_streams(enable_video, pcall, pconference);
 							no_max_streams_video = (enabled || (mgr == marie.getCMgr())) ? no_streams_video : 1;
-							_linphone_call_check_max_nb_streams(pcall, no_streams_audio, no_max_streams_video,
+							_linphone_call_check_max_nb_streams(pcall, no_max_streams_audio, no_max_streams_video,
 							                                    no_streams_text);
 							_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_streams_video,
 							                                       no_streams_text);
@@ -410,12 +436,11 @@ static void create_conference_dial_out_base(bool_t send_ics,
 								BC_ASSERT_TRUE(linphone_address_weak_equal(
 								    linphone_conference_info_get_uri(call_log_info), confAddr));
 
-								bctbx_list_t *info_participants =
+								const bctbx_list_t *info_participants =
 								    linphone_conference_info_get_participants(call_log_info);
 								// Original participants + Marie who joined the conference
 								BC_ASSERT_EQUAL(bctbx_list_size(info_participants),
 								                participant_conference_info_participants, size_t, "%zu");
-								bctbx_list_free(info_participants);
 
 								BC_ASSERT_GREATER_STRICT(
 								    (long long)linphone_conference_info_get_date_time(call_log_info), 0, long long,
@@ -442,7 +467,7 @@ static void create_conference_dial_out_base(bool_t send_ics,
 						LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), mgr->identity);
 						BC_ASSERT_PTR_NOT_NULL(ccall);
 						if (ccall) {
-							_linphone_call_check_max_nb_streams(ccall, no_streams_audio, no_max_streams_video,
+							_linphone_call_check_max_nb_streams(ccall, no_max_streams_audio, no_max_streams_video,
 							                                    no_streams_text);
 							_linphone_call_check_nb_active_streams(ccall, no_streams_audio, no_streams_video,
 							                                       no_streams_text);
@@ -897,9 +922,16 @@ static void create_simple_conference_dial_out_organizer_codec_mismatch(void) {
 
 		const char *initialSubject = "Schedule of the trip towards the top of Europe";
 		const char *description = "To the Goutier mountain hut!!!! :-)";
-
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, -1, -1, initialSubject,
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, -1, -1, initialSubject,
 		                                                        description, TRUE, security_level);
 		BC_ASSERT_PTR_NULL(confAddr);
 
@@ -985,7 +1017,14 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 		const char *description = "Having fun!!!! :-)";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, -1, -1, initialSubject,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, -1, -1, initialSubject,
 		                                                        description, FALSE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -1094,10 +1133,9 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 					BC_ASSERT_TRUE(
 					    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
 
-					bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
+					const bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
 					// Original participants + Marie who joined the conference
 					BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 5, size_t, "%zu");
-					bctbx_list_free(info_participants);
 
 					BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0,
 					                         long long, "%lld");
@@ -1192,8 +1230,22 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 		BC_ASSERT_PTR_NOT_NULL(fconference);
 
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : all_active_participants) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
 		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conference_members,
-		                            focus.getCMgr(), all_active_participants, confAddr, TRUE);
+		                            focus.getCMgr(), memberList, confAddr, TRUE);
 
 		// wait bit more to detect side effect if any
 		CoreManagerAssert({focus, marie, pauline, laure, michelle, berthe}).waitUntil(chrono::seconds(15), [] {
@@ -1225,13 +1277,14 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 					bool_t enabled = !!linphone_video_activation_policy_get_automatically_initiate(pol);
 					linphone_video_activation_policy_unref(pol);
 
-					size_t no_streams_audio = 1;
+					size_t no_streams_audio = 0;
 					size_t no_streams_video = (enabled) ? (static_cast<int>(all_active_participants.size()) + 1) : 0;
 					size_t no_streams_text = 0;
 
 					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 					BC_ASSERT_PTR_NOT_NULL(pcall);
 					if (pcall) {
+						no_streams_audio = compute_no_audio_streams(pcall, pconference);
 						_linphone_call_check_max_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text);
 						_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_streams_video,
 						                                       no_streams_text);
@@ -1556,7 +1609,14 @@ static void simple_dial_out_conference_with_no_payloads(void) {
 		const char *description = "To the top of the Mont Blanc!!!! :-)";
 
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, -1, -1, initialSubject,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, -1, -1, initialSubject,
 		                                                        description, FALSE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -1608,7 +1668,6 @@ static void simple_dial_out_conference_with_no_payloads(void) {
 				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,
 				                             liblinphone_tester_sip_timeout));
 
-				// If ICE is enabled, the addition to a conference may go through a resume of the call
 				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateCreated, 1,
 				                             liblinphone_tester_sip_timeout));
 				BC_ASSERT_TRUE(
diff --git a/tester/local_scheduled_conference_tester.cpp b/tester/local_scheduled_conference_tester.cpp
index 35dc5391f0..ea049d0e4d 100644
--- a/tester/local_scheduled_conference_tester.cpp
+++ b/tester/local_scheduled_conference_tester.cpp
@@ -218,7 +218,15 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
 		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
 		const char *description = "Chamrousse Pub";
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
@@ -273,8 +281,8 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 			BC_ASSERT_TRUE(
 			    wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
 			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneSubscriptionActive, 1, 5000));
-			BC_ASSERT_TRUE(
-			    wait_for_list(coresList, &mgr->stat.number_of_NotifyReceived, 1, liblinphone_tester_sip_timeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_NotifyFullStateReceived, 1,
+			                             liblinphone_tester_sip_timeout));
 		}
 
 		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
@@ -307,8 +315,26 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 		                             focus_stat.number_of_participant_devices_joined + 3,
 		                             liblinphone_tester_sip_timeout));
 
-		wait_for_conference_streams({focus, marie, pauline, laure}, conferenceMgrs, focus.getCMgr(), members, confAddr,
-		                            TRUE);
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : members) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				auto role = participantInfo;
+				if (role == LinphoneParticipantRoleUnknown) {
+					role = LinphoneParticipantRoleSpeaker;
+				}
+				memberList.insert(std::make_pair(member, role));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
+		wait_for_conference_streams({focus, marie, pauline, laure}, conferenceMgrs, focus.getCMgr(), memberList,
+		                            confAddr, TRUE);
 
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 		BC_ASSERT_PTR_NOT_NULL(fconference);
@@ -345,7 +371,7 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 						                (int)LinphoneCallStateStreamsRunning, int, "%0d");
 					}
 
-					size_t no_streams_audio = (security_level == LinphoneConferenceSecurityLevelEndToEnd) ? 3 : 1;
+					size_t no_streams_audio = 0;
 					size_t no_streams_video = 0;
 					size_t no_active_streams_video = 0;
 					size_t no_streams_text = 0;
@@ -353,6 +379,7 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 					LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 					BC_ASSERT_PTR_NOT_NULL(pcall);
 					if (pcall) {
+						no_streams_audio = compute_no_audio_streams(pcall, pconference);
 						_linphone_call_check_nb_streams(pcall, no_streams_audio, no_streams_video, no_streams_text);
 						_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
 						                                       no_streams_text);
@@ -429,14 +456,14 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 						linphone_address_unref(uri);
 						BC_ASSERT_PTR_NOT_NULL(pconference);
 						if (pconference) {
-							size_t no_streams_audio =
-							    (security_level == LinphoneConferenceSecurityLevelEndToEnd) ? 3 : 1;
+							size_t no_streams_audio = 0;
 							size_t no_active_streams_video = 0;
 							size_t no_streams_text = 0;
 
 							LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 							BC_ASSERT_PTR_NOT_NULL(pcall);
 							if (pcall) {
+								no_streams_audio = compute_no_audio_streams(pcall, pconference);
 								no_active_streams_video =
 								    static_cast<int>(compute_no_video_streams(enable, pcall, pconference));
 								_linphone_call_check_nb_active_streams(pcall, no_streams_audio, no_active_streams_video,
@@ -608,7 +635,15 @@ static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mi
 		const char *description = "Paris Baker";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleListener));
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 		char *conference_address_str = (confAddr) ? linphone_address_as_string(confAddr) : ms_strdup("<unknown>");
@@ -721,8 +756,22 @@ static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mi
 			                             liblinphone_tester_sip_timeout));
 		}
 
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : members) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
 		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
-		                            members, confAddr, TRUE);
+		                            memberList, confAddr, TRUE);
 
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 		BC_ASSERT_PTR_NOT_NULL(fconference);
@@ -958,7 +1007,16 @@ static void create_conference_with_server_restart_base(bool_t organizer_first) {
 		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
 		const char *description = "London Pub";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
@@ -1060,8 +1118,22 @@ static void create_conference_with_server_restart_base(bool_t organizer_first) {
 		                             focus_stat.number_of_participant_devices_joined + 3,
 		                             liblinphone_tester_sip_timeout));
 
-		wait_for_conference_streams({focus, marie, pauline, laure}, conferenceMgrs, focus.getCMgr(), members, confAddr,
-		                            TRUE);
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> memberList;
+		for (const auto &member : members) {
+			try {
+				const auto &participantInfo = participantList.at(member);
+				memberList.insert(std::make_pair(member, participantInfo));
+			} catch (std::out_of_range &) {
+				if (member == marie.getCMgr()) {
+					memberList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+				} else {
+					ms_fatal("Unable to find active participant %s in the participant list",
+					         linphone_core_get_identity(member->lc));
+				}
+			}
+		}
+		wait_for_conference_streams({focus, marie, pauline, laure}, conferenceMgrs, focus.getCMgr(), memberList,
+		                            confAddr, TRUE);
 
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 		BC_ASSERT_PTR_NOT_NULL(fconference);
@@ -1291,7 +1363,14 @@ static void create_simple_conference_with_update_deferred(void) {
 		const char *description = "Paris Baker";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
+			                                                : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -1751,7 +1830,12 @@ static void change_active_speaker(void) {
 		const char *description = "hello";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, invitesList, start_time, end_time,
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : invitesList) {
+			participantList.insert(std::make_pair(p, role));
+		}
+		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
@@ -2010,7 +2094,13 @@ static void conference_with_participant_added_outside_valid_time_slot (bool_t be
 		const char *initialSubject = "Colleagues";
 		const char *description = "Tom Black";
 
-		LinphoneAddress* confAddr = create_conference_on_server(focus, marie, participants, start_time, end_time, initialSubject, description, TRUE, security_level);
+		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		for (auto &p : participants) {
+			participantList.insert(std::make_pair(p, role));
+			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker;
+		}
+		LinphoneAddress* confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 		// Chat room creation to send ICS
 		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated, 2, liblinphone_tester_sip_timeout));
diff --git a/tester/shared_tester_functions.cpp b/tester/shared_tester_functions.cpp
index 234db23ae4..c6a8f2948b 100644
--- a/tester/shared_tester_functions.cpp
+++ b/tester/shared_tester_functions.cpp
@@ -25,6 +25,7 @@
 #include "conference/conference-info.h"
 #include "conference/params/media-session-params.h"
 #include "conference/participant-device.h"
+#include "conference/participant-info.h"
 #include "conference/session/media-session.h"
 #include "liblinphone_tester.h"
 #include "mediastreamer2/msmire.h"
@@ -360,21 +361,6 @@ void _linphone_call_check_max_nb_streams(const LinphoneCall *call,
 	}
 }
 
-void _linphone_call_check_nb_streams(const LinphoneCall *call,
-                                     const int nb_audio_streams,
-                                     const int nb_video_streams,
-                                     const int nb_text_streams) {
-	const SalMediaDescription *call_result_desc = _linphone_call_get_result_desc(call);
-	BC_ASSERT_PTR_NOT_NULL(call_result_desc);
-	if (call_result_desc) {
-		BC_ASSERT_LOWER(call_result_desc->getNbStreams(), nb_audio_streams + nb_video_streams + nb_text_streams, size_t,
-		                "%zu");
-		BC_ASSERT_LOWER(call_result_desc->nbStreamsOfType(SalAudio), nb_audio_streams, size_t, "%zu");
-		BC_ASSERT_LOWER(call_result_desc->nbStreamsOfType(SalVideo), nb_video_streams, size_t, "%zu");
-		BC_ASSERT_LOWER(call_result_desc->nbStreamsOfType(SalText), nb_text_streams, size_t, "%zu");
-	}
-}
-
 void _linphone_call_check_nb_streams(const LinphoneCall *call,
                                      const size_t nb_audio_streams,
                                      const size_t nb_video_streams,
@@ -753,23 +739,22 @@ bool_t linphone_conference_type_is_full_state(const char *text) {
 	           : FALSE;
 }
 
+void linphone_conference_info_check_participant_info(const std::shared_ptr<ParticipantInfo> &info,
+                                                     int sequence_number) {
+	const auto &sequence = info->getSequenceNumber();
+	BC_ASSERT_GREATER(sequence, 0, int, "%0d");
+	BC_ASSERT_EQUAL(sequence, sequence_number, int, "%d");
+}
+
 void linphone_conference_info_check_participant(const LinphoneConferenceInfo *conference_info,
                                                 LinphoneAddress *address,
                                                 int sequence_number) {
-	const auto &sequence = LinphonePrivate::ConferenceInfo::toCpp(conference_info)
-	                           ->getParticipantParam(Address::toCpp(address)->getSharedFromThis(), "X-SEQ");
-	BC_ASSERT_TRUE(!sequence.empty());
-	if (!sequence.empty()) {
-		const int sequenceNumber = std::atoi(sequence.c_str());
-		BC_ASSERT_EQUAL(sequenceNumber, sequence_number, int, "%d");
-	}
+	const auto &participantInfo = LinphonePrivate::ConferenceInfo::toCpp(conference_info)
+	                                  ->findParticipant(Address::toCpp(address)->getSharedFromThis());
+	linphone_conference_info_check_participant_info(participantInfo, sequence_number);
 }
 
 void linphone_conference_info_check_organizer(const LinphoneConferenceInfo *conference_info, int sequence_number) {
-	const auto &sequence = LinphonePrivate::ConferenceInfo::toCpp(conference_info)->getOrganizerParam("X-SEQ");
-	BC_ASSERT_TRUE(!sequence.empty());
-	if (!sequence.empty()) {
-		const int sequenceNumber = std::atoi(sequence.c_str());
-		BC_ASSERT_EQUAL(sequenceNumber, sequence_number, int, "%d");
-	}
+	const auto &organizer = LinphonePrivate::ConferenceInfo::toCpp(conference_info)->getOrganizer();
+	linphone_conference_info_check_participant_info(organizer, sequence_number);
 }
diff --git a/tester/utils-tester.cpp b/tester/utils-tester.cpp
index 94ca8bd8cf..84baa33c33 100644
--- a/tester/utils-tester.cpp
+++ b/tester/utils-tester.cpp
@@ -21,6 +21,7 @@
 #include "bctoolbox/utils.hh"
 
 #include "address/address.h"
+#include "conference/conference-id.h"
 #include "liblinphone_tester.h"
 #include "linphone/utils/utils.h"
 #include "tester_utils.h"
-- 
GitLab