From 5f3273b847ae7be8e202ff56650701bf04bd1b70 Mon Sep 17 00:00:00 2001
From: Andrea Gianarda <andrea.gianarda@belledonne-communications.com>
Date: Tue, 29 Aug 2023 12:28:31 +0200
Subject: [PATCH] Source code:   - Add callback to notify the application that
 a participant has changed role in the conference   - Take into account role
 when creating the list of participant informations of a conference   - Give
 priority to the conference information stored in the database over that
 cached in the call log object   - When a participant is added, give the
 application a pointer to it with all the informations up to date   - In the
 event of a full state, reduce the number of database accesses by updating the
 conference information in the callback onFullStateReceived. Previously, for
 every participant added a DB access was required in order to update the
 conference information

Tests:
  - Add verification of role and sequence id of every participant info in the conference information in the call logs and conference information
  - add helper functions to ease checking of conference informations
---
 coreapi/conference-cbs.h                      |   1 +
 coreapi/conference.cpp                        |   7 +
 coreapi/local_conference.cpp                  |   8 +-
 coreapi/private_functions.h                   |  12 +
 coreapi/remote_conference.cpp                 |  65 +-
 coreapi/remote_conference.h                   |   4 +
 coreapi/tester_utils.h                        |   3 +
 include/linphone/api/c-callbacks.h            |   8 +
 include/linphone/api/c-conference-cbs.h       |  17 +
 include/linphone/api/c-participant-info.h     |   2 +-
 include/linphone/enums/event-log-enums.h      |   3 +
 src/c-wrapper/api/c-call-log.cpp              |   2 +-
 src/c-wrapper/api/c-conference-cbs.cpp        |  10 +
 src/c-wrapper/api/c-conference-info.cpp       |  11 +
 src/c-wrapper/api/c-conference.cpp            |   6 +
 src/c-wrapper/api/c-participant-info.cpp      |  10 +-
 src/call/call-log.cpp                         |   7 +-
 src/call/call-log.h                           |   2 +-
 src/chat/chat-message/chat-message.cpp        |   3 +-
 src/chat/chat-room/chat-room.cpp              |   1 +
 src/chat/chat-room/server-group-chat-room.cpp |   2 +-
 src/chat/encryption/encryption-engine.h       |   2 +-
 src/conference/conference-info.cpp            |  35 +-
 src/conference/conference-interface.h         |   9 +
 src/conference/conference-scheduler.cpp       |  42 +-
 src/conference/conference.cpp                 | 133 +++-
 src/conference/conference.h                   |  12 +-
 .../local-conference-event-handler.cpp        |   2 +-
 .../remote-conference-event-handler.cpp       |  83 +-
 .../remote-conference-event-handler.h         |   5 +
 src/conference/notify-conference-listener.cpp |   6 +
 src/conference/notify-conference-listener.h   |   8 +
 src/conference/participant-device.cpp         |   1 +
 src/conference/participant-info.cpp           |   6 +-
 src/conference/participant-info.h             |   4 +-
 src/conference/participant.cpp                |  13 +
 src/conference/participant.h                  |  12 +-
 src/conference/session/call-session.cpp       |   9 +-
 src/conference/session/call-session.h         |   9 +-
 src/db/main-db.cpp                            |  62 +-
 src/db/main-db.h                              |   2 +-
 src/event-log/event-log.cpp                   |   9 +
 src/event-log/event-log.h                     |   3 +
 tester/liblinphone_tester.h                   |   1 +
 tester/local_conference_edition_tester.cpp    | 506 +++++-------
 tester/local_conference_tester_functions.cpp  | 742 ++++++++++--------
 tester/local_conference_tester_functions.h    |  65 +-
 tester/local_ice_conference_tester.cpp        |  16 +-
 tester/local_inpromptu_conference_tester.cpp  | 372 +++++----
 tester/local_scheduled_conference_tester.cpp  | 297 +++++--
 tester/tester.c                               |   8 +
 51 files changed, 1683 insertions(+), 975 deletions(-)

diff --git a/coreapi/conference-cbs.h b/coreapi/conference-cbs.h
index 282610b0c8..8aca741765 100644
--- a/coreapi/conference-cbs.h
+++ b/coreapi/conference-cbs.h
@@ -35,6 +35,7 @@ public:
 	LinphoneConferenceCbsParticipantRemovedCb participantRemovedCb;
 	LinphoneConferenceCbsParticipantDeviceAddedCb participantDeviceAddedCb;
 	LinphoneConferenceCbsParticipantDeviceRemovedCb participantDeviceRemovedCb;
+	LinphoneConferenceCbsParticipantRoleChangedCb participantRoleChangedCb;
 	LinphoneConferenceCbsParticipantAdminStatusChangedCb participantAdminStatusChangedCb;
 	LinphoneConferenceCbsParticipantDeviceMediaCapabilityChangedCb participantDeviceMediaCapabilityChangedCb;
 	LinphoneConferenceCbsParticipantDeviceMediaAvailabilityChangedCb participantDeviceMediaAvailabilityChangedCb;
diff --git a/coreapi/conference.cpp b/coreapi/conference.cpp
index 947a6b9a75..e0796feb73 100644
--- a/coreapi/conference.cpp
+++ b/coreapi/conference.cpp
@@ -550,9 +550,16 @@ ConferenceInfo::participant_list_t Conference::getFullParticipantList() const {
 		});
 		if (pIt == participantList.end()) {
 			auto participantInfo = Factory::get()->createParticipantInfo(pAddress);
+			participantInfo->setRole(p->getRole());
 			participantList.push_back(participantInfo);
 		}
 	}
+	if (isIn()) {
+		auto me = getMe();
+		auto participantInfo = Factory::get()->createParticipantInfo(me->getAddress());
+		participantInfo->setRole(me->getRole());
+		participantList.push_back(participantInfo);
+	}
 	return participantList;
 }
 
diff --git a/coreapi/local_conference.cpp b/coreapi/local_conference.cpp
index 6a90697f95..f3071c6df1 100644
--- a/coreapi/local_conference.cpp
+++ b/coreapi/local_conference.cpp
@@ -217,18 +217,20 @@ void LocalConference::updateConferenceInformation(SalCallOp *op) {
 			}
 			conferenceInfo->setState(infoState);
 
