diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c
index 0fef5bcbb9c4b0abc018d62ba7f4edbdacb47a14..97f59a3e479d883be50478e48a5fed54277957e0 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 94994bf71469a9d063532e65eb5816ded387c60a..c2518aa389c1e7dfdee45a4689fb1ee6dc9d57ca 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 39d38a2d0f42934119c4c992a424d3de57882ac5..947a6b9a753eded63e9bc14a41ad81359a55bf14 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 78370947b35bb6abc6768c07ca87d058f308e57f..c4cc8e6cfaa7ef4f6831b1932210cdf6be7c25a8 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 d0c93a4075eaf0e802cf3a2fb355091ed0feef2d..a62c037bc7088dfcbaa6420b5409c822b93e1e25 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 82b9bf0dba4da8cfb49f8e19148a6ad6aa6985d1..c85c66cbf6ff4f9fe6805b0c70cb1d762d405fe5 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 b03285cc80ff71cc6daf00bd3e88540cea0d1540..e004259f5432436b40a5392479f38d66d8273e53 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 59b3c6ef7459623d7239d7992f02a362752bd29e..cda3328b240e5aa1f384498549d319b3ad330908 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 6df2219373f692294bc9c9a47a805f02dd22948c..35fc7deae7387347cf0da85cadb21f3b4ce76d64 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 a12ef932f6fb9986ba887ba9d4e26de923c06c53..cb4e3b4462b2d800069b8e7fe5b0af32e8866327 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 07c4447482aacad79746b7e89aa596682d022474..7a73faf8dca3e7a2422d9796ed28e5983fb79e76 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 372d6be358053e293f50b9396f30eba4ab6aa64f..575238b1ce804f7920055c99bf739100bde63b57 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 2f10cdb9b89832c0ce32d9905dec5862f20ae5d8..631c4b0e6fe55fc11e09e1132294d0ddeaf1df80 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 21b284ca354fd59e4338ac1789187716375b978a..06d371ae001a6ed98d4d2087705af6d5a5180186 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 af0268fc16ff01b610620f6f70af0d9bf16eaf54..593fd9779b1e49866ea6b3ce0210039377ba9433 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 0000000000000000000000000000000000000000..7266c17f10aaf62e999e0a5e4653c2f33671ead7
--- /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 09637f41045d94ebd13d6de13d85961daa872d70..f065acf54beac672484706d868edefef5d735d7d 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 baec1b69e9d8753094570726f8077c1dd8fcea77..de442e0af690f6370050c6d3f74e79cfe40db0cb 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 0000000000000000000000000000000000000000..cf439f66632034267ab833d93b8a4229630b18ea
--- /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 328564eb4d2a4826d3816f28d7b23f0a952e0269..bc015334128d5c073400acb06a807fed09cabcf0 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 8c1c9272cd080239f5dbddd8184b5aa7c9298c8e..893847af4cdd656f47a8cd3ad692d0fa13a7e173 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 80dd69d9171d04d18b513f09aa81f5351229fb4a..21af77fa4b9e8127ca9f89cf631ba9b1225ab896 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 256a3134f63cda84b06d2ded63b04669639dc49a..e238eccbf640aa98ce1a74355e27b2fbbf3be91e 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 53f7303fb76764060223fdc74dbbcf321e13d2b1..4dd82e9c9a6e1123be88845827125a013c7f5c98 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 b11308f58ec7aee915fb0c656459f4ea5f74ab33..2b9b55867ee2b50335977b7a8c8e465b2cfd1a91 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 19561f730aa9c4a451d204507a3897592515ba20..b0feacc514d849b4979efee865855dcc8028b343 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 0000000000000000000000000000000000000000..53a143576936b4f06aba3d01970cc1c0035aedc8
--- /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 528136a90c878247835f0e361bf40dc9dd01cffb..f2bfd2397152f9f1d403074ee7946700893c6050 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 987221812508e8f610af5262693360b5ced2afc8..f62f81d5801e5183cee2a127f90c685b952ac5b3 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 0000000000000000000000000000000000000000..84124a8a1cf46e2cd4173639ba9b3fc68430a11f
--- /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 67b609bbec305fd64ec8eb79daab3530e90e9dd0..4d05081e109dd041dc30c8c567b7a0454e20eb51 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 21ad93b09877668a3745f4070161b0cfab5c4cd2..d8e7385e687c624797442ff04988e1c105456696 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 422fde411fa99aa0e2b8f38ffd9bdb75cda8acf1..38cd2f93fb9c3ef958f053ca6f798b7606fee35f 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 6e240203824645fb14ad642a7df2c271950af448..9a865500c93070160ba6bac1962f45320e11f315 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 cf35f58870168049d3b72da74b69691d9f3916a7..e67b25a7e1ca5fb21fab9a43e1846b3b513fd674 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 b60ffcc0e5764e3a00250121938b6887e8f2157a..e111c985895c541cd6e7cf450de98ed5a33bb628 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 ba9fdc27ead355da1beda1186556d909771adb9e..2028907888ed54bcdc4a67320771db9eb02d290a 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 6304531fa92895471e401b7c5d0a688639f5f146..e2c28568e72a12fb771e74013040d3c914148345 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 fc1e9900ba21403f0207ca8630b6ce3d11e5eef4..d9f2990dda4e0aaf01774e3958b6ba4c8f057a78 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 b3365820a47457d5f0564c28816afbee2924e899..7a5290070e56df8e1ef5ea706c227a3303608abd 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 fa7d368c91d0eebc8c8a4778b5f9ca26d28f229d..0cf6a1a25ede5d65b2706c8f519e3fe6999216b6 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 ec346119b44206545d31cb02fc0bf6065210d291..2f19adba716da4a33398e21f9fb873882eba9620 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 dbb13b371c0df546da949800699d0164c8d46dcb..b0e5b814068dbfe5c7adc432d9ab635c514f4b6c 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 2b61c7884220bf01b58c327443b22065e9a73111..4d9c980f5b86cac70de63540858710c74f15be12 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 724088abecbf9762e73fd201b5b3ebea1e83c149..1f3a49d6b47392e590aead2026d3a69f59203b1b 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 a0e27cd9df7b9fcf8af11de0b13928322d15b056..ca6947bde878c320ca59ab0db46523a1efd95ac8 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 0000000000000000000000000000000000000000..09ec6728e3add007b9b1785f6f8cbe4ec7ea392a
--- /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 0000000000000000000000000000000000000000..df9be9bcaf014823a82bd9a17bdb78e7cae89adc
--- /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 6f7cc7df8e9832654d23f19fdb68a582dd207482..4bea9e919aaec6d04cb749aafeabf54b9e4c7a35 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 970928c0388dbb3e329791ff2b29b5ab985b31a7..d9add46b6cf16bd72ba09691215ca73a7525eebc 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 52bab2ec2a8e56b7004c7fb5658d9cf43bbf0c57..1b0d7acd4ba509ba76b482ca74426f80fb8aa2b6 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 c37af9bff144b2dd4a2c0086cba53acdf54e9e87..b4b792313528fbaa9168c03cc547dcd46537aa67 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 6a29d5014877129248e8008bc4dfd3f6999938d2..0a55569f66993f9851f1b676eb0ce66867d7ea03 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 ceed7a1f33eee534862470101621a8c3ae2d74f1..b7decff4337a68b7e23b913df5187f1885b6f398 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 6f618f086870495bdfad0e669c8fd17147cacfee..2a1f08847c4d17f2022be996213546f1e7f91725 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 cad6893d4124a91490527685ee6760b876451ced..2243dd8391afd06f0e83be5215332a66ec4374f6 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 14155aa561e3fd3ce1dc005704f32ed5e5fe60f4..b82652c8a3981888147cff80f4c98a7b3b25cdd3 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 95314db407f87439a7df8fdcde82395fa9283cb5..10ced792dd4da095147207bb26121f4a8e515e8b 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 a1e013833815fb6c63bdad1bf4c9682919eb499d..569c31e5d744c60b9e4eb3179d1977113b3d6949 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 8525230455bec62fa9bc4b90c52cfbd5a2c71b62..314ca423155de67cd68da8a628b5cb6a2c8e75c0 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 4820515ab891c74cbaaba55ac6ef154fd0f09ceb..d024c33517f235c214ed84ea770bf06a5821dadf 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 c9119af383b1e4fd0eb701adbc00882cabb11d22..ba0a4de43e4975b0c668c9b47700e861f4a2d1ac 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 bc6310c3a0a96a5691aed87d28008a7559fd5c07..69aadc122fbe3dd3fd94b5f7690ffe431bce968e 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 06d65eb17b47f11e545c43e90f18c9f8cb26b306..9ca0d071357f8239f5bdb596b3e9a5e8c22a037d 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 0000000000000000000000000000000000000000..10243dc51c2ab5b64ecee9d606839734b94664e8
--- /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 25cfe44cffb06800c4e6f7c1df3126c6d3cc7bbc..1148da05d017c9a66f8e5486d7c7c77b07d31c7c 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 c4fb85cce11c2481c430b54ccab8c49dcb79822e..bdce9c14cdd7a20db342050620c82f1b38c9b9c2 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 d724542116852e8dd351f29482be49f4f0d61f78..b1a1c0f23d912b384d38d1fbb1728672baffca5c 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 a9d8c706737a5f289be0d0bfa38770cb8c09a8f1..48cf2b81e67c38823c6f72dfc72c2af2b7c98a31 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 35dc5391f021e42b961acd3086d082f8e836e0b4..ea049d0e4de8cc3fbeb3b3d2632ad93e1eccfe80 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 234db23ae47faabbe78f069e167523746d73a04d..c6a8f2948b842712ed6545e0a2660a8161f37d54 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 94ca8bd8cf3a279c75312d091fb8e9e32ab5cb67..84baa33c33f1e3623f71416c482df4bead68e4d2 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"