+			long long conferenceInfoId = -1;
 #ifdef HAVE_DB_STORAGE
 			auto &mainDb = getCore()->getPrivate()->mainDb;
 			if (mainDb) {
 				lInfo()
 				    << "Inserting conference information to database in order to be able to recreate the conference "
 				    << *getConferenceAddress() << " in case of restart";
-				mainDb->insertConferenceInfo(conferenceInfo);
+				conferenceInfoId = mainDb->insertConferenceInfo(conferenceInfo);
 			}
 #endif
 			auto callLog = session->getLog();
 			if (callLog) {
 				callLog->setConferenceInfo(conferenceInfo);
+				callLog->setConferenceInfoId(conferenceInfoId);
 			}
 			if (resourceList.isEmpty()) {
 				setState(ConferenceInterface::State::TerminationPending);
@@ -463,6 +465,7 @@ void LocalConference::confirmCreation() {
 		session->startIncomingNotification(false);
 
 		const auto &conferenceInfo = createOrGetConferenceInfo();
+		long long conferenceInfoId = -1;
 #ifdef HAVE_DB_STORAGE
 		/// Method startIncomingNotification can move the conference to the CreationFailed state if the organizer
 		/// doesn't have any of the codecs the server supports
@@ -476,13 +479,14 @@ void LocalConference::confirmCreation() {
 				lInfo()
 				    << "Inserting conference information to database in order to be able to recreate the conference "
 				    << conferenceAddressStr << " in case of restart";
-				mainDb->insertConferenceInfo(conferenceInfo);
+				conferenceInfoId = mainDb->insertConferenceInfo(conferenceInfo);
 			}
 		}
 #endif
 		auto callLog = session->getLog();
 		if (callLog) {
 			callLog->setConferenceInfo(conferenceInfo);
+			callLog->setConferenceInfoId(conferenceInfoId);
 		}
 
 	} else {
diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h
index 4020cacddc..6870c277d9 100644
--- a/coreapi/private_functions.h
+++ b/coreapi/private_functions.h
@@ -422,6 +422,8 @@ void _linphone_conference_notify_participant_device_added(LinphoneConference *co
                                                           const LinphoneParticipantDevice *participant_device);
 void _linphone_conference_notify_participant_device_removed(LinphoneConference *conference,
                                                             const LinphoneParticipantDevice *participant_device);
+void _linphone_conference_notify_participant_role_changed(LinphoneConference *conference,
+                                                          const LinphoneParticipant *participant);
 void _linphone_conference_notify_participant_admin_status_changed(LinphoneConference *conference,
                                                                   const LinphoneParticipant *participant);
 void _linphone_conference_notify_participant_device_media_capability_changed(
@@ -1006,9 +1008,19 @@ bctbx_list_t *linphone_core_get_supported_media_encryptions_at_compile_time();
 LinphoneConferenceState linphone_chat_room_state_to_conference_state(LinphoneChatRoomState state);
 LinphoneChatRoomState linphone_conference_state_to_chat_room_state(LinphoneConferenceState state);
 
+// FIXME: Remove this declaration, use LINPHONE_PUBLIC as ugly workaround, already defined in tester_utils.h
+LINPHONE_PUBLIC int linphone_participant_info_get_sequence_number(const LinphoneParticipantInfo *participant_info);
+LINPHONE_PUBLIC void linphone_participant_info_set_sequence_number(LinphoneParticipantInfo *participant_info,
+                                                                   int sequence);
+
+LINPHONE_PUBLIC void linphone_conference_info_set_ics_sequence(LinphoneConferenceInfo *conference_info,
+                                                               unsigned int sequence);
 LINPHONE_PUBLIC unsigned int linphone_conference_info_get_ics_sequence(const LinphoneConferenceInfo *conference_info);
 LINPHONE_PUBLIC const char *linphone_conference_info_get_utf8_ics_uid(const LinphoneConferenceInfo *conference_info);
+LINPHONE_PUBLIC void linphone_conference_info_set_ics_uid(LinphoneConferenceInfo *conference_info, const char *uid);
 LINPHONE_PUBLIC const char *linphone_conference_info_get_ics_uid(const LinphoneConferenceInfo *conference_info);
+LINPHONE_PUBLIC void linphone_conference_info_set_state(LinphoneConferenceInfo *conference_info,
+                                                        LinphoneConferenceInfoState state);
 
 LinphoneDigestAuthenticationPolicy *linphone_digest_authentication_policy_new(void);
 LinphoneDigestAuthenticationPolicy *linphone_digest_authentication_policy_new_from_config(LinphoneConfig *config);
diff --git a/coreapi/remote_conference.cpp b/coreapi/remote_conference.cpp
index 3202cb76ac..ef830fab76 100644
--- a/coreapi/remote_conference.cpp
+++ b/coreapi/remote_conference.cpp
@@ -811,8 +811,7 @@ bool RemoteConference::transferToFocus(std::shared_ptr<LinphonePrivate::Call> ca
 		const auto &remoteAddress = call->getRemoteAddress();
 		lInfo() << "Transfering call (local address " << call->getLocalAddress()->toString() << " remote address "
 		        << (remoteAddress ? remoteAddress->toString() : "Unknown") << ") to focus " << *referToAddr;
-		const auto &participantAddress = participant->getAddress();
-		updateParticipantsInConferenceInfo(participantAddress);
+		updateParticipantInConferenceInfo(participant);
 		if (call->transfer(referToAddr->toString()) == 0) {
 			m_transferingCalls.push_back(call);
 			return true;
@@ -859,7 +858,7 @@ void RemoteConference::onFocusCallStateChanged(LinphoneCallState state) {
 	switch (state) {
 		case LinphoneCallStreamsRunning: {
 
-			updateParticipantsInConferenceInfo(getMe()->getAddress());
+			updateParticipantInConferenceInfo(getMe());
 			const auto &previousState = session->getPreviousState();
 			// NOTIFY that a participant has been added only if it follows a resume of the call
 			if (previousState == CallSession::State::Resuming) {
@@ -1272,8 +1271,22 @@ void RemoteConference::onParticipantAdded(const shared_ptr<ConferenceParticipant
                                           const std::shared_ptr<Participant> &participant) {
 	const std::shared_ptr<Address> &pAddr = event->getParticipantAddress();
 
-	const auto &participantAddress = participant->getAddress();
-	updateParticipantsInConferenceInfo(participantAddress);
+	// When receiving a participant added notification, we must recreate the conference informations in order to get the
+	// participant list up to date
+	const auto conferenceInfo = getUpdatedConferenceInfo();
+	auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr;
+	if (callLog) {
+		callLog->setConferenceInfo(conferenceInfo);
+	}
+
+#ifdef HAVE_DB_STORAGE
+	auto &mainDb = getCore()->getPrivate()->mainDb;
+	if (mainDb) {
+		lInfo() << "Updating conference information of conference " << *getConferenceAddress()
+		        << " because participant " << *pAddr << " has been added to the conference";
+		mainDb->insertConferenceInfo(conferenceInfo);
+	}
+#endif // HAVE_DB_STORAGE
 
 	if (isMe(pAddr)) {
 		if (getState() == ConferenceInterface::State::CreationPending) {
@@ -1305,10 +1318,37 @@ void RemoteConference::onParticipantAdded(const shared_ptr<ConferenceParticipant
 	}
 }
 
+void RemoteConference::onSubjectChanged(BCTBX_UNUSED(const std::shared_ptr<ConferenceSubjectEvent> &event)) {
+	const auto conferenceInfo = createOrGetConferenceInfo();
+	auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr;
+	if (callLog) {
+		callLog->setConferenceInfo(conferenceInfo);
+	}
+}
+
+void RemoteConference::onParticipantSetRole(BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantEvent> &event),
+                                            BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
+
+	updateParticipantRoleInConferenceInfo(participant);
+	const auto conferenceInfo = createOrGetConferenceInfo();
+	auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr;
+	if (callLog) {
+		callLog->setConferenceInfo(conferenceInfo);
+	}
+}
+
 void RemoteConference::onParticipantRemoved(const shared_ptr<ConferenceParticipantEvent> &event,
                                             BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
 	const std::shared_ptr<Address> &pAddr = event->getParticipantAddress();
 
+	// When receiving a participant removed notification, we must recreate the conference informations in order to get
+	// the security level and the participant list up to date
+	const auto conferenceInfo = createOrGetConferenceInfo();
+	auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr;
+	if (callLog) {
+		callLog->setConferenceInfo(conferenceInfo);
+	}
+
 	if (isMe(pAddr)) {
 		lInfo() << "Unsubscribing all devices of me (address " << *pAddr << ") from conference "
 		        << *getConferenceAddress();
@@ -1437,11 +1477,8 @@ void RemoteConference::onParticipantDeviceMediaAvailabilityChanged(
 void RemoteConference::onFullStateReceived() {
 	// When receiving a full state, we must recreate the conference informations in order to get the security level and
 	// the participant list up to date
-	const auto conferenceInfo = createOrGetConferenceInfo();
-	auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr;
-	if (callLog) {
-		callLog->setConferenceInfo(conferenceInfo);
-	}
+	const auto conferenceInfo = getUpdatedConferenceInfo();
+	long long conferenceInfoId = -1;
 
 #ifdef HAVE_DB_STORAGE
 	// Store into DB after the start incoming notification in order to have a valid conference address being the contact
@@ -1449,10 +1486,16 @@ void RemoteConference::onFullStateReceived() {
 	auto &mainDb = getCore()->getPrivate()->mainDb;
 	if (mainDb) {
 		lInfo() << "Inserting conference information to database related to conference " << *getConferenceAddress();
-		mainDb->insertConferenceInfo(conferenceInfo);
+		conferenceInfoId = mainDb->insertConferenceInfo(conferenceInfo);
 	}
 #endif // HAVE_DB_STORAGE
 
+	auto callLog = getMainSession() ? getMainSession()->getLog() : nullptr;
+	if (callLog) {
+		callLog->setConferenceInfo(conferenceInfo);
+		callLog->setConferenceInfoId(conferenceInfoId);
+	}
+
 	auto requestStreams = [this]() -> LinphoneStatus {
 		lInfo() << "Sending re-INVITE in order to get streams after joining conference " << *getConferenceAddress();
 		setState(ConferenceInterface::State::Created);
diff --git a/coreapi/remote_conference.h b/coreapi/remote_conference.h
index 35fc7deae7..7d6e72d120 100644
--- a/coreapi/remote_conference.h
+++ b/coreapi/remote_conference.h
@@ -139,6 +139,10 @@ public:
 
 	virtual void setParticipantAdminStatus(const std::shared_ptr<LinphonePrivate::Participant> &participant,
 	                                       bool isAdmin) override;
+
+	virtual void onSubjectChanged(const std::shared_ptr<ConferenceSubjectEvent> &event) override;
+	virtual void onParticipantSetRole(const std::shared_ptr<ConferenceParticipantEvent> &event,
+	                                  const std::shared_ptr<Participant> &participant) override;
 	virtual void setSubject(const std::string &subject) override;
 	virtual bool update(const ConferenceParamsInterface &params) override;
 
diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h
index 505aafa174..537ed2bfb4 100644
--- a/coreapi/tester_utils.h
+++ b/coreapi/tester_utils.h
@@ -306,6 +306,9 @@ LINPHONE_PUBLIC const char *linphone_core_get_ephemeral_version(const LinphoneCo
 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,
                                                       const LinphoneAddress *uri);
+LINPHONE_PUBLIC int linphone_participant_info_get_sequence_number(const LinphoneParticipantInfo *participant_info);
+LINPHONE_PUBLIC void linphone_participant_info_set_sequence_number(LinphoneParticipantInfo *participant_info,
+                                                                   int sequence);
 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/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h
index ff0e359793..267fc237fc 100644
--- a/include/linphone/api/c-callbacks.h
+++ b/include/linphone/api/c-callbacks.h
@@ -657,6 +657,14 @@ typedef void (*LinphoneConferenceCbsParticipantDeviceMediaAvailabilityChangedCb)
 typedef void (*LinphoneConferenceCbsParticipantDeviceMediaCapabilityChangedCb)(LinphoneConference *conference,
                                                                                const LinphoneParticipantDevice *device);
 
+/**
+ * Callback used to notify a conference that the role of a participant has been changed.
+ * @param[in] conference #LinphoneConference object @notnil
+ * @param[in] participant #LinphoneParticipant whose role has changed @notnil
+ */
+typedef void (*LinphoneConferenceCbsParticipantRoleChangedCb)(LinphoneConference *conference,
+                                                              const LinphoneParticipant *participant);
+
 /**
  * Callback used to notify a conference that the admin status of a participant has been changed.
  * @param[in] conference #LinphoneConference object @notnil
diff --git a/include/linphone/api/c-conference-cbs.h b/include/linphone/api/c-conference-cbs.h
index 8502f87db3..61d5d81319 100644
--- a/include/linphone/api/c-conference-cbs.h
+++ b/include/linphone/api/c-conference-cbs.h
@@ -128,6 +128,23 @@ LINPHONE_PUBLIC void
 linphone_conference_cbs_set_participant_device_removed(LinphoneConferenceCbs *cbs,
                                                        LinphoneConferenceCbsParticipantDeviceRemovedCb cb);
 
+/**
+ * Get the participant role changed callback.
+ * @param[in] cbs #LinphoneConferenceCbs object.
+ * @return The current participant role changed callback.
+ */
+LINPHONE_PUBLIC LinphoneConferenceCbsParticipantRoleChangedCb
+linphone_conference_cbs_get_participant_role_changed(const LinphoneConferenceCbs *cbs);
+
+/**
+ * Set the participant role changed callback.
+ * @param[in] cbs #LinphoneConferenceCbs object.
+ * @param[in] cb The participant role changed callback to be used.
+ */
+LINPHONE_PUBLIC void
+linphone_conference_cbs_set_participant_role_changed(LinphoneConferenceCbs *cbs,
+                                                     LinphoneConferenceCbsParticipantRoleChangedCb cb);
+
 /**
  * Get the participant admin status changed callback.
  * @param[in] cbs #LinphoneConferenceCbs object.
diff --git a/include/linphone/api/c-participant-info.h b/include/linphone/api/c-participant-info.h
index 7266c17f10..81b6866b92 100644
--- a/include/linphone/api/c-participant-info.h
+++ b/include/linphone/api/c-participant-info.h
@@ -36,7 +36,7 @@ extern "C" {
  * Create a new #LinphoneParticipantInfo object.
  * @return The newly created #LinphoneParticipantInfo object. @notnil
  */
-LINPHONE_PUBLIC LinphoneParticipantInfo *linphone_participant_info_new(LinphoneAddress *address);
+LINPHONE_PUBLIC LinphoneParticipantInfo *linphone_participant_info_new(const LinphoneAddress *address);
 
 /**
  * Take a reference on a #LinphoneParticipantInfo.
diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h
index 1c5220c465..b80bc7663b 100644
--- a/include/linphone/enums/event-log-enums.h
+++ b/include/linphone/enums/event-log-enums.h
@@ -41,6 +41,9 @@ typedef enum _EventLogType {
 	LinphoneEventLogTypeConferenceChatMessage = 5,               /**< Conference chat message event */
 	LinphoneEventLogTypeConferenceParticipantAdded = 6,          /**< Conference participant (added) event */
 	LinphoneEventLogTypeConferenceParticipantRemoved = 7,        /**< Conference participant (removed) event */
+	LinphoneEventLogTypeConferenceParticipantRoleUnknown = 25,   /**< Conference participant (role unknown) event */
+	LinphoneEventLogTypeConferenceParticipantRoleSpeaker = 26,   /**< Conference participant (role speaker) event */
+	LinphoneEventLogTypeConferenceParticipantRoleListener = 27,  /**< Conference participant (role listener) event */
 	LinphoneEventLogTypeConferenceParticipantSetAdmin = 8,       /**< Conference participant (set admin) event */
 	LinphoneEventLogTypeConferenceParticipantUnsetAdmin = 9,     /**< Conference participant (unset admin) event */
 	LinphoneEventLogTypeConferenceParticipantDeviceAdded = 10,   /**< Conference participant device (added) event */
diff --git a/src/c-wrapper/api/c-call-log.cpp b/src/c-wrapper/api/c-call-log.cpp
index 77db2278da..6646511a59 100644
--- a/src/c-wrapper/api/c-call-log.cpp
+++ b/src/c-wrapper/api/c-call-log.cpp
@@ -134,7 +134,7 @@ LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLo
 }
 
 LinphoneConferenceInfo *linphone_call_log_get_conference_info(LinphoneCallLog *call_log) {
-	auto confInfo = CallLog::toCpp(call_log)->getConferenceInfo();
+	auto &confInfo = CallLog::toCpp(call_log)->getConferenceInfo();
 	if (confInfo) return confInfo->toC();
 
 	return nullptr;
diff --git a/src/c-wrapper/api/c-conference-cbs.cpp b/src/c-wrapper/api/c-conference-cbs.cpp
index f26f2b2ba9..c0daf012e4 100644
--- a/src/c-wrapper/api/c-conference-cbs.cpp
+++ b/src/c-wrapper/api/c-conference-cbs.cpp
@@ -88,6 +88,16 @@ void linphone_conference_cbs_set_participant_device_removed(LinphoneConferenceCb
 	ConferenceCbs::toCpp(cbs)->participantDeviceRemovedCb = cb;
 }
 
+LinphoneConferenceCbsParticipantRoleChangedCb
+linphone_conference_cbs_get_participant_role_changed(const LinphoneConferenceCbs *cbs) {
+	return ConferenceCbs::toCpp(cbs)->participantRoleChangedCb;
+}
+
+void linphone_conference_cbs_set_participant_role_changed(LinphoneConferenceCbs *cbs,
+                                                          LinphoneConferenceCbsParticipantRoleChangedCb cb) {
+	ConferenceCbs::toCpp(cbs)->participantRoleChangedCb = cb;
+}
+
 LinphoneConferenceCbsParticipantAdminStatusChangedCb
 linphone_conference_cbs_get_participant_admin_status_changed(const LinphoneConferenceCbs *cbs) {
 	return ConferenceCbs::toCpp(cbs)->participantAdminStatusChangedCb;
diff --git a/src/c-wrapper/api/c-conference-info.cpp b/src/c-wrapper/api/c-conference-info.cpp
index 8150998bb4..1e3d73aa7d 100644
--- a/src/c-wrapper/api/c-conference-info.cpp
+++ b/src/c-wrapper/api/c-conference-info.cpp
@@ -147,10 +147,18 @@ void linphone_conference_info_set_subject(LinphoneConferenceInfo *conference_inf
 	ConferenceInfo::toCpp(conference_info)->setSubject(L_C_TO_STRING(subject));
 }
 
+void linphone_conference_info_set_ics_sequence(LinphoneConferenceInfo *conference_info, unsigned int sequence) {
+	ConferenceInfo::toCpp(conference_info)->setIcsSequence(sequence);
+}
+
 unsigned int linphone_conference_info_get_ics_sequence(const LinphoneConferenceInfo *conference_info) {
 	return ConferenceInfo::toCpp(conference_info)->getIcsSequence();
 }
 
+void linphone_conference_info_set_ics_uid(LinphoneConferenceInfo *conference_info, const char *uid) {
+	return ConferenceInfo::toCpp(conference_info)->setIcsUid(L_C_TO_STRING(uid));
+}
+
 const char *linphone_conference_info_get_ics_uid(const LinphoneConferenceInfo *conference_info) {
 	return L_STRING_TO_C(ConferenceInfo::toCpp(conference_info)->getIcsUid());
 }
@@ -182,6 +190,9 @@ char *linphone_conference_info_get_icalendar_string(const LinphoneConferenceInfo
 	return NULL;
 }
 
+void linphone_conference_info_set_state(LinphoneConferenceInfo *conference_info, LinphoneConferenceInfoState state) {
+	ConferenceInfo::toCpp(conference_info)->setState(static_cast<ConferenceInfo::State>(state));
+}
 LinphoneConferenceInfoState linphone_conference_info_get_state(const LinphoneConferenceInfo *conference_info) {
 	return (LinphoneConferenceInfoState)ConferenceInfo::toCpp(conference_info)->getState();
 }
diff --git a/src/c-wrapper/api/c-conference.cpp b/src/c-wrapper/api/c-conference.cpp
index 551cc2c0ae..be6455f5a1 100644
--- a/src/c-wrapper/api/c-conference.cpp
+++ b/src/c-wrapper/api/c-conference.cpp
@@ -102,6 +102,12 @@ void _linphone_conference_notify_participant_device_state_changed(LinphoneConfer
 	                                  state);
 }
 
+void _linphone_conference_notify_participant_role_changed(LinphoneConference *conference,
+                                                          const LinphoneParticipant *participant) {
+	LINPHONE_HYBRID_OBJECT_INVOKE_CBS(Conference, MediaConference::Conference::toCpp(conference),
+	                                  linphone_conference_cbs_get_participant_role_changed, participant);
+}
+
 void _linphone_conference_notify_participant_admin_status_changed(LinphoneConference *conference,
                                                                   const LinphoneParticipant *participant) {
 	LINPHONE_HYBRID_OBJECT_INVOKE_CBS(Conference, MediaConference::Conference::toCpp(conference),
diff --git a/src/c-wrapper/api/c-participant-info.cpp b/src/c-wrapper/api/c-participant-info.cpp
index 53a1435769..5bf965e5cd 100644
--- a/src/c-wrapper/api/c-participant-info.cpp
+++ b/src/c-wrapper/api/c-participant-info.cpp
@@ -28,7 +28,7 @@
 
 using namespace LinphonePrivate;
 
-LinphoneParticipantInfo *linphone_participant_info_new(LinphoneAddress *address) {
+LinphoneParticipantInfo *linphone_participant_info_new(const LinphoneAddress *address) {
 	return ParticipantInfo::createCObject(Address::toCpp(address)->getSharedFromThis());
 }
 
@@ -58,6 +58,14 @@ LinphoneParticipantRole linphone_participant_info_get_role(const LinphonePartici
 	return (LinphoneParticipantRole)ParticipantInfo::toCpp(participant_info)->getRole();
 }
 
+int linphone_participant_info_get_sequence_number(const LinphoneParticipantInfo *participant_info) {
+	return ParticipantInfo::toCpp(participant_info)->getSequenceNumber();
+}
+
+void linphone_participant_info_set_sequence_number(LinphoneParticipantInfo *participant_info, int sequence) {
+	ParticipantInfo::toCpp(participant_info)->setSequenceNumber(sequence);
+}
+
 void linphone_participant_info_add_parameter(LinphoneParticipantInfo *participant_info,
                                              const char *name,
                                              const char *value) {
diff --git a/src/call/call-log.cpp b/src/call/call-log.cpp
index ec5964a2d1..6762ce1ca6 100644
--- a/src/call/call-log.cpp
+++ b/src/call/call-log.cpp
@@ -208,9 +208,10 @@ void CallLog::setConferenceInfo(std::shared_ptr<ConferenceInfo> conferenceInfo)
 	mConferenceInfo = conferenceInfo;
 }
 
-std::shared_ptr<ConferenceInfo> CallLog::getConferenceInfo() {
-	if (mConferenceInfo != nullptr) return mConferenceInfo;
-
+std::shared_ptr<ConferenceInfo> &CallLog::getConferenceInfo() {
+	// The conference info stored in the database is always up to date, therefore try to update the cache all the time
+	// if there id is valid Nonetheless, the cache variable is required if the core disables the storage of information
+	// in the database.
 	if (mConferenceInfoId != -1) {
 		setConferenceInfo(L_GET_PRIVATE(getCore())->mainDb->getConferenceInfo(mConferenceInfoId));
 	}
diff --git a/src/call/call-log.h b/src/call/call-log.h
index 29eac9fa1a..147811271f 100644
--- a/src/call/call-log.h
+++ b/src/call/call-log.h
@@ -93,7 +93,7 @@ public:
 	void setConferenceInfoId(long long conferenceInfoId);
 
 	void setConferenceInfo(std::shared_ptr<ConferenceInfo> conferenceInfo);
-	std::shared_ptr<ConferenceInfo> getConferenceInfo();
+	std::shared_ptr<ConferenceInfo> &getConferenceInfo();
 
 	std::string toString() const override;
 
diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp
index 528c051a36..a6d0eb3b11 100644
--- a/src/chat/chat-message/chat-message.cpp
+++ b/src/chat/chat-message/chat-message.cpp
@@ -152,7 +152,8 @@ void ChatMessagePrivate::setParticipantState(const std::shared_ptr<Address> &par
 	LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q);
 	LinphoneChatRoom *cr = L_GET_C_BACK_PTR(chatRoom);
 	auto me = chatRoom->getMe();
-	auto participant = participantAddress == me->getAddress() ? me : chatRoom->findParticipant(participantAddress);
+	auto participant =
+	    participantAddress->weakEqual(*me->getAddress()) ? me : chatRoom->findParticipant(participantAddress);
 	ParticipantImdnState imdnState(participant, newState, stateChangeTime);
 
 	// Legacy callbacks, deprecated !
diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp
index 955cb19ad1..fd566c4b63 100644
--- a/src/chat/chat-room/chat-room.cpp
+++ b/src/chat/chat-room/chat-room.cpp
@@ -29,6 +29,7 @@
 #include "chat/chat-message/is-composing-message.h"
 #include "chat/chat-message/notification-message-p.h"
 #include "chat/chat-room/chat-room-p.h"
+#include "conference/conference.h"
 #include "content/content-manager.h"
 #include "core/core-p.h"
 #include "linphone/utils/algorithm.h"
diff --git a/src/chat/chat-room/server-group-chat-room.cpp b/src/chat/chat-room/server-group-chat-room.cpp
index 38cd2f93fb..2cb00c390c 100644
--- a/src/chat/chat-room/server-group-chat-room.cpp
+++ b/src/chat/chat-room/server-group-chat-room.cpp
@@ -1047,7 +1047,7 @@ shared_ptr<CallSession> ServerGroupChatRoomPrivate::makeSession(const std::share
 			csp.addCustomHeader("One-To-One-Chat-Room", "true");
 		if (capabilities & ServerGroupChatRoom::Capabilities::Encrypted)
 			csp.addCustomHeader("End-To-End-Encrypted", "true");
-		if (capabilities & ClientGroupChatRoom::Capabilities::Ephemeral) {
+		if (capabilities & ServerGroupChatRoom::Capabilities::Ephemeral) {
 			csp.addCustomHeader("Ephemerable", "true");
 			csp.addCustomHeader("Ephemeral-Life-Time", to_string(params->getEphemeralLifetime()));
 		}
diff --git a/src/chat/encryption/encryption-engine.h b/src/chat/encryption/encryption-engine.h
index c2cb005e61..da7d63a3d2 100644
--- a/src/chat/encryption/encryption-engine.h
+++ b/src/chat/encryption/encryption-engine.h
@@ -25,7 +25,7 @@
 
 #include <memory>
 
-#include "chat/chat-room/client-group-chat-room.h"
+#include "chat/chat-room/chat-room.h"
 #include "chat/modifier/chat-message-modifier.h"
 #include "core/core-accessor.h"
 #include "linphone/lpconfig.h"
diff --git a/src/conference/conference-info.cpp b/src/conference/conference-info.cpp
index 4bbceb4fad..69b4f66b89 100644
--- a/src/conference/conference-info.cpp
+++ b/src/conference/conference-info.cpp
@@ -111,8 +111,21 @@ void ConferenceInfo::addParticipants(const ConferenceInfo::participant_list_t &p
 
 void ConferenceInfo::addParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo) {
 	const auto &address = participantInfo->getAddress();
-	if (hasParticipant(address)) {
-		mParticipants.push_back(participantInfo->clone()->toSharedPtr());
+	if (!hasParticipant(address)) {
+		std::shared_ptr<ParticipantInfo> newInfo = nullptr;
+		// Check whetner the participant to be added is the organizer
+		if (mOrganizer && (participantInfo->getAddress()->weakEqual(*mOrganizer->getAddress()))) {
+			// Update the organizer role and parameters
+			newInfo = mOrganizer;
+			newInfo->setRole(participantInfo->getRole());
+			newInfo->addParameters(participantInfo->getAllParameters());
+		} else {
+			newInfo = participantInfo->clone()->toSharedPtr();
+		}
+		mParticipants.push_back(newInfo);
+		lInfo() << "Participant with address " << *address << " has been added to conference info " << this
+		        << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>"))
+		        << ") with role " << newInfo->getRole();
 	} else {
 		lInfo() << "Participant with address " << *address << " is already in the list of conference info " << this
 		        << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")";
@@ -134,13 +147,25 @@ void ConferenceInfo::removeParticipant(const std::shared_ptr<const Address> &par
 		lInfo() << "Unable to remove participant with address " << *participant << " in conference info " << this
 		        << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")";
 	} else {
+		lInfo() << "Participant with address " << *participant << " has been removed from conference info " << this
+		        << " (address " << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")";
 		mParticipants.erase(it);
 	}
 }
 
 void ConferenceInfo::updateParticipant(const std::shared_ptr<const ParticipantInfo> &participantInfo) {
-	removeParticipant(participantInfo);
-	addParticipant(participantInfo);
+	const auto &address = participantInfo->getAddress();
+	if (hasParticipant(address)) {
+		lInfo() << "Updating participant with address " << *address << " in conference info " << this << " (address "
+		        << (getUri() ? getUri()->toString() : std::string("<unknown address>")) << ")";
+		removeParticipant(participantInfo);
+		addParticipant(participantInfo);
+	} else {
+		lError() << "Unable to update informations of participant with address " << *participantInfo->getAddress()
+		         << " in conference info " << this << " (address "
+		         << (getUri() ? getUri()->toString() : std::string("<unknown address>"))
+		         << ") because he/she has not been found in the list of participants";
+	}
 }
 
 ConferenceInfo::participant_list_t::const_iterator
@@ -150,7 +175,7 @@ ConferenceInfo::findParticipantIt(const std::shared_ptr<const Address> &address)
 }
 
 bool ConferenceInfo::hasParticipant(const std::shared_ptr<const Address> &address) const {
-	return (findParticipantIt(address) == mParticipants.end());
+	return (findParticipantIt(address) != mParticipants.end());
 }
 
 const std::shared_ptr<ParticipantInfo>
diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h
index e2c28568e7..cf45b8dd52 100644
--- a/src/conference/conference-interface.h
+++ b/src/conference/conference-interface.h
@@ -349,6 +349,15 @@ public:
 	virtual void
 	    onEphemeralLifetimeChanged(BCTBX_UNUSED(const std::shared_ptr<ConferenceEphemeralMessageEvent> &event)){};
 
+	/*
+	 * This fonction is called each time a participant changes its role in the conference after full state notification.
+	 * @param[in] event informations related to the participant new role. @notnil
+	 * @param[in] participant participant whose role changed. @notnil
+	 */
+	virtual void onParticipantSetRole(BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantEvent> &event),
+	                                  BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
+	}
+
 	/*
 	 * This fonction is called each time a new admin is set by the focus after full state notification.
 	 * @param[in] event informations related to the new admin participant. @notnil
diff --git a/src/conference/conference-scheduler.cpp b/src/conference/conference-scheduler.cpp
index 387a356215..aa44a4a8f8 100644
--- a/src/conference/conference-scheduler.cpp
+++ b/src/conference/conference-scheduler.cpp
@@ -23,7 +23,9 @@
 #include "account/account.h"
 #include "c-wrapper/c-wrapper.h"
 #include "chat/chat-message/chat-message-p.h"
+#include "conference/conference-params.h"
 #include "conference/conference-scheduler.h"
+#include "conference/conference.h"
 #include "conference/params/call-session-params-p.h"
 #include "conference/participant-info.h"
 #include "conference/session/media-session.h"
@@ -474,11 +476,12 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 	const bool participantFound = (std::find_if(participants.cbegin(), participants.cend(), [&sender](const auto &p) {
 		                               return (sender->weakEqual(*p->getAddress()));
 	                               }) != participants.cend());
+	const auto &conferenceAddress = mConferenceInfo->getUri();
 	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
-		           << ") of conference " << *mConferenceInfo->getUri();
+		           << ") of conference " << *conferenceAddress;
 		return;
 	}
 
@@ -493,6 +496,14 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 		return;
 	}
 
+	std::shared_ptr<ConferenceInfo> dbConferenceInfo = nullptr;
+#ifdef HAVE_DB_STORAGE
+	auto &mainDb = getCore()->getPrivate()->mainDb;
+	if (mainDb && conferenceAddress) {
+		dbConferenceInfo = getCore()->getPrivate()->mainDb->getConferenceInfoFromURI(conferenceAddress);
+	}
+#endif // HAVE_DB_STORAGE
+
 	std::list<std::shared_ptr<Address>> invitees;
 	for (const auto &participantInfo : participants) {
 		invitees.push_back(participantInfo->getAddress());
@@ -521,6 +532,19 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 		const auto &participantInfo = mConferenceInfo->findParticipant(participant);
 		if (participantInfo) {
 			auto newParticipantInfo = participantInfo->clone()->toSharedPtr();
+			if (newParticipantInfo->getRole() == Participant::Role::Unknown) {
+				// Search if the role of the participant info stored in the database is different.
+				// We hit this case, if a client creates an inpromptu conference on a server and sends the ICS
+				// invitation as well. If the network connection is fast enough, it may happen that that the client
+				// already received the NOTIFY full state, therefore the server already took the decision on the
+				// participant role In such a scenario, the participant information stored in the conference scheduler
+				// should stick with it
+				const auto &dbParticipantInfo =
+				    (dbConferenceInfo) ? dbConferenceInfo->findParticipant(newParticipantInfo->getAddress()) : nullptr;
+				if (dbParticipantInfo) {
+					newParticipantInfo->setRole(dbParticipantInfo->getRole());
+				}
+			}
 			const auto &sequence = newParticipantInfo->getSequenceNumber();
 			const auto newSequence = (sequence < 0) ? 0 : sequence + 1;
 			newParticipantInfo->setSequenceNumber(newSequence);
@@ -530,11 +554,14 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 
 	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);
+		auto organizerAmongParticipants = (mConferenceInfo->findParticipant(organizerInfo->getAddress()) != nullptr);
+		if (!organizerAmongParticipants) {
+			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)) {
@@ -567,8 +594,7 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 			remoteAddress = participant;
 		}
 		shared_ptr<AbstractChatRoom> chatRoom =
-			getCore()->getPrivate()->searchChatRoom(chatRoomParams, sender, remoteAddress, participantList);
-
+		    getCore()->getPrivate()->searchChatRoom(chatRoomParams, sender, remoteAddress, participantList);
 
 		if (!chatRoom) {
 			lInfo() << "[Conference Scheduler] [" << this << "] Existing chat room between [" << *sender << "] and ["
diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp
index 961fcf8270..ddaa61cad5 100644
--- a/src/conference/conference.cpp
+++ b/src/conference/conference.cpp
@@ -94,7 +94,7 @@ bool Conference::addParticipant(BCTBX_UNUSED(std::shared_ptr<Call> call)) {
 bool Conference::addParticipant(const std::shared_ptr<Address> &participantAddress) {
 	shared_ptr<Participant> participant = findParticipant(participantAddress);
 	if (participant) {
-		lWarning() << "Not adding participant '" << participantAddress->toString()
+		lWarning() << "Not adding participant '" << *participantAddress
 		           << "' because it is already a participant of the Conference";
 		return false;
 	}
@@ -523,6 +523,34 @@ shared_ptr<ConferenceParticipantEvent> Conference::notifyParticipantRemoved(
 	return event;
 }
 
+shared_ptr<ConferenceParticipantEvent>
+Conference::notifyParticipantSetRole(time_t creationTime,
+                                     const bool isFullState,
+                                     const std::shared_ptr<Participant> &participant,
+                                     Participant::Role role) {
+	EventLog::Type eventType = EventLog::Type::None;
+	switch (role) {
+		case Participant::Role::Speaker:
+			eventType = EventLog::Type::ConferenceParticipantRoleSpeaker;
+			break;
+		case Participant::Role::Listener:
+			eventType = EventLog::Type::ConferenceParticipantRoleListener;
+			break;
+		case Participant::Role::Unknown:
+			eventType = EventLog::Type::ConferenceParticipantRoleUnknown;
+			break;
+	}
+	shared_ptr<ConferenceParticipantEvent> event =
+	    make_shared<ConferenceParticipantEvent>(eventType, creationTime, conferenceId, participant->getAddress());
+	event->setFullState(isFullState);
+	event->setNotifyId(lastNotify);
+
+	for (const auto &l : confListeners) {
+		l->onParticipantSetRole(event, participant);
+	}
+	return event;
+}
+
 shared_ptr<ConferenceParticipantEvent> Conference::notifyParticipantSetAdmin(
     time_t creationTime, const bool isFullState, const std::shared_ptr<Participant> &participant, bool isAdmin) {
 	shared_ptr<ConferenceParticipantEvent> event = make_shared<ConferenceParticipantEvent>(
@@ -718,6 +746,29 @@ std::shared_ptr<ConferenceInfo> Conference::createConferenceInfo() const {
 	return nullptr;
 }
 
+const std::shared_ptr<ConferenceInfo> Conference::getUpdatedConferenceInfo() const {
+	auto conferenceInfo = createOrGetConferenceInfo();
+
+	// Update me only if he/she is already in the list of participants info
+	const auto &meAddress = getMe()->getAddress();
+	const auto &currentParticipants = conferenceInfo->getParticipants();
+	const auto meInfoIt =
+	    std::find_if(currentParticipants.begin(), currentParticipants.end(),
+	                 [&meAddress](const auto &p) { return (meAddress->weakEqual(*p->getAddress())); });
+	if (meInfoIt != currentParticipants.end()) {
+		updateParticipantInfoInConferenceInfo(conferenceInfo, getMe());
+	}
+
+	for (const auto &participant : getParticipants()) {
+		updateParticipantInfoInConferenceInfo(conferenceInfo, participant);
+	}
+
+	conferenceInfo->setSecurityLevel(confParams->getSecurityLevel());
+	conferenceInfo->setSubject(confParams->getSubject());
+
+	return conferenceInfo;
+}
+
 std::shared_ptr<ConferenceInfo> Conference::createConferenceInfoWithCustomParticipantList(
     const std::shared_ptr<Address> &organizer, const ConferenceInfo::participant_list_t invitedParticipants) const {
 	std::shared_ptr<ConferenceInfo> info = ConferenceInfo::create();
@@ -811,27 +862,34 @@ void Conference::updateSubjectInConferenceInfo(const std::string &subject) const
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
-void Conference::updateParticipantsInConferenceInfo(const std::shared_ptr<Address> &participantAddress) const {
+void Conference::updateParticipantRoleInConferenceInfo(const std::shared_ptr<Participant> &participant) const {
 #ifdef HAVE_DB_STORAGE
 	if ((getState() == ConferenceInterface::State::CreationPending) ||
 	    (getState() == ConferenceInterface::State::Created)) {
 		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 (participantAddress->weakEqual(*p->getAddress())); });
-			if (participantAddressIt == currentParticipants.end()) {
-				info->addParticipant(participantAddress);
+			const auto &address = participant->getAddress();
+			const auto &newRole = participant->getRole();
+			const auto &participantInfo = info->findParticipant(address);
+			if (participantInfo) {
+				auto newParticipantInfo = participantInfo->clone()->toSharedPtr();
+				newParticipantInfo->setRole(newRole);
+
+				info->updateParticipant(newParticipantInfo);
 
 				// Store into DB after the start incoming notification in order to have a valid conference address being
 				// the contact address of the call
 				auto &mainDb = getCore()->getPrivate()->mainDb;
 				if (mainDb) {
 					lInfo() << "Updating conference information of conference " << *getConferenceAddress()
-					        << " because participant " << *participantAddress << " has been added";
+					        << " because the role of participant " << *address << " changed to " << newRole;
 					mainDb->insertConferenceInfo(info);
 				}
+			} else {
+				lError() << "Unable to update role of participant " << *address << " to " << newRole
+				         << " because it cannot be found in the conference info linked to conference "
+				         << *getConferenceAddress();
 			}
 		}
 	}
@@ -841,4 +899,61 @@ void Conference::updateParticipantsInConferenceInfo(const std::shared_ptr<Addres
 #pragma GCC diagnostic pop
 #endif // _MSC_VER
 
+bool Conference::updateParticipantInfoInConferenceInfo(std::shared_ptr<ConferenceInfo> &info,
+                                                       const std::shared_ptr<Participant> &participant) const {
+	bool update = false;
+	const auto &participantAddress = participant->getAddress();
+	const auto &currentParticipants = info->getParticipants();
+	const auto participantInfoIt =
+	    std::find_if(currentParticipants.begin(), currentParticipants.end(), [&participantAddress](const auto &p) {
+		    return (participantAddress->weakEqual(*p->getAddress()));
+	    });
+
+	const auto &participantRole = participant->getRole();
+	if (participantInfoIt == currentParticipants.end()) {
+		auto participantInfo = ParticipantInfo::create(participantAddress);
+		participantInfo->setRole(participantRole);
+		info->addParticipant(participantInfo);
+		update = true;
+	} else {
+		auto participantInfo = (*participantInfoIt)->clone()->toSharedPtr();
+		if (participantInfo->getRole() != participantRole) {
+			participantInfo->setRole(participantRole);
+			info->updateParticipant(participantInfo);
+			update = true;
+		}
+	}
+	return update;
+}
+
+void Conference::updateParticipantInConferenceInfo(const std::shared_ptr<Participant> &participant) const {
+	const auto &participantAddress = participant->getAddress();
+	if (!participant) {
+		lError() << "Conference " << *getConferenceAddress()
+		         << " received a request to update the conference info to add participant with address "
+		         << *participantAddress << " but it looks like he/she is not part of this conference";
+		return;
+	}
+
+#ifdef HAVE_DB_STORAGE
+	if ((getState() == ConferenceInterface::State::CreationPending) ||
+	    (getState() == ConferenceInterface::State::Created)) {
+		auto info = createOrGetConferenceInfo();
+		if (info) {
+			bool update = updateParticipantInfoInConferenceInfo(info, participant);
+
+			// Store into DB after the start incoming notification in order to have a valid conference address being
+			// the contact address of the call
+			auto &mainDb = getCore()->getPrivate()->mainDb;
+			if (mainDb && update) {
+				lInfo() << "Updating conference information of conference " << *getConferenceAddress()
+				        << " because participant " << *participantAddress
+				        << " has been added or has modified its informations";
+				mainDb->insertConferenceInfo(info);
+			}
+		}
+	}
+#endif // HAVE_DB_STORAGE
+}
+
 LINPHONE_END_NAMESPACE
diff --git a/src/conference/conference.h b/src/conference/conference.h
index f595355e1a..f53956b69a 100644
--- a/src/conference/conference.h
+++ b/src/conference/conference.h
@@ -30,6 +30,7 @@
 #include "conference/conference-interface.h"
 #include "conference/conference-listener.h"
 #include "conference/conference-params.h"
+#include "conference/participant.h"
 #include "core/core-accessor.h"
 #include "linphone/core.h"
 #include "linphone/types.h"
@@ -143,6 +144,11 @@ public:
 	    time_t creationTime, const bool isFullState, const std::shared_ptr<Participant> &participant);
 	virtual std::shared_ptr<ConferenceParticipantEvent> notifyParticipantRemoved(
 	    time_t creationTime, const bool isFullState, const std::shared_ptr<Participant> &participant);
+	virtual std::shared_ptr<ConferenceParticipantEvent>
+	notifyParticipantSetRole(time_t creationTime,
+	                         const bool isFullState,
+	                         const std::shared_ptr<Participant> &participant,
+	                         Participant::Role role);
 	virtual std::shared_ptr<ConferenceParticipantEvent> notifyParticipantSetAdmin(
 	    time_t creationTime, const bool isFullState, const std::shared_ptr<Participant> &participant, bool isAdmin);
 	virtual std::shared_ptr<ConferenceSubjectEvent>
@@ -203,8 +209,11 @@ public:
 	void clearParticipants();
 
 	void updateSubjectInConferenceInfo(const std::string &subject) const;
-	void updateParticipantsInConferenceInfo(const std::shared_ptr<Address> &participantAddress) const;
+	void updateParticipantInConferenceInfo(const std::shared_ptr<Participant> &participant) const;
+	bool updateParticipantInfoInConferenceInfo(std::shared_ptr<ConferenceInfo> &info,
+	                                           const std::shared_ptr<Participant> &participant) const;
 	void updateSecurityLevelInConferenceInfo(const ConferenceParams::SecurityLevel &level) const;
+	void updateParticipantRoleInConferenceInfo(const std::shared_ptr<Participant> &participant) const;
 
 protected:
 	explicit Conference(const std::shared_ptr<Core> &core,
@@ -249,6 +258,7 @@ protected:
 	virtual std::shared_ptr<ConferenceInfo>
 	createConferenceInfoWithCustomParticipantList(const std::shared_ptr<Address> &organizer,
 	                                              const ConferenceInfo::participant_list_t invitedParticipants) const;
+	const std::shared_ptr<ConferenceInfo> getUpdatedConferenceInfo() 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 6b00ee27e5..5791ddf383 100644
--- a/src/conference/handlers/local-conference-event-handler.cpp
+++ b/src/conference/handlers/local-conference-event-handler.cpp
@@ -1128,7 +1128,7 @@ void LocalConferenceEventHandler::onParticipantAdded(const std::shared_ptr<Confe
 	// Do not send notify if conference pointer is null. It may mean that the confernece has been terminated
 	if (conf) {
 		notifyAllExcept(makeContent(createNotifyParticipantAdded(participant->getAddress())), participant);
-		conf->updateParticipantsInConferenceInfo(participant->getAddress());
+		conf->updateParticipantInConferenceInfo(participant);
 
 		if (conf) {
 			shared_ptr<Core> core = conf->getCore();
diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp
index 4d9c980f5b..a782dec7d7 100644
--- a/src/conference/handlers/remote-conference-event-handler.cpp
+++ b/src/conference/handlers/remote-conference-event-handler.cpp
@@ -80,6 +80,45 @@ bool RemoteConferenceEventHandler::getInitialSubscriptionUnderWayFlag() const {
 	return initialSubscriptionUnderWay;
 }
 
+void RemoteConferenceEventHandler::fillParticipantAttributes(
+    std::shared_ptr<Participant> &participant,
+    xsd::cxx::tree::optional<LinphonePrivate::Xsd::ConferenceInfo::UserRolesType> &roles,
+    StateType state,
+    bool isFullState,
+    bool notify) const {
+	if (roles) {
+		auto &entry = roles->getEntry();
+
+		time_t creationTime = time(nullptr);
+
+		// Admin
+		bool isAdmin = (find(entry, "admin") != entry.end() ? true : false);
+		if (participant->isAdmin() != isAdmin) {
+			participant->setAdmin(isAdmin);
+			if (!isFullState && notify) {
+				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);
+		Participant::Role role = Participant::Role::Unknown;
+		if (isListener) {
+			role = 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
+			role = Participant::Role::Speaker;
+		}
+		if (participant->getRole() != role) {
+			participant->setRole(role);
+			if (!isFullState && notify) {
+				conf->notifyParticipantSetRole(creationTime, isFullState, participant, role);
+			}
+		}
+	}
+}
+
 void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xmlBody) {
 	istringstream data(xmlBody);
 	unique_ptr<ConferenceType> confInfo;
@@ -101,7 +140,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 
 	if (!peerAddress || (*entityAddress != *peerAddress)) {
 		const std::string peerAddressString = peerAddress ? peerAddress->toString() : std::string("<unknown>");
-		lError() << "Unable to process received NOTIFY because the entity address " << entityAddress->toString()
+		lError() << "Unable to process received NOTIFY because the entity address " << *entityAddress
 		         << " doesn't match the peer address " << peerAddressString;
 		return;
 	}
@@ -274,9 +313,10 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 			    return (*address == *currentParticipant->getAddress());
 		    });
 
+		auto &roles = user.getRoles();
 		if (state == StateType::deleted) {
 			if (conf->isMe(address)) {
-				lInfo() << "Participant " << address->toString() << " requested to be deleted is me.";
+				lInfo() << "Participant " << *address << " requested to be deleted is me.";
 				continue;
 			} else if (participant) {
 				conf->participants.remove(participant);
@@ -288,17 +328,19 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 
 				continue;
 			} else {
-				lWarning() << "Participant " << address->toString() << " removed but not in the list of participants!";
+				lWarning() << "Participant " << *address << " removed but not in the list of participants!";
 			}
 		} else if (state == StateType::full) {
 			if (conf->isMe(address)) {
-				lInfo() << "Participant " << address->toString() << " requested to be added is me.";
+				lInfo() << "Participant " << *address << " requested to be added is me.";
+				fillParticipantAttributes(participant, roles, state, isFullState, false);
 			} else if (participant) {
 				lWarning() << "Participant " << *participant << " added but already in the list of participants!";
 			} else {
 				participant = Participant::create(conf, address);
+				fillParticipantAttributes(participant, roles, state, isFullState, false);
+
 				conf->participants.push_back(participant);
-				conf->updateParticipantsInConferenceInfo(address);
 				lInfo() << "Participant " << *participant << " is successfully added - conference "
 				        << conferenceAddressString << " has " << conf->getParticipantCount() << " participants";
 				if (!isFullState ||
@@ -315,37 +357,14 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 		}
 
 		if (!participant) {
-			lDebug() << "Participant " << address->toString()
+			lDebug() << "Participant " << *address
 			         << " is not in the list of participants however it is trying to change the list of devices or "
 			            "change role! Resubscribing to conference "
 			         << conferenceAddressString << " to clear things up.";
 			requestFullState();
 		} else {
 
-			auto &roles = user.getRoles();
-			if (roles) {
-				auto &entry = roles->getEntry();
-
-				// 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);
-				}
-			}
-
+			fillParticipantAttributes(participant, roles, state, isFullState, true);
 			for (const auto &endpoint : user.getEndpoint()) {
 				if (!endpoint.getEntity().present()) continue;
 
@@ -560,7 +579,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 					if (conf->isMe(address) && conf->getMainSession()) device->setSession(conf->getMainSession());
 
 					if (state == StateType::full) {
-						lInfo() << "Participant device " << gruu->toString() << " has been successfully added";
+						lInfo() << "Participant device " << *gruu << " has been successfully added";
 						bool sendNotify =
 						    (!oldParticipants.empty() && (pIt == oldParticipants.cend())) && !conf->isMe(address);
 						if (pIt != oldParticipants.cend()) {
@@ -575,7 +594,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 							conf->notifyParticipantDeviceAdded(creationTime, isFullState, participant, device);
 						}
 					} else {
-						lInfo() << "Participant device " << gruu->toString() << " has been successfully updated";
+						lInfo() << "Participant device " << *gruu << " has been successfully updated";
 					}
 				} else {
 					lDebug() << "Unable to update media direction of device " << *gruu
diff --git a/src/conference/handlers/remote-conference-event-handler.h b/src/conference/handlers/remote-conference-event-handler.h
index a10308733e..06442ef197 100644
--- a/src/conference/handlers/remote-conference-event-handler.h
+++ b/src/conference/handlers/remote-conference-event-handler.h
@@ -95,6 +95,11 @@ private:
 	void unsubscribePrivate();
 	void updateInitialSubcriptionUnderWay(std::shared_ptr<Event> notifyLev);
 	time_t dateTimeToTimeT(const Xsd::XmlSchema::DateTime &xsdTime) const;
+	void fillParticipantAttributes(std::shared_ptr<Participant> &participant,
+	                               xsd::cxx::tree::optional<LinphonePrivate::Xsd::ConferenceInfo::UserRolesType> &roles,
+	                               Xsd::ConferenceInfo::StateType state,
+	                               bool isFullState,
+	                               bool notify) const;
 	L_DISABLE_COPY(RemoteConferenceEventHandler);
 };
 
diff --git a/src/conference/notify-conference-listener.cpp b/src/conference/notify-conference-listener.cpp
index 00eb03061a..9aea415252 100644
--- a/src/conference/notify-conference-listener.cpp
+++ b/src/conference/notify-conference-listener.cpp
@@ -43,6 +43,12 @@ void NotifyConferenceListener::onParticipantRemoved(
 	_linphone_conference_notify_participant_removed(conf->toC(), participant->toC());
 }
 
+void NotifyConferenceListener::onParticipantSetRole(
+    BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantEvent> &event),
+    const std::shared_ptr<Participant> &participant) {
+	_linphone_conference_notify_participant_role_changed(conf->toC(), participant->toC());
+}
+
 void NotifyConferenceListener::onParticipantSetAdmin(
     BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantEvent> &event),
     const std::shared_ptr<Participant> &participant) {
diff --git a/src/conference/notify-conference-listener.h b/src/conference/notify-conference-listener.h
index 71b904d421..e2d38abf53 100644
--- a/src/conference/notify-conference-listener.h
+++ b/src/conference/notify-conference-listener.h
@@ -54,6 +54,14 @@ public:
 	virtual void onParticipantRemoved(const std::shared_ptr<ConferenceParticipantEvent> &event,
 	                                  const std::shared_ptr<Participant> &participant) override;
 
+	/*
+	 * This fonction is called each time a participant changes its role in the conference after full state notification.
+	 * @param[in] event informations related to the participant new role. @notnil
+	 * @param[in] participant participant whose role changed. @notnil
+	 */
+	virtual void onParticipantSetRole(const std::shared_ptr<ConferenceParticipantEvent> &event,
+	                                  const std::shared_ptr<Participant> &participant) override;
+
 	/*
 	 * This fonction is called each time a new admin is set by the focus after full state notification.
 	 * @param[in] event informations related to the new admin participant. @notnil
diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp
index 7d28895ef0..5185ae9bbd 100644
--- a/src/conference/participant-device.cpp
+++ b/src/conference/participant-device.cpp
@@ -20,6 +20,7 @@
 
 #include "participant-device.h"
 #include "chat/encryption/encryption-engine.h"
+#include "conference/conference.h"
 #include "conference/params/media-session-params-p.h"
 #include "conference/params/media-session-params.h"
 #include "conference/session/call-session-p.h"
diff --git a/src/conference/participant-info.cpp b/src/conference/participant-info.cpp
index 09ec6728e3..8bb692aa85 100644
--- a/src/conference/participant-info.cpp
+++ b/src/conference/participant-info.cpp
@@ -28,7 +28,7 @@ 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) {
+ParticipantInfo::ParticipantInfo(const std::shared_ptr<const Address> &address) {
 	mAddress = Address::create(address->getUri());
 }
 
@@ -111,6 +111,10 @@ void ParticipantInfo::removeParameter(const std::string &name) {
 	}
 }
 
+ParticipantInfo::participant_params_t ParticipantInfo::getParameters() const {
+	return mParameters;
+}
+
 ParticipantInfo::participant_params_t ParticipantInfo::getAllParameters() const {
 	auto params = mParameters;
 	if (mSequence >= 0) {
diff --git a/src/conference/participant-info.h b/src/conference/participant-info.h
index df9be9bcaf..aa184628a9 100644
--- a/src/conference/participant-info.h
+++ b/src/conference/participant-info.h
@@ -38,7 +38,7 @@ public:
 	static const std::string sequenceParameter;
 	static const std::string roleParameter;
 
-	ParticipantInfo(const std::shared_ptr<Address> &address);
+	ParticipantInfo(const std::shared_ptr<const Address> &address);
 	virtual ~ParticipantInfo();
 
 	ParticipantInfo(const ParticipantInfo &other);
@@ -60,6 +60,8 @@ public:
 	bool hasParameter(const std::string &name) const;
 	void removeParameter(const std::string &name);
 
+	// getParameters() return only parameters that do not have a dedicated member in the class, i.e. mParameters
+	ParticipantInfo::participant_params_t getParameters() const;
 	ParticipantInfo::participant_params_t getAllParameters() const;
 
 	static const std::string memberParametersToString(const participant_params_t &params);
diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp
index cbcc72344f..a0a280bf85 100644
--- a/src/conference/participant.cpp
+++ b/src/conference/participant.cpp
@@ -22,6 +22,7 @@
 
 #include "participant.h"
 
+#include "conference/conference.h"
 #include "core/core.h"
 #include "params/media-session-params.h"
 #include "participant.h"
@@ -275,6 +276,18 @@ Participant::getSecurityLevelExcept(const std::shared_ptr<ParticipantDevice> &ig
 
 // -----------------------------------------------------------------------------
 
+std::shared_ptr<Core> Participant::getCore() const {
+	return mConference ? mConference->getCore() : nullptr;
+}
+
+Conference *Participant::getConference() const {
+	return mConference;
+}
+
+void Participant::setConference(Conference *conference) {
+	mConference = conference;
+}
+
 bool Participant::isAdmin() const {
 	return isThisAdmin;
 }
diff --git a/src/conference/participant.h b/src/conference/participant.h
index 8c76500296..dcefcd4409 100644
--- a/src/conference/participant.h
+++ b/src/conference/participant.h
@@ -149,15 +149,9 @@ public:
 	};
 
 protected:
-	std::shared_ptr<Core> getCore() const {
-		return mConference ? mConference->getCore() : nullptr;
-	}
-	Conference *getConference() const {
-		return mConference;
-	}
-	void setConference(Conference *conference) {
-		mConference = conference;
-	}
+	std::shared_ptr<Core> getCore() const;
+	Conference *getConference() const;
+	void setConference(Conference *conference);
 
 	std::shared_ptr<CallSession> createSession(const Conference &conference,
 	                                           const CallSessionParams *params,
diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp
index 6e40226c88..70e83e689b 100644
--- a/src/conference/session/call-session.cpp
+++ b/src/conference/session/call-session.cpp
@@ -20,13 +20,12 @@
 
 #include <bctoolbox/defs.h>
 
-#include "linphone/api/c-content.h"
-#include "linphone/core.h"
-
 #include "account/account.h"
 #include "address/address.h"
 #include "c-wrapper/c-wrapper.h"
+#include "call/call-log.h"
 #include "call/call.h"
+#include "conference.h"
 #include "conference/conference-scheduler.h"
 #include "conference/params/call-session-params-p.h"
 #include "conference/participant.h"
@@ -34,9 +33,9 @@
 #include "conference/session/call-session.h"
 #include "core/core-p.h"
 #include "factory/factory.h"
+#include "linphone/api/c-content.h"
+#include "linphone/core.h"
 #include "logger/logger.h"
-
-#include "conference.h"
 #include "private.h"
 
 using namespace std;
diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h
index 5b890fbab9..ebb7a65e53 100644
--- a/src/conference/session/call-session.h
+++ b/src/conference/session/call-session.h
@@ -23,8 +23,8 @@
 
 #include "address/address.h"
 #include "conference/conference-id.h"
-#include "conference/conference.h"
 #include "conference/params/call-session-params.h"
+#include "core/core-accessor.h"
 #include "core/core-listener.h"
 #include "linphone/misc.h"
 #include "object/object.h"
@@ -34,13 +34,18 @@
 
 LINPHONE_BEGIN_NAMESPACE
 
+class CallLog;
 class CallSessionPrivate;
+class CallSessionListener;
 class Content;
 class Core;
+class Conference;
 
 namespace MediaConference {
 class Conference;
-}
+class RemoteConference;
+class LocalConference;
+} // namespace MediaConference
 
 class LINPHONE_PUBLIC CallSession : public Object, public CoreAccessor {
 	friend class Call;
diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp
index 4b3d491cb1..d903def193 100644
--- a/src/db/main-db.cpp
+++ b/src/db/main-db.cpp
@@ -1033,6 +1033,9 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceInfoEvent(const ConferenceId
 
 		case EventLog::Type::ConferenceParticipantAdded:
 		case EventLog::Type::ConferenceParticipantRemoved:
+		case EventLog::Type::ConferenceParticipantRoleUnknown:
+		case EventLog::Type::ConferenceParticipantRoleSpeaker:
+		case EventLog::Type::ConferenceParticipantRoleListener:
 		case EventLog::Type::ConferenceParticipantSetAdmin:
 		case EventLog::Type::ConferenceParticipantUnsetAdmin:
 			eventLog = selectConferenceParticipantEvent(conferenceId, type, row);
@@ -1923,28 +1926,6 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row &
 	conferenceInfo->setSecurityLevel(
 	    static_cast<ConferenceParams::SecurityLevel>(dbSession.getUnsignedInt(row, 10, 0)));
 
-	static const string participantQuery =
-	    "SELECT sip_address.value, conference_info_participant.deleted, conference_info_participant.params"
-	    " FROM sip_address, conference_info, conference_info_participant"
-	    " WHERE conference_info.id = :conferenceInfoId"
-	    " AND sip_address.id = conference_info_participant.participant_sip_address_id"
-	    " AND conference_info_participant.conference_info_id = conference_info.id";
-
-	soci::session *session = dbSession.getBackendSession();
-	soci::rowset<soci::row> participantRows = (session->prepare << participantQuery, soci::use(dbConferenceInfoId));
-	for (const auto &participantRow : participantRows) {
-		int deleted = participantRow.get<int>(1);
-		if (deleted == 0) {
-			std::shared_ptr<Address> participantAddress = Address::create(participantRow.get<string>(0));
-			const string participantParamsStr = participantRow.get<string>(2);
-			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.
@@ -1957,6 +1938,7 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row &
 	                                     " AND sip_address.id = conference_info_organizer.organizer_sip_address_id"
 	                                     " AND conference_info_organizer.conference_info_id = conference_info.id";
 
+	soci::session *session = dbSession.getBackendSession();
 	soci::rowset<soci::row> organizerRows = (session->prepare << organizerQuery, soci::use(dbConferenceInfoId));
 	for (const auto &organizerRow : organizerRows) {
 		organizerAddress = Address::create(organizerRow.get<string>(0));
@@ -1967,6 +1949,27 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row &
 	organizerInfo->setParameters(organizerParams);
 	conferenceInfo->setOrganizer(organizerInfo);
 
+	static const string participantQuery =
+	    "SELECT sip_address.value, conference_info_participant.deleted, conference_info_participant.params"
+	    " FROM sip_address, conference_info, conference_info_participant"
+	    " WHERE conference_info.id = :conferenceInfoId"
+	    " AND sip_address.id = conference_info_participant.participant_sip_address_id"
+	    " AND conference_info_participant.conference_info_id = conference_info.id";
+
+	soci::rowset<soci::row> participantRows = (session->prepare << participantQuery, soci::use(dbConferenceInfoId));
+	for (const auto &participantRow : participantRows) {
+		int deleted = participantRow.get<int>(1);
+		if (deleted == 0) {
+			std::shared_ptr<Address> participantAddress = Address::create(participantRow.get<string>(0));
+			const string participantParamsStr = participantRow.get<string>(2);
+			ParticipantInfo::participant_params_t participantParams =
+			    ParticipantInfo::stringToMemberParameters(participantParamsStr);
+			auto participantInfo = ParticipantInfo::create(participantAddress);
+			participantInfo->setParameters(participantParams);
+			conferenceInfo->addParticipant(participantInfo);
+		}
+	}
+
 	cache(conferenceInfo, dbConferenceInfoId);
 
 	return conferenceInfo;
@@ -3497,6 +3500,9 @@ bool MainDb::addEvent(const shared_ptr<EventLog> &eventLog) {
 
 			case EventLog::Type::ConferenceParticipantAdded:
 			case EventLog::Type::ConferenceParticipantRemoved:
+			case EventLog::Type::ConferenceParticipantRoleUnknown:
+			case EventLog::Type::ConferenceParticipantRoleSpeaker:
+			case EventLog::Type::ConferenceParticipantRoleListener:
 			case EventLog::Type::ConferenceParticipantSetAdmin:
 			case EventLog::Type::ConferenceParticipantUnsetAdmin:
 				eventId = d->insertConferenceParticipantEvent(eventLog);
@@ -3574,6 +3580,9 @@ bool MainDb::updateEvent(const shared_ptr<EventLog> &eventLog) {
 			case EventLog::Type::ConferenceCallEnded:
 			case EventLog::Type::ConferenceParticipantAdded:
 			case EventLog::Type::ConferenceParticipantRemoved:
+			case EventLog::Type::ConferenceParticipantRoleUnknown:
+			case EventLog::Type::ConferenceParticipantRoleSpeaker:
+			case EventLog::Type::ConferenceParticipantRoleListener:
 			case EventLog::Type::ConferenceParticipantSetAdmin:
 			case EventLog::Type::ConferenceParticipantUnsetAdmin:
 			case EventLog::Type::ConferenceParticipantDeviceAdded:
@@ -5318,18 +5327,19 @@ std::shared_ptr<ConferenceInfo> MainDb::getConferenceInfoFromURI(const std::shar
 	return nullptr;
 }
 
-void MainDb::insertConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo) {
+long long MainDb::insertConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo) {
 #ifdef HAVE_DB_STORAGE
 	if (isInitialized()) {
 		auto dbConfInfo = getConferenceInfoFromURI(conferenceInfo->getUri());
-		L_DB_TRANSACTION {
+		return L_DB_TRANSACTION {
 			L_D();
-
-			d->insertConferenceInfo(conferenceInfo, dbConfInfo);
+			auto id = d->insertConferenceInfo(conferenceInfo, dbConfInfo);
 			tr.commit();
+			return id;
 		};
 	}
 #endif
+	return -1;
 }
 
 void MainDb::deleteConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo) {
diff --git a/src/db/main-db.h b/src/db/main-db.h
index e3f3de999f..46f6cdf66a 100644
--- a/src/db/main-db.h
+++ b/src/db/main-db.h
@@ -211,7 +211,7 @@ public:
 	std::list<std::shared_ptr<ConferenceInfo>> getConferenceInfos(time_t afterThisTime = -1) const;
 	std::shared_ptr<ConferenceInfo> getConferenceInfo(long long conferenceInfoId) const;
 	std::shared_ptr<ConferenceInfo> getConferenceInfoFromURI(const std::shared_ptr<Address> &uri) const;
-	void insertConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo);
+	long long insertConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo);
 	void deleteConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo);
 
 	// ---------------------------------------------------------------------------
diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp
index 50eca2da86..a93a34a1cb 100644
--- a/src/event-log/event-log.cpp
+++ b/src/event-log/event-log.cpp
@@ -94,6 +94,15 @@ std::ostream &operator<<(std::ostream &lhs, EventLog::Type e) {
 		case EventLog::Type::ConferenceParticipantRemoved:
 			lhs << "ConferenceParticipantRemoved";
 			break;
+		case EventLog::Type::ConferenceParticipantRoleUnknown:
+			lhs << "ConferenceParticipantRoleUnknown";
+			break;
+		case EventLog::Type::ConferenceParticipantRoleSpeaker:
+			lhs << "ConferenceParticipantRoleSpeaker";
+			break;
+		case EventLog::Type::ConferenceParticipantRoleListener:
+			lhs << "ConferenceParticipantRoleListener";
+			break;
 		case EventLog::Type::ConferenceParticipantSetAdmin:
 			lhs << "ConferenceParticipantSetAdmin";
 			break;
diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h
index 1fcb199f3f..e43d4193ab 100644
--- a/src/event-log/event-log.h
+++ b/src/event-log/event-log.h
@@ -49,6 +49,9 @@ public:
 		ConferenceChatMessage = LinphoneEventLogTypeConferenceChatMessage,
 		ConferenceParticipantAdded = LinphoneEventLogTypeConferenceParticipantAdded,
 		ConferenceParticipantRemoved = LinphoneEventLogTypeConferenceParticipantRemoved,
+		ConferenceParticipantRoleUnknown = LinphoneEventLogTypeConferenceParticipantRoleUnknown,
+		ConferenceParticipantRoleSpeaker = LinphoneEventLogTypeConferenceParticipantRoleSpeaker,
+		ConferenceParticipantRoleListener = LinphoneEventLogTypeConferenceParticipantRoleListener,
 		ConferenceParticipantSetAdmin = LinphoneEventLogTypeConferenceParticipantSetAdmin,
 		ConferenceParticipantUnsetAdmin = LinphoneEventLogTypeConferenceParticipantUnsetAdmin,
 		ConferenceParticipantDeviceAdded = LinphoneEventLogTypeConferenceParticipantDeviceAdded,
diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h
index 5a7d9aab9f..c508e8b8a0 100644
--- a/tester/liblinphone_tester.h
+++ b/tester/liblinphone_tester.h
@@ -460,6 +460,7 @@ typedef struct _stats {
 	int tmmbr_received_from_cb;
 
 	int number_of_participants_added;
+	int number_of_participant_role_changed;
 	int number_of_participant_admin_statuses_changed;
 	int number_of_participants_removed;
 	int number_of_subject_changed;
diff --git a/tester/local_conference_edition_tester.cpp b/tester/local_conference_edition_tester.cpp
index 162802832c..64514173ce 100644
--- a/tester/local_conference_edition_tester.cpp
+++ b/tester/local_conference_edition_tester.cpp
@@ -96,10 +96,12 @@ 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";
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : invitedParticipants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -128,17 +130,19 @@ static void edit_simple_conference_base(bool_t from_organizer,
 
 			participants.push_back(lise.getCMgr());
 
+			LinphoneParticipantRole role = LinphoneParticipantRoleListener;
 			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);
+			LinphoneParticipantInfo *lise_participant_info =
+			    add_participant_info_to_list(&participants_info, lise.getCMgr()->identity, role, -1);
 			linphone_conference_info_add_participant_2(conf_info, lise_participant_info);
-			linphone_participant_info_unref(lise_participant_info);
+			participantList.insert(std::make_pair(lise.getCMgr(), lise_participant_info));
 
 			if (role_changed) {
-				LinphoneParticipantRole current_pauline_role = participantList[pauline.getCMgr()];
+				LinphoneParticipantRole current_pauline_role =
+				    linphone_participant_info_get_role(participantList[pauline.getCMgr()]);
 				LinphoneParticipantRole new_pauline_role = (current_pauline_role == LinphoneParticipantRoleListener)
 				                                               ? LinphoneParticipantRoleSpeaker
 				                                               : LinphoneParticipantRoleListener;
@@ -155,9 +159,19 @@ static void edit_simple_conference_base(bool_t from_organizer,
 					    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_set_role(participantList[pauline.getCMgr()], new_pauline_role);
+					const bctbx_list_t *participant_info_it = bctbx_list_find_custom(
+					    participants_info, (int (*)(const void *, const void *))find_matching_participant_info,
+					    pauline_participant_info);
+					BC_ASSERT_PTR_NOT_NULL(participant_info_it);
+					if (participant_info_it) {
+						LinphoneParticipantInfo *participant_info_found =
+						    (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it);
+						linphone_participant_info_set_role(participant_info_found, new_pauline_role);
+					}
 					linphone_participant_info_unref(pauline_participant_info);
 				}
-				participantList[pauline.getCMgr()] = new_pauline_role;
 			}
 
 			const auto ics_participant_number = 3;
@@ -254,49 +268,6 @@ static void edit_simple_conference_base(bool_t from_organizer,
 							    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_participant_infos(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;
@@ -304,20 +275,24 @@ static void edit_simple_conference_base(bool_t from_organizer,
 									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");
 
+								update_sequence_number(&participants_info, {lise.getCMgr()->identity},
+								                       (mgr == focus.getCMgr()) ? 0 : 1,
+								                       (mgr == focus.getCMgr()) ? -1 : 0);
+
+								check_conference_info_against_db(mgr, confAddr, conf_info_from_original_content);
 								linphone_conference_info_unref(conf_info_from_original_content);
+
+								check_conference_info_in_db(mgr, uid, confAddr, marie.getCMgr()->identity,
+								                            participants_info, start_time, duration, initialSubject,
+								                            description, exp_sequence, exp_state, security_level,
+								                            FALSE);
 							}
 						}
 						linphone_chat_message_unref(msg);
@@ -334,6 +309,8 @@ static void edit_simple_conference_base(bool_t from_organizer,
 		if (join) {
 			std::list<LinphoneCoreManager *> conferenceMgrs{focus.getCMgr(), marie.getCMgr(), pauline.getCMgr()};
 			std::list<LinphoneCoreManager *> members{marie.getCMgr(), pauline.getCMgr()};
+			add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, LinphoneParticipantRoleSpeaker,
+			                             0);
 
 			stats focus_stat = focus.getStats();
 			for (auto mgr : members) {
@@ -392,20 +369,8 @@ static void edit_simple_conference_base(bool_t from_organizer,
 			                             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));
-					}
-				}
-			}
+			std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList =
+			    fill_memmber_list(members, participantList, marie.getCMgr(), participants_info);
 			wait_for_conference_streams({focus, marie, pauline, laure, michelle, lise}, conferenceMgrs, focus.getCMgr(),
 			                            memberList, confAddr, TRUE);
 
@@ -578,7 +543,15 @@ static void edit_simple_conference_base(bool_t from_organizer,
 		bctbx_list_t *initialInfos = NULL;
 		for (const auto &participant : initialParticipants) {
 			LinphoneParticipantInfo *info = linphone_participant_info_new(participant->identity);
-			initialInfos = bctbx_list_append(initialInfos, info);
+			const bctbx_list_t *participant_info_it = bctbx_list_find_custom(
+			    participants_info, (int (*)(const void *, const void *))find_matching_participant_info, info);
+			BC_ASSERT_PTR_NOT_NULL(participant_info_it);
+			if (participant_info_it) {
+				LinphoneParticipantInfo *participant_info_found =
+				    (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it);
+				initialInfos = bctbx_list_append(initialInfos, participant_info_found);
+			}
+			linphone_participant_info_unref(info);
 		}
 
 		for (int attempt = 0; attempt < 3; attempt++) {
@@ -597,8 +570,9 @@ static void edit_simple_conference_base(bool_t from_organizer,
 				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 {
+					// If marie was in the list of participants, she will be removed as well but she will be kept as
+					// organizer
 					linphone_conference_info_set_participant_infos(conf_info, initialInfos);
 				}
 
@@ -646,6 +620,24 @@ static void edit_simple_conference_base(bool_t from_organizer,
 					                             focus_stat.number_of_LinphoneCallReleased + 1,
 					                             liblinphone_tester_sip_timeout));
 
+					if (add) {
+						LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+						add_participant_info_to_list(&participants_info, michelle.getCMgr()->identity, role, 0);
+					} else {
+						for (const auto &mgr : {michelle.getCMgr(), marie.getCMgr()}) {
+							LinphoneParticipantInfo *participant_info = linphone_participant_info_new(mgr->identity);
+							bctbx_list_t *participant_info_found_it = bctbx_list_find_custom(
+							    participants_info, (int (*)(const void *, const void *))find_matching_participant_info,
+							    participant_info);
+							if (participant_info_found_it) {
+								LinphoneParticipantInfo *participant_info_found =
+								    (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_found_it);
+								participants_info = bctbx_list_remove(participants_info, participant_info_found);
+								linphone_participant_info_unref(participant_info_found);
+							}
+							linphone_participant_info_unref(participant_info);
+						}
+					}
 					LinphoneChatRoomParams *chat_room_params =
 					    linphone_core_create_default_chat_room_params(manager_editing->lc);
 					linphone_chat_room_params_set_backend(chat_room_params, LinphoneChatRoomBackendBasic);
@@ -717,51 +709,6 @@ static void edit_simple_conference_base(bool_t from_organizer,
 									    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_participant_infos(
-										        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) {
@@ -775,8 +722,6 @@ static void edit_simple_conference_base(bool_t from_organizer,
 											exp_sequence = (sequence + attempt + 1);
 										}
 
-										BC_ASSERT_EQUAL(ics_sequence, exp_sequence, int, "%d");
-
 										LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateNew;
 										if (mgr == michelle.getCMgr()) {
 											if (add) {
@@ -787,11 +732,34 @@ static void edit_simple_conference_base(bool_t from_organizer,
 										} else {
 											exp_state = LinphoneConferenceInfoStateUpdated;
 										}
-										BC_ASSERT_EQUAL(
-										    (int)linphone_conference_info_get_state(conf_info_from_original_content),
-										    (int)exp_state, int, "%d");
 
+										update_sequence_number(&participants_info, {michelle.getCMgr()->identity},
+										                       (mgr == focus.getCMgr()) ? 0 : (sequence + attempt + 1),
+										                       (mgr == focus.getCMgr()) ? -1 : 0);
+
+										LinphoneParticipantInfo *participant_info =
+										    linphone_participant_info_new(lise.getCMgr()->identity);
+										const bctbx_list_t *participant_info_it = bctbx_list_find_custom(
+										    participants_info,
+										    (int (*)(const void *, const void *))find_matching_participant_info,
+										    participant_info);
+										BC_ASSERT_PTR_NOT_NULL(participant_info_it);
+										if (participant_info_it) {
+											LinphoneParticipantInfo *participant_info_found =
+											    (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it);
+											linphone_participant_info_set_sequence_number(participant_info_found,
+											                                              (attempt + 1));
+										}
+										linphone_participant_info_unref(participant_info);
+
+										check_conference_info_against_db(mgr, confAddr,
+										                                 conf_info_from_original_content);
 										linphone_conference_info_unref(conf_info_from_original_content);
+
+										check_conference_info_in_db(mgr, uid, confAddr, marie.getCMgr()->identity,
+										                            participants_info, start_time, duration, subject,
+										                            description2, exp_sequence, exp_state,
+										                            security_level, FALSE);
 									}
 								}
 								linphone_chat_message_unref(msg);
@@ -858,34 +826,71 @@ static void edit_simple_conference_base(bool_t from_organizer,
 							} else if (mgr == lise.getCMgr()) {
 								exp_sequence = use_default_account ? (attempt + 1) : 0;
 							} else {
-								exp_sequence = use_default_account ? (sequence + attempt + 1) : 1;
+								exp_sequence = use_default_account ? (attempt + 2) : 1;
 							}
 						}
-						check_conference_info(mgr, confAddr, marie.getCMgr(),
-						                      ((use_default_account && add) ? 4 : 3) +
-						                          ((((attempt == 0) && 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) {
-								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);
+						ms_message("%s - END mgr %s", __func__, linphone_core_get_identity(mgr->lc));
+						bool is_focus = (mgr == focus.getCMgr());
+						bctbx_list_t *participants_info2 = bctbx_list_copy_with_data(
+						    participants_info, (bctbx_list_copy_func)linphone_participant_info_clone);
+						if (is_focus) {
+							add_participant_info_to_list(&participants_info2, marie.getCMgr()->identity,
+							                             LinphoneParticipantRoleSpeaker, 0);
+						}
+
+						// If not using the default account (which was used to create the conference), the
+						// conference scheduler errors out and Michelle is not added
+						int exp_sequence_number = 0;
+						if (use_default_account) {
+							if (is_focus) {
+								exp_sequence_number = (attempt + 1);
+							} else {
+								exp_sequence_number = (attempt + 2);
+							}
+						} else {
+							if (is_focus) {
+								exp_sequence_number = 0;
+							} else {
+								exp_sequence_number = 1;
+							}
+						}
+						std::list<LinphoneAddress *> new_participants{michelle.getCMgr()->identity};
+						if (!join || (is_focus && (attempt > 0))) {
+							new_participants.push_back(marie.getCMgr()->identity);
+						}
+						update_sequence_number(&participants_info2, new_participants, exp_sequence_number,
+						                       (mgr == focus.getCMgr()) ? -1 : 0);
+
+						LinphoneParticipantInfo *lise_participant_info =
+						    linphone_participant_info_new(lise.getCMgr()->identity);
+						const bctbx_list_t *participant_info_it = bctbx_list_find_custom(
+						    participants_info2, (int (*)(const void *, const void *))find_matching_participant_info,
+						    lise_participant_info);
+						BC_ASSERT_PTR_NOT_NULL(participant_info_it);
+						if (participant_info_it) {
+							int exp_lise_sequence_number = 0;
+							if (use_default_account) {
+								if (is_focus) {
+									exp_lise_sequence_number = attempt;
+								} else {
+									exp_lise_sequence_number = (attempt + 1);
+								}
+							} else {
+								if (is_focus) {
+									exp_lise_sequence_number = -1;
+								} else {
+									exp_lise_sequence_number = 0;
 								}
 							}
+							LinphoneParticipantInfo *participant_info_found =
+							    (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it);
+							linphone_participant_info_set_sequence_number(participant_info_found,
+							                                              exp_lise_sequence_number);
+						}
+						linphone_participant_info_unref(lise_participant_info);
+
+						if (!is_focus) {
 							int exp_organizer_sequence = 0;
 							if (use_default_account) {
 								exp_organizer_sequence = attempt + 2;
@@ -894,6 +899,13 @@ static void edit_simple_conference_base(bool_t from_organizer,
 							}
 							linphone_conference_info_check_organizer(info, exp_organizer_sequence);
 						}
+
+						check_conference_info_in_db(mgr, uid, confAddr, marie.getCMgr()->identity, participants_info2,
+						                            start_time, duration, exp_subject, exp_description, exp_sequence,
+						                            exp_state, security_level, FALSE);
+
+						bctbx_list_free_with_data(participants_info2,
+						                          (bctbx_list_free_func)linphone_participant_info_unref);
 					}
 					if (info) {
 						linphone_conference_info_unref(info);
@@ -903,7 +915,7 @@ static void edit_simple_conference_base(bool_t from_organizer,
 			}
 			add = !add;
 		}
-		bctbx_list_free_with_data(initialInfos, (void (*)(void *))linphone_participant_info_unref);
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		ms_free(uid);
 		ms_free(conference_address_str);
 		linphone_address_unref(alternative_address);
@@ -996,10 +1008,12 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 		const char *description = "Testing characters";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -1034,6 +1048,26 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 		           linphone_core_get_identity(michelle.getLc()), linphone_core_get_identity(laure.getLc()));
 		ms_free(conference_address_str);
 
+		// Remove Laure from list of expected participants
+		LinphoneParticipantInfo *laure_participant_info = linphone_participant_info_new(laure.getCMgr()->identity);
+		bctbx_list_t *laure_participant_info_found_it = bctbx_list_find_custom(
+		    participants_info, (int (*)(const void *, const void *))find_matching_participant_info,
+		    laure_participant_info);
+		BC_ASSERT_PTR_NOT_NULL(laure_participant_info_found_it);
+		if (laure_participant_info_found_it) {
+			LinphoneParticipantInfo *laure_participant_info_found =
+			    (LinphoneParticipantInfo *)bctbx_list_get_data(laure_participant_info_found_it);
+			participants_info = bctbx_list_remove(participants_info, laure_participant_info_found);
+			linphone_participant_info_unref(laure_participant_info_found);
+		}
+		linphone_participant_info_unref(laure_participant_info);
+		participantList.erase(laure.getCMgr());
+
+		// Add michelle to list of expected participants
+		participantList.insert(std::make_pair(
+		    michelle.getCMgr(), add_participant_info_to_list(&participants_info, michelle.getCMgr()->identity,
+		                                                     LinphoneParticipantRoleUnknown, 0)));
+
 		stats focus_stat = focus.getStats();
 
 		LinphoneConferenceInfo *conf_info = linphone_core_find_conference_information_from_uri(marie.getLc(), confAddr);
@@ -1133,49 +1167,6 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 						    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_participant_infos(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;
@@ -1184,9 +1175,15 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 							} else {
 								exp_state = LinphoneConferenceInfoStateUpdated;
 							}
-							BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(conf_info_from_original_content),
-							                (int)exp_state, int, "%d");
 
+							update_sequence_number(&participants_info, {michelle.getCMgr()->identity},
+							                       (mgr == focus.getCMgr()) ? 0 : 1, (mgr == focus.getCMgr()) ? -1 : 0);
+
+							const unsigned int ics_sequence = (mgr == michelle.getCMgr()) ? 0 : (sequence + 1);
+							check_conference_info_members(conf_info_from_original_content, uid, confAddr,
+							                              marie.getCMgr()->identity, participants_info, start_time,
+							                              duration, subject, description2, ics_sequence, exp_state,
+							                              security_level, FALSE);
 							linphone_conference_info_unref(conf_info_from_original_content);
 						}
 					}
@@ -1224,13 +1221,19 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 						exp_state = LinphoneConferenceInfoStateUpdated;
 					}
 				}
-				check_conference_info(mgr, confAddr, marie.getCMgr(), participants.size(), start_time, duration,
-				                      exp_subject, exp_description, exp_sequence, exp_state, security_level);
+
+				update_sequence_number(&participants_info, {michelle.getCMgr()->identity},
+				                       (mgr == focus.getCMgr()) ? 0 : 1, (mgr == focus.getCMgr()) ? -1 : 0);
+
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info,
+				                            start_time, duration, exp_subject, exp_description, exp_sequence, exp_state,
+				                            security_level, FALSE);
 			}
 			if (info) {
 				linphone_conference_info_unref(info);
 			}
 		}
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_conference_info_unref(conf_info);
 		ms_free(uid);
 		linphone_address_unref(confAddr);
@@ -1277,10 +1280,12 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 		const char *description = "Testing characters";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -1402,52 +1407,15 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 						    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_participant_infos(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");
-
+							const unsigned int ics_sequence = (sequence + 1);
 							LinphoneConferenceInfoState exp_state = LinphoneConferenceInfoStateUpdated;
-							BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(conf_info_from_original_content),
-							                (int)exp_state, int, "%d");
+							update_sequence_number(&participants_info, {}, (mgr == focus.getCMgr()) ? 0 : 1,
+							                       (mgr == focus.getCMgr()) ? -1 : 0);
 
+							check_conference_info_members(conf_info_from_original_content, uid, confAddr,
+							                              marie.getCMgr()->identity, participants_info, start_time,
+							                              new_duration, initialSubject, description, ics_sequence,
+							                              exp_state, security_level, FALSE);
 							linphone_conference_info_unref(conf_info_from_original_content);
 						}
 					}
@@ -1598,56 +1566,17 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 						    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_participant_infos(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");
-
+							const unsigned int ics_sequence = (sequence + 1);
 							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");
-
+							check_conference_info_members(conf_info_from_original_content, uid, confAddr,
+							                              marie.getCMgr()->identity, NULL, start_time, new_duration,
+							                              subject, description2, ics_sequence, exp_state,
+							                              security_level, FALSE);
 							linphone_conference_info_unref(conf_info_from_original_content);
 						}
 					}
@@ -1671,19 +1600,20 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 
 				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, security_level);
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, NULL, start_time,
+				                            new_duration, exp_subject, exp_description, exp_sequence, exp_state,
+				                            security_level, FALSE);
 			}
 			if (info) {
 				linphone_conference_info_unref(info);
 			}
 		}
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_conference_info_unref(conf_info);
 		ms_free(uid);
 		linphone_address_unref(confAddr);
diff --git a/tester/local_conference_tester_functions.cpp b/tester/local_conference_tester_functions.cpp
index 6bcd04088c..d5da877468 100644
--- a/tester/local_conference_tester_functions.cpp
+++ b/tester/local_conference_tester_functions.cpp
@@ -1573,47 +1573,201 @@ void conference_scheduler_invitations_sent(LinphoneConferenceScheduler *schedule
 	stat->number_of_ConferenceSchedulerInvitationsSent++;
 }
 
-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,
-                           LinphoneConferenceSecurityLevel security_level) {
+std::map<LinphoneCoreManager *, LinphoneParticipantInfo *>
+fill_memmber_list(std::list<LinphoneCoreManager *> members,
+                  std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList,
+                  LinphoneCoreManager *organizer,
+                  bctbx_list_t *participants_info) {
+	std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList;
+	for (const auto &member : members) {
+		try {
+			auto &participantInfo = participantList.at(member);
+			LinphoneParticipantRole role = linphone_participant_info_get_role(participantInfo);
+			if (role == LinphoneParticipantRoleUnknown) {
+				role = LinphoneParticipantRoleSpeaker;
+				linphone_participant_info_set_role(participantInfo, role);
+			}
+			memberList.insert(std::make_pair(member, participantInfo));
+		} catch (std::out_of_range &) {
+			if (member == organizer) {
+				memberList.insert(
+				    std::make_pair(member, add_participant_info_to_list(&participants_info, member->identity,
+				                                                        LinphoneParticipantRoleSpeaker, 0)));
+			} else {
+				ms_fatal("Unable to find active participant %s in the participant list",
+				         linphone_core_get_identity(member->lc));
+			}
+		}
+	}
+	return memberList;
+}
+
+void check_conference_info_in_db(LinphoneCoreManager *mgr,
+                                 const char *uid,
+                                 LinphoneAddress *confAddr,
+                                 LinphoneAddress *organizer,
+                                 bctbx_list_t *participantList,
+                                 long long start_time,
+                                 int duration, // in minutes
+                                 const char *subject,
+                                 const char *description,
+                                 unsigned int sequence,
+                                 LinphoneConferenceInfoState state,
+                                 LinphoneConferenceSecurityLevel security_level,
+                                 bool_t skip_participant_info) {
 	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)));
+		check_conference_info_members(info, uid, confAddr, organizer, participantList, start_time, duration, subject,
+		                              description, sequence, state, security_level, skip_participant_info);
+		linphone_conference_info_unref(info);
+	}
+}
 
-		const bctbx_list_t *info_participants = linphone_conference_info_get_participant_infos(info);
-		BC_ASSERT_EQUAL(bctbx_list_size(info_participants), no_members, size_t, "%zu");
-		BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(info), (int)security_level, int, "%0d");
+void check_conference_info_against_db(LinphoneCoreManager *mgr,
+                                      LinphoneAddress *confAddr,
+                                      const LinphoneConferenceInfo *info1) {
+	LinphoneConferenceInfo *info2 = linphone_core_find_conference_information_from_uri(mgr->lc, confAddr);
+	if (BC_ASSERT_PTR_NOT_NULL(info2)) {
+		compare_conference_infos(info1, info2, FALSE);
+		linphone_conference_info_unref(info2);
+	}
+}
+
+void check_conference_info_members(const LinphoneConferenceInfo *info,
+                                   const char *uid,
+                                   LinphoneAddress *confAddr,
+                                   LinphoneAddress *organizer,
+                                   bctbx_list_t *participantList,
+                                   long long start_time,
+                                   int duration, // in minutes
+                                   const char *subject,
+                                   const char *description,
+                                   unsigned int sequence,
+                                   LinphoneConferenceInfoState state,
+                                   LinphoneConferenceSecurityLevel security_level,
+                                   bool_t skip_participant_info) {
+	LinphoneConferenceInfo *info2 = linphone_conference_info_new();
+	linphone_conference_info_set_ics_uid(info2, uid);
+	linphone_conference_info_set_uri(info2, confAddr);
+	linphone_conference_info_set_organizer(info2, organizer);
+	linphone_conference_info_set_participant_infos(info2, participantList);
+	linphone_conference_info_set_date_time(info2, start_time);
+	linphone_conference_info_set_duration(info2, duration);
+	linphone_conference_info_set_subject(info2, subject);
+	linphone_conference_info_set_description(info2, description);
+	linphone_conference_info_set_ics_sequence(info2, sequence);
+	linphone_conference_info_set_state(info2, state);
+	linphone_conference_info_set_security_level(info2, security_level);
+	compare_conference_infos(info, info2, skip_participant_info);
+	linphone_conference_info_unref(info2);
+}
+
+void compare_conference_infos(const LinphoneConferenceInfo *info1,
+                              const LinphoneConferenceInfo *info2,
+                              bool_t skip_participant_info) {
+	BC_ASSERT_PTR_NOT_NULL(info1);
+	BC_ASSERT_PTR_NOT_NULL(info2);
+	if (info1 && info2) {
+		BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_conference_info_get_organizer(info1),
+		                                           linphone_conference_info_get_organizer(info2)));
+		BC_ASSERT_TRUE(
+		    linphone_address_equal(linphone_conference_info_get_uri(info1), linphone_conference_info_get_uri(info2)));
+
+		const bctbx_list_t *info1_participants = linphone_conference_info_get_participant_infos(info1);
+		const bctbx_list_t *info2_participants = linphone_conference_info_get_participant_infos(info2);
+		BC_ASSERT_EQUAL(bctbx_list_size(info1_participants), bctbx_list_size(info2_participants), size_t, "%zu");
+		for (const bctbx_list_t *it = info1_participants; it; it = bctbx_list_next(it)) {
+			const LinphoneParticipantInfo *participant_info1 = (LinphoneParticipantInfo *)bctbx_list_get_data(it);
+			const bctbx_list_t *participant_info2_it = bctbx_list_find_custom(
+			    info2_participants, (int (*)(const void *, const void *))find_matching_participant_info,
+			    participant_info1);
+			BC_ASSERT_PTR_NOT_NULL(participant_info2_it);
+			if (participant_info2_it) {
+				const LinphoneParticipantInfo *participant_info2 =
+				    (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info2_it);
+				BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_participant_info_get_address(participant_info1),
+				                                           linphone_participant_info_get_address(participant_info2)));
+				if (!skip_participant_info) {
+					BC_ASSERT_EQUAL(linphone_participant_info_get_role(participant_info1),
+					                linphone_participant_info_get_role(participant_info2), int, "%0d");
+					BC_ASSERT_EQUAL(linphone_participant_info_get_sequence_number(participant_info1),
+					                linphone_participant_info_get_sequence_number(participant_info2), int, "%0d");
+				}
+			}
+		}
 
-		if (start_time > 0) {
-			BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(info), start_time, long long, "%lld");
+		BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(info1),
+		                (int)linphone_conference_info_get_security_level(info2), int, "%0d");
+
+		time_t start_time1 = linphone_conference_info_get_date_time(info1);
+		time_t start_time2 = linphone_conference_info_get_date_time(info2);
+
+		if ((start_time1 > 0) && (start_time2 > 0)) {
+			BC_ASSERT_EQUAL((long long)start_time1, (long long)start_time2, long long, "%lld");
 		} else {
-			BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld");
+			if ((start_time1 != 0) && (start_time1 != -1)) {
+				BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info1), 0, long long,
+				                         "%lld");
+			}
+			if ((start_time2 != 0) && (start_time2 != -1)) {
+				BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info2), 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);
+
+		const int duration1_m = linphone_conference_info_get_duration(info1);
+		const int duration2_m = linphone_conference_info_get_duration(info2);
+		//		BC_ASSERT_EQUAL(duration_m, ((duration < 0) ? 0 : duration), int, "%d");
+		BC_ASSERT_EQUAL(duration1_m, duration2_m, int, "%d");
+
+		const char *subject1 = linphone_conference_info_get_subject(info1);
+		const char *subject2 = linphone_conference_info_get_subject(info2);
+		if (subject1 && subject2) {
+			BC_ASSERT_STRING_EQUAL(subject1, subject2);
 		} else {
-			BC_ASSERT_PTR_NULL(linphone_conference_info_get_subject(info));
+			BC_ASSERT_PTR_NULL(subject1);
+			BC_ASSERT_PTR_NULL(subject2);
+		}
+
+		const char *description1 = linphone_conference_info_get_description(info1);
+		const char *description2 = linphone_conference_info_get_description(info2);
+		if (description1 && description2) {
+			BC_ASSERT_STRING_EQUAL(description1, description2);
+		}
+
+		const unsigned int ics_sequence1 = linphone_conference_info_get_ics_sequence(info1);
+		const unsigned int ics_sequence2 = linphone_conference_info_get_ics_sequence(info2);
+		BC_ASSERT_EQUAL(ics_sequence1, ics_sequence2, int, "%d");
+		BC_ASSERT_EQUAL((int)linphone_conference_info_get_state(info1), (int)linphone_conference_info_get_state(info2),
+		                int, "%d");
+
+		const char *uid1 = linphone_conference_info_get_ics_uid(info1);
+		const char *uid2 = linphone_conference_info_get_ics_uid(info2);
+		if (uid1 && uid2) {
+			BC_ASSERT_STRING_EQUAL(uid1, uid2);
 		}
-		if (description) {
-			BC_ASSERT_STRING_EQUAL(linphone_conference_info_get_description(info), description);
+	}
+}
+
+void update_sequence_number(bctbx_list_t **participants_info,
+                            const std::list<LinphoneAddress *> new_participants,
+                            int exp_sequence,
+                            int exp_new_participant_sequence) {
+	// Increment sequence number of participants
+	for (const bctbx_list_t *it = *participants_info; it; it = bctbx_list_next(it)) {
+		LinphoneParticipantInfo *participant_info = (LinphoneParticipantInfo *)bctbx_list_get_data(it);
+		bool is_new_participant = false;
+		for (const auto &address : new_participants) {
+			is_new_participant |=
+			    !!linphone_address_weak_equal(linphone_participant_info_get_address(participant_info), address);
+		}
+		int sequence_number = 0;
+		if (is_new_participant) {
+			sequence_number = exp_new_participant_sequence;
 		} else {
-			BC_ASSERT_PTR_NULL(linphone_conference_info_get_description(info));
+			sequence_number = exp_sequence;
 		}
-		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);
+		linphone_participant_info_set_sequence_number(participant_info, sequence_number);
 	}
 }
 
@@ -1634,10 +1788,35 @@ static bool have_common_audio_payload(LinphoneCoreManager *mgr1, LinphoneCoreMan
 	return found;
 }
 
+int find_matching_participant_info(const LinphoneParticipantInfo *info1, const LinphoneParticipantInfo *info2) {
+	return !linphone_address_weak_equal(linphone_participant_info_get_address(info1),
+	                                    linphone_participant_info_get_address(info2));
+}
+
+LinphoneParticipantInfo *add_participant_info_to_list(bctbx_list_t **participants_info,
+                                                      const LinphoneAddress *address,
+                                                      LinphoneParticipantRole role,
+                                                      int sequence) {
+	LinphoneParticipantInfo *ret = NULL;
+	LinphoneParticipantInfo *participant_info = linphone_participant_info_new(address);
+	linphone_participant_info_set_role(participant_info, role);
+	linphone_participant_info_set_sequence_number(participant_info, sequence);
+	const bctbx_list_t *participant_info_it = bctbx_list_find_custom(
+	    *participants_info, (int (*)(const void *, const void *))find_matching_participant_info, participant_info);
+	if (participant_info_it) {
+		ret = (LinphoneParticipantInfo *)bctbx_list_get_data(participant_info_it);
+	} else {
+		ret = linphone_participant_info_ref(participant_info);
+		*participants_info = bctbx_list_append(*participants_info, ret);
+	}
+	linphone_participant_info_unref(participant_info);
+	return ret;
+}
+
 LinphoneAddress *
 create_conference_on_server(Focus &focus,
                             ClientConference &organizer,
-                            std::map<LinphoneCoreManager *, LinphoneParticipantRole> requested_participants,
+                            std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> requested_participants,
                             time_t start_time,
                             time_t end_time,
                             const char *subject,
@@ -1648,21 +1827,18 @@ create_conference_on_server(Focus &focus,
 	coresList = bctbx_list_append(coresList, organizer.getLc());
 	std::vector<stats> participant_stats;
 	std::map<LinphoneCoreManager *, LinphoneCall *> previous_calls;
-	bctbx_list_t *participant_infos = NULL;
+	bctbx_list_t *participants_info = 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 (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);
+	for (const auto &[mgr, participant_info] : requested_participants) {
+		LinphoneParticipantInfo *info = linphone_participant_info_clone(participant_info);
+		participants_info = bctbx_list_append(participants_info, info);
 		if (mgr == organizer.getCMgr()) {
 			found_me = true;
 		} else {
@@ -1672,6 +1848,10 @@ create_conference_on_server(Focus &focus,
 		}
 	}
 
+	int duration = 0;
+	if ((end_time >= 0) && (start_time >= 0) && (end_time > start_time)) {
+		duration = static_cast<int>((end_time - start_time) / 60); // duration is expected to be set in minutes
+	}
 	stats organizer_stat = organizer.getStats();
 	stats focus_stat = focus.getStats();
 
@@ -1695,11 +1875,8 @@ 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_participant_infos(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_participant_infos(conf_info, participants_info);
+	linphone_conference_info_set_duration(conf_info, duration);
 	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);
@@ -1717,7 +1894,6 @@ create_conference_on_server(Focus &focus,
 	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,
@@ -1810,16 +1986,30 @@ create_conference_on_server(Focus &focus,
 		linphone_conference_info_unref(info);
 	}
 
-	organizer_expected_participant_number =
-	    requested_participants.size() + ((!dialout || send_ics || found_me) ? 0 : 1);
-	participant_expected_participant_number =
-	    requested_participants.size() + ((!dialout || send_ics || found_me) ? 0 : 1);
+	if (dialout && !send_ics && !found_me) {
+		add_participant_info_to_list(&participants_info, organizer.getCMgr()->identity, LinphoneParticipantRoleSpeaker,
+		                             0);
+	}
+
+	for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) {
+		LinphoneParticipantInfo *participant_info_el = (LinphoneParticipantInfo *)bctbx_list_get_data(info_it);
+		if (dialout && !send_ics) {
+			linphone_participant_info_set_role(participant_info_el, LinphoneParticipantRoleUnknown);
+			linphone_participant_info_set_sequence_number(participant_info_el, -1);
+		} else {
+			linphone_participant_info_set_sequence_number(participant_info_el, 0);
+			if (dialout && send_ics &&
+			    (linphone_participant_info_get_role(participant_info_el) == LinphoneParticipantRoleUnknown)) {
+				linphone_participant_info_set_role(participant_info_el, LinphoneParticipantRoleSpeaker);
+			}
+		}
+	}
+
 	if (!dialout) {
 		// This check is not reliable when the conference is dialing participants
-		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, security_level);
+		check_conference_info_in_db(organizer.getCMgr(), uid, conference_address, organizer.getCMgr()->identity,
+		                            participants_info, start_time, duration, subject, description, 0,
+		                            LinphoneConferenceInfoStateNew, security_level, FALSE);
 	}
 
 	idx = 0;
@@ -1867,89 +2057,19 @@ create_conference_on_server(Focus &focus,
 						if (!BC_ASSERT_PTR_NOT_NULL(conf_info_in_db)) {
 							goto end;
 						}
+						check_conference_info_members(conf_info_in_db, uid, conference_address, organizer_address,
+						                              participants_info, start_time, duration, subject, description, 0,
+						                              LinphoneConferenceInfoStateNew,
+						                              LinphoneConferenceSecurityLevelNone, dialout);
 
 						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_participant_infos(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_participant_infos(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");
+							compare_conference_infos(conf_info_from_original_content, conf_info_in_db, FALSE);
 							linphone_conference_info_unref(conf_info_from_original_content);
-							linphone_conference_info_unref(conf_info_in_db);
 						}
+						linphone_conference_info_unref(conf_info_in_db);
 						linphone_chat_message_unref(msg);
 					}
 				}
@@ -1964,11 +2084,11 @@ create_conference_on_server(Focus &focus,
 						goto end;
 					}
 					// 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,
-					                      subject, (!!send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew,
-					                      LinphoneConferenceSecurityLevelNone);
+					check_conference_info_members(
+					    conf_info_in_db, uid, conference_address, organizer.getCMgr()->identity, participants_info,
+					    start_time, ((start_time > 0) && (end_time > 0)) ? (int)(end_time - start_time) / 60 : 0,
+					    subject, (!!send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew,
+					    LinphoneConferenceSecurityLevelNone, dialout);
 					if (!!send_ics) {
 						for (auto &p : participants) {
 							linphone_conference_info_check_participant(conf_info_in_db, p->identity, 0);
@@ -1985,15 +2105,10 @@ create_conference_on_server(Focus &focus,
 		idx++;
 	}
 
-	if (uid) {
-		ms_free(uid);
-	}
-
 	if (conference_address && !dialout) {
-		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, security_level);
+		check_conference_info_in_db(organizer.getCMgr(), uid, conference_address, organizer.getCMgr()->identity,
+		                            participants_info, start_time, duration, subject, description, 0,
+		                            LinphoneConferenceInfoStateNew, security_level, FALSE);
 	}
 
 	BC_ASSERT_EQUAL(organizer.getStats().number_of_LinphoneConferenceStateTerminationPending,
@@ -2010,11 +2125,14 @@ create_conference_on_server(Focus &focus,
 	ms_free(conference_address_str);
 
 end:
+	if (uid) {
+		ms_free(uid);
+	}
+
 	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);
-
+	bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 	return conference_address;
 }
 
@@ -2099,7 +2217,7 @@ size_t compute_no_audio_streams(LinphoneCall *call, LinphoneConference *conferen
 void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs,
                                  std::list<LinphoneCoreManager *> conferenceMgrs,
                                  LinphoneCoreManager *focus,
-                                 std::map<LinphoneCoreManager *, LinphoneParticipantRole> members,
+                                 std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> members,
                                  const LinphoneAddress *confAddr,
                                  bool_t enable_video) {
 	for (auto mgr : conferenceMgrs) {
@@ -2231,13 +2349,14 @@ void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<Co
 					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
 				}
 
-				for (const auto &[mMgr, role] : members) {
+				for (const auto &[mMgr, info] : 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);
+						participant_check &=
+						    (linphone_participant_get_role(p) == linphone_participant_info_get_role(info));
 					}
 				}
 			}
@@ -2628,10 +2747,14 @@ void create_conference_base(time_t start_time,
 		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
 		const char *description = "Paris Baker";
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
-		participantList.insert(std::make_pair(laure.getCMgr(), LinphoneParticipantRoleListener));
-		participantList.insert(std::make_pair(pauline.getCMgr(), LinphoneParticipantRoleSpeaker));
-
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
+		participantList.insert(
+		    std::make_pair(laure.getCMgr(), add_participant_info_to_list(&participants_info, laure.getCMgr()->identity,
+		                                                                 LinphoneParticipantRoleListener, -1)));
+		participantList.insert(std::make_pair(
+		    pauline.getCMgr(), add_participant_info_to_list(&participants_info, pauline.getCMgr()->identity,
+		                                                    LinphoneParticipantRoleSpeaker, -1)));
 		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
@@ -2749,21 +2872,8 @@ 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));
-				}
-			}
-		}
-
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList =
+		    fill_memmber_list(members, participantList, marie.getCMgr(), participants_info);
 		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
 		                            memberList, confAddr, enable_video);
 
@@ -3764,6 +3874,9 @@ void create_conference_base(time_t start_time,
 
 				conferenceMgrs.push_back(michelle.getCMgr());
 				members.push_back(michelle.getCMgr());
+				participantList.insert(std::make_pair(
+				    michelle.getCMgr(), add_participant_info_to_list(&participants_info, michelle.getCMgr()->identity,
+				                                                     LinphoneParticipantRoleListener, 0)));
 
 				extra_participants = 1;
 
@@ -3876,22 +3989,8 @@ 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));
-						}
-					}
-				}
+				std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList =
+				    fill_memmber_list(members, participantList, marie.getCMgr(), participants_info);
 				wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs,
 				                            focus.getCMgr(), memberList, confAddr, enable_video);
 
@@ -4786,6 +4885,7 @@ void create_conference_base(time_t start_time,
 
 		ms_free(conference_address_str);
 		linphone_address_unref(confAddr);
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		bctbx_list_free(coresList);
 	}
 }
@@ -4847,13 +4947,16 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 		}
 
 		time_t end_time = (duration <= 0) ? -1 : (start_time + duration * 60);
+		int actual_duration = (duration < 0) ? 0 : duration;
 		const char *initialSubject = "Weekly recap";
 		const char *description = "What happened in the past week";
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -4870,6 +4973,8 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 		auto conferenceMgrs = members;
 		conferenceMgrs.push_back(focus.getCMgr());
 
+		update_sequence_number(&participants_info, {}, 0, -1);
+
 		if (start_time < 0) {
 			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneCallOutgoingInit,
 			                             marie_stat.number_of_LinphoneCallOutgoingInit + 1,
@@ -4889,8 +4994,9 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 			}
 		} else if (confAddr) {
 			for (auto mgr : members) {
-				check_conference_info(mgr, confAddr, marie.getCMgr(), participants.size(), start_time, duration,
-				                      initialSubject, description, 0, LinphoneConferenceInfoStateNew, security_level);
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info,
+				                            start_time, actual_duration, initialSubject, description, 0,
+				                            LinphoneConferenceInfoStateNew, security_level, FALSE);
 
 				LinphoneCallParams *new_params = linphone_core_create_call_params(mgr->lc, nullptr);
 				linphone_call_params_set_video_direction(new_params, LinphoneMediaDirectionSendRecv);
@@ -4937,6 +5043,7 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 			}
 		}
 
+		add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, LinphoneParticipantRoleSpeaker, 0);
 		for (auto mgr : participants) {
 			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
 			                             liblinphone_tester_sip_timeout));
@@ -4952,8 +5059,9 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_NotifyFullStateReceived, 1,
 			                             liblinphone_tester_sip_timeout));
 
-			check_conference_info(mgr, confAddr, marie.getCMgr(), members.size(), start_time, duration, initialSubject,
-			                      description, 0, LinphoneConferenceInfoStateNew, security_level);
+			check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, start_time,
+			                            actual_duration, initialSubject, description, 0, LinphoneConferenceInfoStateNew,
+			                            security_level, FALSE);
 
 			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 			BC_ASSERT_PTR_NOT_NULL(pcall);
@@ -4962,31 +5070,7 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 				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_participant_infos(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");
-					BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(call_log_info),
-					                (int)security_level, int, "%0d");
-					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);
+					check_conference_info_against_db(mgr, confAddr, call_log_info);
 				}
 			}
 		}
@@ -5032,20 +5116,8 @@ 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));
-				}
-			}
-		}
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList =
+		    fill_memmber_list(members, participantList, marie.getCMgr(), participants_info);
 		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
 		                            memberList, confAddr, TRUE);
 
@@ -5209,6 +5281,8 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 
 		int participant_added = ((one_addition) ? 1 : 2);
 
+		LinphoneParticipantInfo *berthe_participant_info = add_participant_info_to_list(
+		    &participants_info, berthe.getCMgr()->identity, LinphoneParticipantRoleListener, -1);
 		if (accept) {
 			if (berthe_call) {
 				linphone_call_accept(berthe_call);
@@ -5216,7 +5290,8 @@ 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));
+			participantList.insert(std::make_pair(berthe.getCMgr(), berthe_participant_info));
+			memberList.insert(std::make_pair(berthe.getCMgr(), berthe_participant_info));
 
 			BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
 			                             focus_stat.number_of_LinphoneCallStreamsRunning + 2,
@@ -5245,7 +5320,10 @@ 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));
+				LinphoneParticipantInfo *participant_info = add_participant_info_to_list(
+				    &participants_info, michelle.getCMgr()->identity, LinphoneParticipantRoleListener, -1);
+				participantList.insert(std::make_pair(michelle.getCMgr(), participant_info));
+				memberList.insert(std::make_pair(michelle.getCMgr(), participant_info));
 
 				BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallStreamsRunning,
 				                             focus_stat.number_of_LinphoneCallStreamsRunning + 4,
@@ -5523,10 +5601,23 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 				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, security_level);
+			bctbx_list_t *participants_info2 =
+			    bctbx_list_copy_with_data(participants_info, (bctbx_list_copy_func)linphone_participant_info_clone);
+			const char *description2 = NULL;
+			if ((!one_addition && (mgr == michelle.getCMgr())) || (mgr == berthe.getCMgr())) {
+				for (bctbx_list_t *it = participants_info2; it; it = bctbx_list_next(it)) {
+					LinphoneParticipantInfo *participant_info = (LinphoneParticipantInfo *)bctbx_list_get_data(it);
+					linphone_participant_info_set_sequence_number(participant_info, -1);
+				}
+			} else {
+				description2 = description;
+			}
+
+			check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info2, 0, 0,
+			                            initialSubject, description2, 0, LinphoneConferenceInfoStateNew, security_level,
+			                            FALSE);
+
+			bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref);
 		}
 
 		// wait bit more to detect side effect if any
@@ -5534,6 +5625,7 @@ void create_conference_with_late_participant_addition_base(time_t start_time,
 			return false;
 		});
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -5598,10 +5690,12 @@ 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;
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList1;
+		bctbx_list_t *participants_info1 = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList1;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants1) {
-			participantList1.insert(std::make_pair(p, role));
+			participantList1.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info1, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -5756,11 +5850,13 @@ void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) {
 				mgr_in_conf2.push_back(marie.getCMgr());
 			}
 		}
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList2;
+		bctbx_list_t *participants_info2 = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList2;
 		for (auto &p : participants2) {
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
-			participantList2.insert(std::make_pair(p, role));
+			participantList2.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info2, p->identity, role, -1)));
 		}
 
 		LinphoneAddress *confAddr2 =
@@ -6432,6 +6528,8 @@ void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) {
 		// wait bit more to detect side effect if any
 		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
 
+		bctbx_list_free_with_data(participants_info1, (bctbx_list_free_func)linphone_participant_info_unref);
+		bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref);
 		ms_free(conference1_address_str);
 		ms_free(conference2_address_str);
 		linphone_address_unref(focusUri);
@@ -6492,10 +6590,12 @@ void create_one_participant_conference_toggle_video_base(LinphoneConferenceLayou
 		const char *description = "- <F2><F3>\n\\çà";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -7119,6 +7219,7 @@ void create_one_participant_conference_toggle_video_base(LinphoneConferenceLayou
 			}
 		}
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -7167,10 +7268,12 @@ 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;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			if (role == LinphoneParticipantRoleSpeaker) {
 				role = LinphoneParticipantRoleListener;
 			} else if (role == LinphoneParticipantRoleListener) {
@@ -7179,12 +7282,15 @@ void create_conference_with_active_call_base(bool_t dialout) {
 				role = LinphoneParticipantRoleSpeaker;
 			}
 		}
-		participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleListener));
+		participantList.insert(
+		    std::make_pair(marie.getCMgr(), add_participant_info_to_list(&participants_info, marie.getCMgr()->identity,
+		                                                                 LinphoneParticipantRoleListener, -1)));
+
 		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, -1,
 		                                                        initialSubject, description, send_ics, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
 
-		// the conference server calls Berthe  - who knows why......
+		// Berthe calls the conference server  - who knows why......
 		LinphoneCallParams *new_params = linphone_core_create_call_params(berthe.getLc(), NULL);
 
 		LinphoneContent *content = linphone_core_create_content(berthe.getLc());
@@ -7227,12 +7333,15 @@ void create_conference_with_active_call_base(bool_t dialout) {
 		}
 
 		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionIncomingReceived,
-		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 1, 5000));
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 1,
+		                             liblinphone_tester_sip_timeout));
 		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));
+		                             focus_stat.number_of_LinphoneSubscriptionTerminated + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionOutgoingProgress, 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionError, 1,
+		                             liblinphone_tester_sip_timeout));
 		if (dialout) {
 			// Chat room creation to send ICS
 			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
@@ -7301,6 +7410,19 @@ void create_conference_with_active_call_base(bool_t dialout) {
 		}
 		linphone_call_params_unref(new_params);
 
+		if (!dialout) {
+			add_participant_info_to_list(&participants_info, berthe.getCMgr()->identity,
+			                             LinphoneParticipantRoleListener, -1);
+		}
+
+		update_sequence_number(&participants_info, {berthe.getCMgr()->identity}, 0, -1);
+		for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) {
+			LinphoneParticipantInfo *participant_info_el = (LinphoneParticipantInfo *)bctbx_list_get_data(info_it);
+			if (linphone_participant_info_get_role(participant_info_el) == LinphoneParticipantRoleUnknown) {
+				linphone_participant_info_set_role(participant_info_el, LinphoneParticipantRoleSpeaker);
+			}
+		}
+
 		for (auto mgr : participants) {
 			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1,
 			                             liblinphone_tester_sip_timeout));
@@ -7309,14 +7431,20 @@ void create_conference_with_active_call_base(bool_t dialout) {
 
 			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_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_NotifyFullStateReceived, 1,
 			                             liblinphone_tester_sip_timeout));
 
-			check_conference_info(mgr, confAddr, marie.getCMgr(), 4, 0, 0, initialSubject,
-			                      (send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew, security_level);
+			if (!dialout) {
+				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_participant_devices_added, 1,
+				                             liblinphone_tester_sip_timeout));
+			}
+			check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0,
+			                            initialSubject, (send_ics) ? description : NULL, 0,
+			                            LinphoneConferenceInfoStateNew, security_level, FALSE);
 
 			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 			BC_ASSERT_PTR_NOT_NULL(pcall);
@@ -7325,31 +7453,7 @@ void create_conference_with_active_call_base(bool_t dialout) {
 				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_participant_infos(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");
-					BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(call_log_info),
-					                (int)security_level, int, "%0d");
-					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));
-					}
+					check_conference_info_against_db(mgr, confAddr, call_log_info);
 				}
 			}
 		}
@@ -7377,13 +7481,15 @@ void create_conference_with_active_call_base(bool_t dialout) {
 		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
 		                             focus_stat.number_of_LinphoneSubscriptionActive + 4, 5000));
 
+		int no_participants = (dialout) ? 4 : 5;
 		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
-		                             focus_stat.number_of_participants_added + 4, liblinphone_tester_sip_timeout));
+		                             focus_stat.number_of_participants_added + no_participants,
+		                             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,
+		                             focus_stat.number_of_participant_devices_added + no_participants,
 		                             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,
+		                             focus_stat.number_of_participant_devices_joined + no_participants,
 		                             liblinphone_tester_sip_timeout));
 
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
@@ -7452,19 +7558,35 @@ void create_conference_with_active_call_base(bool_t dialout) {
 				    }
 
 				    bool role_check = true;
-				    for (auto m : participantList) {
-					    LinphoneCoreManager *mMgr = m.first;
-					    LinphoneParticipantRole role = m.second;
+				    for (const auto &[mMgr, info] : participantList) {
 					    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);
+						    role_check &=
+						        (linphone_participant_get_role(p) == linphone_participant_info_get_role(info));
 					    }
 				    }
 				    return role_check;
 			    });
+
+			if (mgr != focus.getCMgr()) {
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0,
+				                            initialSubject, (send_ics) ? description : NULL, 0,
+				                            LinphoneConferenceInfoStateNew, security_level, FALSE);
+
+				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)) {
+						check_conference_info_against_db(mgr, confAddr, call_log_info);
+					}
+				}
+			}
 		}
 
 		// wait bit more to detect side effect if any
@@ -7690,35 +7812,17 @@ void create_conference_with_active_call_base(bool_t dialout) {
 				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));
+					LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log);
+					if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) {
+						check_conference_info_against_db(mgr, confAddr, call_log_info);
+					}
 				}
 				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_participant_infos(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);
-			}
+			check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, start_time,
+			                            0, initialSubject, (send_ics || (mgr == marie.getCMgr())) ? description : NULL,
+			                            0, LinphoneConferenceInfoStateNew, security_level, FALSE);
 		}
 
 		// wait bit more to detect side effect if any
@@ -7726,6 +7830,7 @@ void create_conference_with_active_call_base(bool_t dialout) {
 			return false;
 		});
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -7808,9 +7913,11 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
 		linphone_conference_params_unref(conf_params);
 		BC_ASSERT_PTR_NOT_NULL(conf);
 
+		bctbx_list_t *participants_info = NULL;
 		std::list<stats> participant_stats;
 		for (auto mgr : {marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
 			participant_stats.push_back(mgr->stat);
+			add_participant_info_to_list(&participants_info, mgr->identity, LinphoneParticipantRoleSpeaker, -1);
 		}
 
 		if (conf) {
@@ -7921,8 +8028,9 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
 			}
 
 			if (confAddr) {
-				check_conference_info(mgr, confAddr, marie.getCMgr(), 3, 0, 0, initialSubject, NULL, 0,
-				                      LinphoneConferenceInfoStateNew, security_level);
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0,
+				                            initialSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level,
+				                            FALSE);
 			}
 		}
 
@@ -7952,8 +8060,8 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
 			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, security_level);
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0,
+				                            newSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level, FALSE);
 			}
 			participant_stats.pop_front();
 		}
@@ -8128,8 +8236,8 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
 			}
 
 			if (confAddr) {
-				check_conference_info(mgr, confAddr, marie.getCMgr(), 3, 0, 0, newSubject, NULL, 0,
-				                      LinphoneConferenceInfoStateNew, security_level);
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0,
+				                            newSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level, FALSE);
 			}
 		}
 
@@ -8273,6 +8381,7 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
 
 							LinphoneAddress *uri = linphone_address_new(linphone_core_get_identity(mgr->lc));
 							LinphoneCall *ccall = linphone_core_get_call_by_remote_address2(focus.getLc(), uri);
+							linphone_address_unref(uri);
 							BC_ASSERT_PTR_NOT_NULL(ccall);
 							if (ccall) {
 								const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
@@ -8363,6 +8472,7 @@ void create_simple_conference_merging_calls_base(bool_t enable_ice,
 			}
 		}
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_conference_unref(conf);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
diff --git a/tester/local_conference_tester_functions.h b/tester/local_conference_tester_functions.h
index bdce9c14cd..fd01e888a0 100644
--- a/tester/local_conference_tester_functions.h
+++ b/tester/local_conference_tester_functions.h
@@ -385,7 +385,7 @@ void create_conference_base(time_t start_time,
 void wait_for_conference_streams(std::initializer_list<std::reference_wrapper<CoreManager>> coreMgrs,
                                  std::list<LinphoneCoreManager *> conferenceMgrs,
                                  LinphoneCoreManager *focus,
-                                 std::map<LinphoneCoreManager *, LinphoneParticipantRole> members,
+                                 std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> members,
                                  const LinphoneAddress *confAddr,
                                  bool_t enable_video);
 
@@ -408,7 +408,7 @@ void create_conference_with_active_call_base(bool_t dialout);
 LinphoneAddress *
 create_conference_on_server(Focus &focus,
                             ClientConference &organizer,
-                            std::map<LinphoneCoreManager *, LinphoneParticipantRole> requested_participants,
+                            std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> requested_participants,
                             time_t start_time,
                             time_t end_time,
                             const char *subject,
@@ -427,17 +427,47 @@ void set_video_settings_in_conference(LinphoneCoreManager *focus,
 
 size_t compute_no_video_streams(bool_t enable_video, LinphoneCall *call, LinphoneConference *conference);
 
-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,
-                           LinphoneConferenceSecurityLevel security_level);
+std::map<LinphoneCoreManager *, LinphoneParticipantInfo *>
+fill_memmber_list(std::list<LinphoneCoreManager *> members,
+                  std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList,
+                  LinphoneCoreManager *organizer,
+                  bctbx_list_t *participants_info);
+
+void check_conference_info_against_db(LinphoneCoreManager *mgr,
+                                      LinphoneAddress *confAddr,
+                                      const LinphoneConferenceInfo *info1);
+
+void check_conference_info_in_db(LinphoneCoreManager *mgr,
+                                 const char *uid,
+                                 LinphoneAddress *confAddr,
+                                 LinphoneAddress *organizer,
+                                 bctbx_list_t *participantList,
+                                 long long start_time,
+                                 int duration,
+                                 const char *subject,
+                                 const char *description,
+                                 unsigned int sequence,
+                                 LinphoneConferenceInfoState state,
+                                 LinphoneConferenceSecurityLevel security_level,
+                                 bool_t skip_participant_info);
+
+void check_conference_info_members(const LinphoneConferenceInfo *info,
+                                   const char *uid,
+                                   LinphoneAddress *confAddr,
+                                   LinphoneAddress *organizer,
+                                   bctbx_list_t *participantList,
+                                   long long start_time,
+                                   int duration,
+                                   const char *subject,
+                                   const char *description,
+                                   unsigned int sequence,
+                                   LinphoneConferenceInfoState state,
+                                   LinphoneConferenceSecurityLevel security_level,
+                                   bool_t skip_participant_info);
+
+void compare_conference_infos(const LinphoneConferenceInfo *info1,
+                              const LinphoneConferenceInfo *info2,
+                              bool_t skip_participant_info);
 
 size_t compute_no_audio_streams(LinphoneCall *call, LinphoneConference *conference);
 
@@ -446,6 +476,15 @@ void conference_scheduler_state_changed(LinphoneConferenceScheduler *scheduler,
 void conference_scheduler_invitations_sent(LinphoneConferenceScheduler *scheduler,
                                            const bctbx_list_t *failed_addresses);
 
+void update_sequence_number(bctbx_list_t **participants_info,
+                            const std::list<LinphoneAddress *> new_participants,
+                            int exp_sequence,
+                            int exp_new_participant_sequence);
+int find_matching_participant_info(const LinphoneParticipantInfo *info1, const LinphoneParticipantInfo *info2);
+LinphoneParticipantInfo *add_participant_info_to_list(bctbx_list_t **participants_info,
+                                                      const LinphoneAddress *address,
+                                                      LinphoneParticipantRole role,
+                                                      int sequence);
 } // namespace LinphoneTest
 
 #endif // LOCAL_CONFERENCE_TESTER_FUNCTIONS_H_
diff --git a/tester/local_ice_conference_tester.cpp b/tester/local_ice_conference_tester.cpp
index e6fb8998ae..4e4f63925b 100644
--- a/tester/local_ice_conference_tester.cpp
+++ b/tester/local_ice_conference_tester.cpp
@@ -132,10 +132,14 @@ static void abort_call_to_ice_conference(void) {
 
 		stats focus_stat = focus.getStats();
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participant_infos = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			LinphoneParticipantInfo *participant_info = linphone_participant_info_new(p->identity);
+			linphone_participant_info_set_role(participant_info, role);
+			participant_infos = bctbx_list_append(participant_infos, participant_info);
+			participantList.insert(std::make_pair(p, participant_info));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -447,6 +451,7 @@ static void abort_call_to_ice_conference(void) {
 		// wait bit more to detect side effect if any
 		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(chrono::seconds(2), [] { return false; });
 
+		bctbx_list_free_with_data(participant_infos, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -475,10 +480,9 @@ static test_t local_conference_scheduled_ice_conference_tests[] = {
     TEST_ONE_TAG("Create simple end-to-end encrypted ICE conference",
                  LinphoneTest::create_simple_end_to_end_encrypted_ice_conference,
                  "ICE"),
-    TEST_TWO_TAGS("Create simple ICE conference by merging calls",
-                  LinphoneTest::create_simple_ice_conference_merging_calls,
-                  "LeaksMemory",
-                  "ICE"), /* because of aborted calls*/
+    TEST_ONE_TAG("Create simple ICE conference by merging calls",
+                 LinphoneTest::create_simple_ice_conference_merging_calls,
+                 "ICE"), /* because of aborted calls*/
     TEST_TWO_TAGS("Abort call to ICE conference",
                   LinphoneTest::abort_call_to_ice_conference,
                   "LeaksMemory",
diff --git a/tester/local_inpromptu_conference_tester.cpp b/tester/local_inpromptu_conference_tester.cpp
index 9b70e97c58..0968969839 100644
--- a/tester/local_inpromptu_conference_tester.cpp
+++ b/tester/local_inpromptu_conference_tester.cpp
@@ -99,10 +99,12 @@ 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!!!! :-)";
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
-		LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			if (role == LinphoneParticipantRoleSpeaker) {
 				role = LinphoneParticipantRoleListener;
 			} else if (role == LinphoneParticipantRoleListener) {
@@ -214,12 +216,37 @@ static void create_conference_dial_out_base(bool_t send_ics,
 			}
 		}
 
+		bctbx_list_t *participants_info2 = NULL;
+		for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) {
+			const LinphoneParticipantInfo *participant_info_el =
+			    (LinphoneParticipantInfo *)bctbx_list_get_data(info_it);
+			const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el);
+			const int sequence = (send_ics) ? 0 : -1;
+			LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+			LinphoneParticipantRole current_role = linphone_participant_info_get_role(participant_info_el);
+			if (send_ics) {
+				if (current_role == LinphoneParticipantRoleUnknown) {
+					role = LinphoneParticipantRoleSpeaker;
+				} else {
+					role = current_role;
+				}
+			} else {
+				role = LinphoneParticipantRoleUnknown;
+			}
+			add_participant_info_to_list(&participants_info2, address, role, sequence);
+		}
+
+		if (!send_ics) {
+			add_participant_info_to_list(&participants_info2, marie.getCMgr()->identity, LinphoneParticipantRoleUnknown,
+			                             -1);
+		}
+
 		if (confAddr) {
 			for (auto mgr : participants) {
-				// Encryption is None because we haven't received yet the NOTIFY full stae with this information
-				check_conference_info(mgr, confAddr, marie.getCMgr(), (send_ics) ? 4 : 5, 0, 0, initialSubject,
-				                      (accept && send_ics) ? description : NULL, 0, LinphoneConferenceInfoStateNew,
-				                      LinphoneConferenceSecurityLevelNone);
+				// Encryption is None because we haven't received yet the NOTIFY full state yet
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info2, 0, 0,
+				                            initialSubject, (accept && send_ics) ? description : NULL, 0,
+				                            LinphoneConferenceInfoStateNew, LinphoneConferenceSecurityLevelNone, FALSE);
 
 				LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 				BC_ASSERT_PTR_NOT_NULL(pcall);
@@ -235,10 +262,37 @@ static void create_conference_dial_out_base(bool_t send_ics,
 			}
 		}
 
-		int participant_conference_info_participants = 5;
+		bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref);
+
+		add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, LinphoneParticipantRoleSpeaker,
+		                             (send_ics) ? 0 : -1);
+
 		if (accept) {
+			update_sequence_number(&participants_info, {}, (send_ics) ? 0 : -1, -1);
+
 			int participant_no = static_cast<int>(participants.size());
 			for (auto mgr : participants) {
+
+				bctbx_list_t *participants_info3 = NULL;
+				for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) {
+					const LinphoneParticipantInfo *participant_info_el =
+					    (LinphoneParticipantInfo *)bctbx_list_get_data(info_it);
+					const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el);
+					const int sequence = linphone_participant_info_get_sequence_number(participant_info_el);
+					bool found = false;
+					for (const auto &mgr : codec_mismatch_members) {
+						found |= !!linphone_address_weak_equal(address, mgr->identity);
+					}
+					LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+					LinphoneParticipantRole current_role = linphone_participant_info_get_role(participant_info_el);
+					if (!found && (current_role == LinphoneParticipantRoleUnknown)) {
+						role = LinphoneParticipantRoleSpeaker;
+					} else {
+						role = current_role;
+					}
+					add_participant_info_to_list(&participants_info3, address, role, sequence);
+				}
+
 				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,
@@ -249,9 +303,9 @@ static void create_conference_dial_out_base(bool_t send_ics,
 				                             liblinphone_tester_sip_timeout));
 				BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_NotifyFullStateReceived, 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, security_level);
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info3, 0, 0,
+				                            initialSubject, (send_ics) ? description : NULL, 0,
+				                            LinphoneConferenceInfoStateNew, security_level, FALSE);
 				LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 				BC_ASSERT_PTR_NOT_NULL(pcall);
 				if (pcall) {
@@ -259,32 +313,10 @@ static void create_conference_dial_out_base(bool_t send_ics,
 					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_participant_infos(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));
-						}
+						check_conference_info_against_db(mgr, confAddr, call_log_info);
 					}
 				}
+				bctbx_list_free_with_data(participants_info3, (bctbx_list_free_func)linphone_participant_info_unref);
 			}
 
 			if (enable_ice) {
@@ -334,24 +366,8 @@ 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));
-					}
-				}
-			}
+			std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList =
+			    fill_memmber_list(members, participantList, marie.getCMgr(), participants_info);
 			wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs,
 			                            focus.getCMgr(), memberList, confAddr, enable_video);
 
@@ -378,11 +394,34 @@ static void create_conference_dial_out_base(bool_t send_ics,
 						no_participants = static_cast<int>(members.size());
 						BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
 					} else {
+						bctbx_list_t *participants_info3 = NULL;
+						for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) {
+							const LinphoneParticipantInfo *participant_info_el =
+							    (LinphoneParticipantInfo *)bctbx_list_get_data(info_it);
+							const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el);
+							const int sequence = linphone_participant_info_get_sequence_number(participant_info_el);
+							bool found = false;
+							for (const auto &mgr : codec_mismatch_members) {
+								found |= !!linphone_address_weak_equal(address, mgr->identity);
+							}
+							LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+							LinphoneParticipantRole current_role =
+							    linphone_participant_info_get_role(participant_info_el);
+							if (((mgr == marie.getCMgr()) || !found) &&
+							    (current_role == LinphoneParticipantRoleUnknown)) {
+								role = LinphoneParticipantRoleSpeaker;
+							} else {
+								role = current_role;
+							}
+							add_participant_info_to_list(&participants_info3, address, role, sequence);
+						}
 
-						check_conference_info(mgr, confAddr, marie.getCMgr(), participant_conference_info_participants,
-						                      0, 0, initialSubject,
-						                      (send_ics || (mgr == marie.getCMgr())) ? description : NULL, 0,
-						                      LinphoneConferenceInfoStateNew, security_level);
+						check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info3,
+						                            0, 0, initialSubject,
+						                            (send_ics || (mgr == marie.getCMgr())) ? description : NULL, 0,
+						                            LinphoneConferenceInfoStateNew, security_level, FALSE);
+						bctbx_list_free_with_data(participants_info3,
+						                          (bctbx_list_free_func)linphone_participant_info_unref);
 
 						no_participants = participant_no;
 						BC_ASSERT_TRUE(linphone_conference_is_in(pconference));
@@ -406,10 +445,9 @@ 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_max_streams_audio = (security_level == LinphoneConferenceSecurityLevelEndToEnd)
+						                                  ? bctbx_list_size(participants_info)
+						                                  : 1;
 						size_t no_max_streams_video = (enabled || (mgr == marie.getCMgr()))
 						                                  ? ((security_level == LinphoneConferenceSecurityLevelEndToEnd)
 						                                         ? 2 * (participants.size() + 1)
@@ -442,36 +480,7 @@ static void create_conference_dial_out_base(bool_t send_ics,
 							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_participant_infos(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");
-								BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(call_log_info),
-								                (int)security_level, int, "%0d");
-								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 || (mgr == marie.getCMgr())) {
-									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));
-								}
+								check_conference_info_against_db(mgr, confAddr, call_log_info);
 							}
 						}
 
@@ -777,14 +786,41 @@ static void create_conference_dial_out_base(bool_t send_ics,
 				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;
+					LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log);
+					if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) {
+						check_conference_info_against_db(mgr, confAddr, call_log_info);
+					}
 					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(), participant_conference_info_participants, 0, 0, initialSubject,
+
+			bctbx_list_t *participants_info3 = NULL;
+			for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) {
+				const LinphoneParticipantInfo *participant_info_el =
+				    (LinphoneParticipantInfo *)bctbx_list_get_data(info_it);
+				const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el);
+				const int sequence = linphone_participant_info_get_sequence_number(participant_info_el);
+				bool found = false;
+				for (const auto &mgr : codec_mismatch_members) {
+					found |= !!linphone_address_weak_equal(address, mgr->identity);
+				}
+				LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+				LinphoneParticipantRole current_role = linphone_participant_info_get_role(participant_info_el);
+				if ((mgr != marie.getCMgr()) && !accept) {
+					role = LinphoneParticipantRoleUnknown;
+				} else if (((mgr == marie.getCMgr()) || !found) && (current_role == LinphoneParticipantRoleUnknown)) {
+					role = LinphoneParticipantRoleSpeaker;
+				} else {
+					role = current_role;
+				}
+				add_participant_info_to_list(&participants_info3, address, role, sequence);
+			}
+			check_conference_info_in_db(
+			    mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info3, 0, 0, initialSubject,
 			    ((accept && send_ics) || (mgr == marie.getCMgr())) ? description : NULL, 0,
-			    LinphoneConferenceInfoStateNew, (accept) ? security_level : LinphoneConferenceSecurityLevelNone);
+			    LinphoneConferenceInfoStateNew, (accept) ? security_level : LinphoneConferenceSecurityLevelNone, FALSE);
+			bctbx_list_free_with_data(participants_info3, (bctbx_list_free_func)linphone_participant_info_unref);
 		}
 
 		// wait bit more to detect side effect if any
@@ -792,6 +828,7 @@ static void create_conference_dial_out_base(bool_t send_ics,
 			return false;
 		});
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -934,10 +971,12 @@ static void create_simple_conference_dial_out_organizer_codec_mismatch(void) {
 		const char *description = "To the Goutier mountain hut!!!! :-)";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -957,6 +996,7 @@ static void create_simple_conference_dial_out_organizer_codec_mismatch(void) {
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 		BC_ASSERT_PTR_NULL(fconference);
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		if (confAddr) linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -1027,10 +1067,12 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 		const char *description = "Having fun!!!! :-)";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -1093,9 +1135,21 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 		}
 
 		if (confAddr) {
+			add_participant_info_to_list(&participants_info, marie.getCMgr()->identity, LinphoneParticipantRoleSpeaker,
+			                             -1);
 			for (auto mgr : participants) {
-				check_conference_info(mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject, NULL, 0,
-				                      LinphoneConferenceInfoStateNew, security_level);
+				bctbx_list_t *participants_info2 = NULL;
+				for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) {
+					LinphoneParticipantInfo *participant_info_el =
+					    (LinphoneParticipantInfo *)bctbx_list_get_data(info_it);
+					LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+					const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el);
+					add_participant_info_to_list(&participants_info2, address, role, -1);
+				}
+
+				check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info2, 0, 0,
+				                            initialSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level,
+				                            FALSE);
 
 				LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 				BC_ASSERT_PTR_NOT_NULL(pcall);
@@ -1109,6 +1163,8 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 						linphone_call_decline(pcall, reason);
 					}
 				}
+
+				bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref);
 			}
 		}
 
@@ -1125,11 +1181,11 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 			                             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, &mgr->stat.number_of_NotifyFullStateReceived, 1,
+			                             liblinphone_tester_sip_timeout));
 
-			check_conference_info(mgr, confAddr, marie.getCMgr(), 5, 0, 0, initialSubject, NULL, 0,
-			                      LinphoneConferenceInfoStateNew, security_level);
+			check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0,
+			                            initialSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level, TRUE);
 
 			LinphoneCall *pcall = linphone_core_get_call_by_remote_address2(mgr->lc, confAddr);
 			BC_ASSERT_PTR_NOT_NULL(pcall);
@@ -1138,28 +1194,7 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 				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_participant_infos(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");
-					BC_ASSERT_EQUAL((int)linphone_conference_info_get_security_level(call_log_info),
-					                (int)security_level, int, "%0d");
-					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));
+					check_conference_info_against_db(mgr, confAddr, call_log_info);
 				}
 			}
 		}
@@ -1241,20 +1276,8 @@ 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));
-				}
-			}
-		}
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList =
+		    fill_memmber_list(all_active_participants, participantList, marie.getCMgr(), participants_info);
 		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conference_members,
 		                            focus.getCMgr(), memberList, confAddr, TRUE);
 
@@ -1369,6 +1392,23 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 				if (devices) {
 					bctbx_list_free_with_data(devices, (void (*)(void *))linphone_participant_device_unref);
 				}
+
+				if (mgr != focus.getCMgr()) {
+					check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info, 0, 0,
+					                            initialSubject, NULL, 0, LinphoneConferenceInfoStateNew, security_level,
+					                            TRUE);
+
+					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)) {
+							check_conference_info_against_db(mgr, confAddr, call_log_info);
+						}
+					}
+				}
 			}
 		}
 
@@ -1528,12 +1568,45 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 				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));
+					LinphoneConferenceInfo *call_log_info = linphone_call_log_get_conference_info(call_log);
+					if (BC_ASSERT_PTR_NOT_NULL(call_log_info)) {
+						check_conference_info_against_db(mgr, confAddr, call_log_info);
+					}
 				}
 				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,
-			                      security_level);
+
+			bool mgr_declining_call = false;
+			for (auto declining_mgr : declining_participants) {
+				mgr_declining_call |= !!linphone_address_weak_equal(mgr->identity, declining_mgr->identity);
+			}
+
+			bctbx_list_t *participants_info2 = NULL;
+			for (bctbx_list_t *info_it = participants_info; info_it; info_it = bctbx_list_next(info_it)) {
+				LinphoneParticipantInfo *participant_info_el = (LinphoneParticipantInfo *)bctbx_list_get_data(info_it);
+				const LinphoneAddress *address = linphone_participant_info_get_address(participant_info_el);
+				bool declining_call = false;
+				for (auto declining_mgr : declining_participants) {
+					declining_call |= !!linphone_address_weak_equal(address, declining_mgr->identity);
+				}
+
+				LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
+				int sequence = -1;
+				if (mgr_declining_call || (declining_call && (mgr != marie.getCMgr()))) {
+					role = LinphoneParticipantRoleUnknown;
+					sequence = -1;
+				} else {
+					role = linphone_participant_info_get_role(participant_info_el);
+					sequence = linphone_participant_info_get_sequence_number(participant_info_el);
+				}
+				add_participant_info_to_list(&participants_info2, address, role, sequence);
+			}
+			check_conference_info_in_db(mgr, NULL, confAddr, marie.getCMgr()->identity, participants_info2, 0, 0,
+			                            initialSubject, (mgr == marie.getCMgr()) ? description : NULL, 0,
+			                            LinphoneConferenceInfoStateNew, security_level,
+			                            !((mgr == marie.getCMgr()) || mgr_declining_call));
+
+			bctbx_list_free_with_data(participants_info2, (bctbx_list_free_func)linphone_participant_info_unref);
 		}
 
 		// wait bit more to detect side effect if any
@@ -1541,6 +1614,7 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 			return false;
 		});
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -1627,10 +1701,12 @@ static void simple_dial_out_conference_with_no_payloads(void) {
 		const char *description = "To the top of the Mont Blanc!!!! :-)";
 
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -1768,6 +1844,7 @@ static void simple_dial_out_conference_with_no_payloads(void) {
 		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateDeleted, 1,
 		                             liblinphone_tester_sip_timeout));
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -1788,9 +1865,8 @@ static test_t local_conference_inpromptu_conference_tests[] = {
     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_NO_TAG("Create simple conference by merging calls with video toggling",
+                LinphoneTest::create_simple_conference_merging_calls_with_video_toggling),
     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),
diff --git a/tester/local_scheduled_conference_tester.cpp b/tester/local_scheduled_conference_tester.cpp
index ac760308c3..f5809aec54 100644
--- a/tester/local_scheduled_conference_tester.cpp
+++ b/tester/local_scheduled_conference_tester.cpp
@@ -83,16 +83,14 @@ static void create_conference_on_unresponsive_server(void) {
 
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelEndToEnd;
 
-		bctbx_list_t *participant_infos = NULL;
+		bctbx_list_t *participants_info = NULL;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		const char *domain = linphone_address_get_domain(marie.getCMgr()->identity);
 		char user_address[100];
 		for (int idx = 0; idx < 180; idx++) {
 			snprintf(user_address, sizeof(user_address), "sip:happyuser%0d@%s", idx, domain);
 			LinphoneAddress *user = linphone_factory_create_address(linphone_factory_get(), user_address);
-			LinphoneParticipantInfo *participant_info = linphone_participant_info_new(user);
-			linphone_participant_info_set_role(participant_info, role);
-			participant_infos = bctbx_list_append(participant_infos, participant_info);
+			add_participant_info_to_list(&participants_info, user, role, -1);
 			if (role == LinphoneParticipantRoleSpeaker) {
 				role = LinphoneParticipantRoleListener;
 			} else if (role == LinphoneParticipantRoleListener) {
@@ -124,7 +122,7 @@ static void create_conference_on_unresponsive_server(void) {
 		                                               linphone_account_get_params(default_account)))
 		                                         : linphone_address_new(linphone_core_get_identity(marie.getLc()));
 		linphone_conference_info_set_organizer(conf_info, organizer_address);
-		linphone_conference_info_set_participant_infos(conf_info, participant_infos);
+		linphone_conference_info_set_participant_infos(conf_info, participants_info);
 		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);
@@ -155,7 +153,7 @@ static void create_conference_on_unresponsive_server(void) {
 		                             marie_stat.number_of_ConferenceSchedulerStateError + 2, request_timeout_wait));
 
 		linphone_conference_info_unref(conf_info);
-		bctbx_list_free_with_data(participant_infos, (bctbx_list_free_func)linphone_participant_info_unref);
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		if (organizer_address) linphone_address_unref(organizer_address);
 		linphone_conference_scheduler_unref(conference_scheduler);
 		bctbx_list_free(coresList);
@@ -284,16 +282,18 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 		ClientConference marie("marie_rc", focus.getIdentity());
 		ClientConference pauline("pauline_rc", focus.getIdentity());
 		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
 		focus.registerAsParticipantDevice(laure);
+		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()}) {
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), berthe.getCMgr()}) {
 			LinphoneVideoActivationPolicy *pol =
 			    linphone_factory_create_video_activation_policy(linphone_factory_get());
 			linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
@@ -323,13 +323,19 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 		const char *initialSubject = "Test characters: ^ :) ¤ çà @";
 		const char *description = "Chamrousse Pub";
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
-			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
-			                                                : LinphoneParticipantRoleSpeaker;
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
+			role = (role == LinphoneParticipantRoleListener) ? LinphoneParticipantRoleSpeaker
+			                                                 : LinphoneParticipantRoleListener;
 		}
+		participantList.insert(std::make_pair(
+		    berthe.getCMgr(), add_participant_info_to_list(&participants_info, berthe.getCMgr()->identity,
+		                                                   LinphoneParticipantRoleSpeaker, -1)));
+
 		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 
@@ -378,10 +384,8 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 			                             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));
+			                             ((mgr == marie.getCMgr()) ? 4 : 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));
@@ -400,8 +404,6 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 		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));
@@ -419,25 +421,9 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 		                             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);
-				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,
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList =
+		    fill_memmber_list(members, participantList, marie.getCMgr(), participants_info);
+		wait_for_conference_streams({focus, marie, pauline, laure, berthe}, conferenceMgrs, focus.getCMgr(), memberList,
 		                            confAddr, TRUE);
 
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
@@ -529,6 +515,153 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 			}
 		}
 
+		focus_stat = focus.getStats();
+
+		LinphoneCallParams *new_params = linphone_core_create_call_params(berthe.getCMgr()->lc, nullptr);
+		linphone_call_params_enable_video(new_params, FALSE);
+		linphone_call_params_set_conference_video_layout(new_params, LinphoneConferenceLayoutActiveSpeaker);
+		ms_message("%s is calling conference %s", linphone_core_get_identity(berthe.getCMgr()->lc),
+		           conference_address_str);
+		linphone_core_invite_address_with_params_2(berthe.getCMgr()->lc, confAddr, new_params, NULL, nullptr);
+		linphone_call_params_unref(new_params);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneCallOutgoingProgress, 1,
+		                             liblinphone_tester_sip_timeout));
+		int no_streams_running = 2;
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneCallUpdating,
+		                             (no_streams_running - 1), liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->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, &berthe.getCMgr()->stat.number_of_LinphoneConferenceStateCreated, 2,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(
+		    wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneSubscriptionOutgoingProgress, 1, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_LinphoneSubscriptionActive, 1, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getCMgr()->stat.number_of_NotifyFullStateReceived, 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));
+		focus_no_streams_running = 2;
+		// 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 - 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_LinphoneSubscriptionIncomingReceived,
+		                             focus_stat.number_of_LinphoneSubscriptionIncomingReceived + 1, 5000));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneSubscriptionActive,
+		                             focus_stat.number_of_LinphoneSubscriptionActive + 1, 5000));
+
+		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));
+
+		participants.push_back(berthe.getCMgr());
+		members.push_back(berthe.getCMgr());
+		conferenceMgrs.push_back(berthe.getCMgr());
+
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList2 =
+		    fill_memmber_list(members, participantList, marie.getCMgr(), participants_info);
+		wait_for_conference_streams({focus, marie, pauline, laure, berthe}, conferenceMgrs, focus.getCMgr(),
+		                            memberList2, confAddr, TRUE);
+
+		// 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), 4, size_t, "%zu");
+				bctbx_list_free_with_data(participant_device_list, (void (*)(void *))linphone_participant_device_unref);
+
+				if (mgr == focus.getCMgr()) {
+					no_participants = 4;
+					BC_ASSERT_FALSE(linphone_conference_is_in(pconference));
+				} else {
+					no_participants = 3;
+					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");
+					}
+
+					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;
+
+					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);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(pcall);
+						BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_lparams));
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(pcall);
+						BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_rparams));
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pcall);
+						BC_ASSERT_FALSE(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_active_streams_video,
+						                                       no_streams_text);
+						const LinphoneCallParams *call_lparams = linphone_call_get_params(ccall);
+						BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_lparams));
+						const LinphoneCallParams *call_rparams = linphone_call_get_remote_params(ccall);
+						BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_rparams));
+						const LinphoneCallParams *call_cparams = linphone_call_get_current_params(ccall);
+						BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_cparams));
+					}
+				}
+				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);
+				}
+			}
+		}
+
 		// Everybody adds video
 		std::list<LinphoneCoreManager *> withVideo{};
 		int mCnt = 0;
@@ -596,16 +729,21 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 		                                (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()));
+		const int total_berthe_calls =
+		    berthe.getStats().number_of_LinphoneCallEnd + (int)bctbx_list_size(linphone_core_get_calls(berthe.getLc()));
 
 		linphone_core_terminate_all_calls(pauline.getLc());
 		linphone_core_terminate_all_calls(laure.getLc());
 		linphone_core_terminate_all_calls(marie.getLc());
+		linphone_core_terminate_all_calls(berthe.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, &berthe.getStats().number_of_LinphoneCallEnd, total_berthe_calls, 30000));
 		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallEnd, total_focus_calls, 40000));
 
 		BC_ASSERT_TRUE(
@@ -614,6 +752,8 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 		    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, &berthe.getStats().number_of_LinphoneCallReleased, total_berthe_calls, 30000));
 		BC_ASSERT_TRUE(
 		    wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallReleased, total_focus_calls, 40000));
 
@@ -621,7 +761,7 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 			linphone_conference_terminate(fconference);
 		}
 
-		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr()}) {
+		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), berthe.getCMgr()}) {
 
 			// Wait for all conferences to be terminated
 			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneConferenceStateTerminationPending, 1,
@@ -632,7 +772,7 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 			                             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));
+			                             (mgr == focus.getCMgr()) ? 4 : 1, liblinphone_tester_sip_timeout));
 
 			if (mgr && (mgr != focus.getCMgr())) {
 				LinphoneCall *participant_call =
@@ -658,6 +798,7 @@ static void create_conference_with_audio_only_participants_base(LinphoneConferen
 			}
 		}
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		ms_free(conference_address_str);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
@@ -741,14 +882,19 @@ static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mi
 		const char *description = "Paris Baker";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
-		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
+		LinphoneParticipantRole role = LinphoneParticipantRoleUnknown;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
-		participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleListener));
+		participantList.insert(
+		    std::make_pair(marie.getCMgr(), add_participant_info_to_list(&participants_info, marie.getCMgr()->identity,
+		                                                                 LinphoneParticipantRoleListener, -1)));
+
 		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 		BC_ASSERT_PTR_NOT_NULL(confAddr);
@@ -792,10 +938,11 @@ static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mi
 			participantList.erase(m);
 		}
 
-		for (auto [mgr, role] : participantList) {
+		for (auto [mgr, info] : participantList) {
 			BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1,
 			                             liblinphone_tester_sip_timeout));
-			int no_streams_running = (role == LinphoneParticipantRoleSpeaker) ? 3 : 2;
+			int no_streams_running =
+			    (linphone_participant_info_get_role(info) == LinphoneParticipantRoleSpeaker) ? 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,
@@ -864,20 +1011,8 @@ 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));
-				}
-			}
-		}
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList =
+		    fill_memmber_list(members, participantList, marie.getCMgr(), participants_info);
 		wait_for_conference_streams({focus, marie, pauline, laure, michelle, berthe}, conferenceMgrs, focus.getCMgr(),
 		                            memberList, confAddr, TRUE);
 
@@ -1060,6 +1195,7 @@ static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mi
 			return false;
 		});
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		ms_free(conference_address_str);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
@@ -1120,14 +1256,18 @@ static void create_conference_with_server_restart_base(bool_t organizer_first) {
 		const char *description = "London Pub";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
-		participantList.insert(std::make_pair(marie.getCMgr(), LinphoneParticipantRoleSpeaker));
+		participantList.insert(
+		    std::make_pair(marie.getCMgr(), add_participant_info_to_list(&participants_info, marie.getCMgr()->identity,
+		                                                                 LinphoneParticipantRoleSpeaker, -1)));
 		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
 
@@ -1230,20 +1370,8 @@ static void create_conference_with_server_restart_base(bool_t organizer_first) {
 		                             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));
-				}
-			}
-		}
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> memberList =
+		    fill_memmber_list(members, participantList, marie.getCMgr(), participants_info);
 		wait_for_conference_streams({focus, marie, pauline, laure}, conferenceMgrs, focus.getCMgr(), memberList,
 		                            confAddr, TRUE);
 
@@ -1411,6 +1539,7 @@ static void create_conference_with_server_restart_base(bool_t organizer_first) {
 			}
 		}
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		ms_free(conference_address_str);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
@@ -1477,10 +1606,12 @@ static void create_simple_conference_with_update_deferred(void) {
 		const char *description = "Paris Baker";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener
 			                                                : LinphoneParticipantRoleSpeaker;
 		}
@@ -1887,6 +2018,7 @@ static void create_simple_conference_with_update_deferred(void) {
 		// wait bit more to detect side effect if any
 		CoreManagerAssert({focus, marie, pauline, laure, michelle}).waitUntil(chrono::seconds(2), [] { return false; });
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -1944,10 +2076,12 @@ static void change_active_speaker(void) {
 		const char *description = "hello";
 		LinphoneConferenceSecurityLevel security_level = LinphoneConferenceSecurityLevelNone;
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo *> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : invitesList) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(
+			    std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 		}
 		LinphoneAddress *confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time,
 		                                                        initialSubject, description, TRUE, security_level);
@@ -2156,6 +2290,7 @@ static void change_active_speaker(void) {
 			}
 		}
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
@@ -2208,10 +2343,11 @@ static void conference_with_participant_added_outside_valid_time_slot (bool_t be
 		const char *initialSubject = "Colleagues";
 		const char *description = "Tom Black";
 
-		std::map<LinphoneCoreManager *, LinphoneParticipantRole> participantList;
+		bctbx_list_t *participants_info = NULL;
+		std::map<LinphoneCoreManager *, LinphoneParticipantInfo*> participantList;
 		LinphoneParticipantRole role = LinphoneParticipantRoleSpeaker;
 		for (auto &p : participants) {
-			participantList.insert(std::make_pair(p, role));
+			participantList.insert(std::make_pair(p, add_participant_info_to_list(&participants_info, p->identity, role, -1)));
 			role = (role == LinphoneParticipantRoleSpeaker) ? LinphoneParticipantRoleListener : LinphoneParticipantRoleSpeaker;
 		}
 		LinphoneAddress* confAddr = create_conference_on_server(focus, marie, participantList, start_time, end_time, initialSubject, description, TRUE, security_level);
@@ -2237,6 +2373,7 @@ static void conference_with_participant_added_outside_valid_time_slot (bool_t be
 			return false;
 		});
 
+		bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
 		linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 
diff --git a/tester/tester.c b/tester/tester.c
index 482e275833..17f11c20eb 100644
--- a/tester/tester.c
+++ b/tester/tester.c
@@ -702,6 +702,13 @@ conference_participant_device_media_capability_changed(LinphoneConference *confe
 	manager->stat.number_of_participant_devices_media_capability_changed++;
 }
 
+static void conference_participant_role_changed(LinphoneConference *conference,
+                                                BCTBX_UNUSED(const LinphoneParticipant *participant)) {
+	LinphoneCore *core = linphone_conference_get_core(conference);
+	LinphoneCoreManager *manager = (LinphoneCoreManager *)linphone_core_get_user_data(core);
+	manager->stat.number_of_participant_role_changed++;
+}
+
 static void conference_participant_admin_status_changed(LinphoneConference *conference,
                                                         BCTBX_UNUSED(const LinphoneParticipant *participant)) {
 	LinphoneCore *core = linphone_conference_get_core(conference);
@@ -747,6 +754,7 @@ void core_conference_state_changed(BCTBX_UNUSED(LinphoneCore *core),
 		linphone_conference_cbs_set_state_changed(cbs, conference_state_changed);
 		linphone_conference_cbs_set_available_media_changed(cbs, conference_available_media_changed);
 		linphone_conference_cbs_set_subject_changed(cbs, conference_subject_changed);
+		linphone_conference_cbs_set_participant_role_changed(cbs, conference_participant_role_changed);
 		linphone_conference_cbs_set_participant_admin_status_changed(cbs, conference_participant_admin_status_changed);
 		linphone_conference_cbs_set_participant_device_media_capability_changed(
 		    cbs, conference_participant_device_media_capability_changed);
-- 
GitLab