diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc
index 83f2ceb37dcedf4a8829fd185e30304ab710af8f..909b78edc08c78591d03eb9e8aa0f63543e7a3ba 100644
--- a/coreapi/TunnelManager.cc
+++ b/coreapi/TunnelManager.cc
@@ -18,19 +18,20 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+
 #include "bctoolbox/defs.h"
 
-#include "TunnelManager.hh"
+#include "ortp/rtpsession.h"
 
+#include "TunnelManager.hh"
 #include "account/account.h"
 #include "linphone/core.h"
 #include "linphone/core_utils.h"
-#include "ortp/rtpsession.h"
 #include "private.h"
 #include "private_functions.h"
-#ifdef __ANDROID__
-#include <android/log.h>
-#endif
 
 belledonnecomm::TunnelManager *bcTunnel(const LinphoneTunnel *tunnel);
 
diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c
index f88e283b852d3e9067941c1dea1ef27a30563f9c..bf84327062fdc51550ec1454e118470c3f011e56 100644
--- a/coreapi/bellesip_sal/sal_address_impl.c
+++ b/coreapi/bellesip_sal/sal_address_impl.c
@@ -22,15 +22,22 @@
 /**/
 /* Address manipulation API*/
 SalAddress *sal_address_new(const char *uri) {
-	belle_sip_header_address_t *result;
-	if (uri && uri[0] != '\0') {
+	if (uri) {
+		belle_sip_header_address_t *result;
 		result = belle_sip_header_address_fast_parse(uri);
-		/*may return NULL*/
+		if (result) belle_sip_object_ref(result);
+		return (SalAddress *)result;
 	} else {
-		result = belle_sip_header_address_new();
-		belle_sip_header_address_set_uri(result, belle_sip_uri_new());
+		return sal_address_new_empty();
 	}
-	if (result) belle_sip_object_ref(result);
+	return NULL;
+}
+
+SalAddress *sal_address_new_empty(void) {
+	belle_sip_header_address_t *result;
+	result = belle_sip_header_address_new();
+	belle_sip_header_address_set_uri(result, belle_sip_uri_new());
+	belle_sip_object_ref(result);
 	return (SalAddress *)result;
 }
 
@@ -171,7 +178,8 @@ bool_t sal_address_is_sip(const SalAddress *addr) {
 }
 
 char *sal_address_as_string_uri_only(const SalAddress *addr) {
-	belle_sip_header_address_t *header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
+	SalAddress *address_uri = sal_address_new_uri_only(addr);
+	belle_sip_header_address_t *header_addr = BELLE_SIP_HEADER_ADDRESS(address_uri);
 	belle_sip_uri_t *sip_uri = belle_sip_header_address_get_uri(header_addr);
 	belle_generic_uri_t *absolute_uri = belle_sip_header_address_get_absolute_uri(header_addr);
 	char tmp[1024] = {0};
@@ -187,7 +195,20 @@ char *sal_address_as_string_uri_only(const SalAddress *addr) {
 		return NULL;
 	}
 	belle_sip_object_marshal(uri, tmp, sizeof(tmp), &off);
-	return ms_strdup(tmp);
+	char *uri_string = ms_strdup(tmp);
+	sal_address_unref(address_uri);
+	return uri_string;
+}
+
+SalAddress *sal_address_new_uri_only(const SalAddress *addr) {
+	belle_sip_header_address_t *uri_only = belle_sip_header_address_new();
+	if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr))) {
+		belle_sip_header_address_set_uri(
+		    uri_only, BELLE_SIP_URI(belle_sip_object_clone(
+		                  BELLE_SIP_OBJECT(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr))))));
+	}
+	belle_sip_object_ref(uri_only);
+	return (SalAddress *)uri_only;
 }
 
 void sal_address_set_param(SalAddress *addr, const char *name, const char *value) {
@@ -201,6 +222,11 @@ bool_t sal_address_has_param(const SalAddress *addr, const char *name) {
 	return !!belle_sip_parameters_has_parameter(parameters, name);
 }
 
+void sal_address_clean_params(const SalAddress *addr) {
+	belle_sip_parameters_t *parameters = BELLE_SIP_PARAMETERS(addr);
+	belle_sip_parameters_clean(parameters);
+}
+
 void sal_address_remove_param(const SalAddress *addr, const char *name) {
 	belle_sip_parameters_t *parameters = BELLE_SIP_PARAMETERS(addr);
 	belle_sip_parameters_remove_parameter(parameters, name);
@@ -234,19 +260,15 @@ bool_t sal_address_has_uri_param(const SalAddress *addr, const char *name) {
 	return !!belle_sip_parameters_has_parameter(parameters, name);
 }
 
-bctbx_map_t *sal_address_get_uri_params(const SalAddress *addr) {
+void sal_address_get_uri_params(const SalAddress *addr, std::map<std::string, std::string> &params) {
 	belle_sip_parameters_t *parameters =
 	    BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr)));
 	const belle_sip_list_t *param_names = belle_sip_parameters_get_parameter_names(parameters);
-	bctbx_map_t *param_map = bctbx_mmap_cchar_new();
 	for (belle_sip_list_t *it = (belle_sip_list_t *)param_names; it != NULL; it = it->next) {
 		const char *name = (const char *)it->data;
 		const char *value = belle_sip_parameters_get_parameter(parameters, name);
-		bctbx_pair_t *pair = (bctbx_pair_t *)bctbx_pair_cchar_new(name, ms_strdup(value));
-		bctbx_map_cchar_insert_and_delete(param_map, pair);
+		params[name] = value ? value : "";
 	}
-
-	return param_map;
 }
 
 const char *sal_address_get_uri_param(const SalAddress *addr, const char *name) {
diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c
index 2fd9834ceca94baed8ee47f87091e592f3c2705b..fd4983db811a9290e46c0f99d4ae1daf2b77e082 100644
--- a/coreapi/bellesip_sal/sal_impl.c
+++ b/coreapi/bellesip_sal/sal_impl.c
@@ -19,6 +19,7 @@
  */
 
 #include "sal_impl.h"
+#include "tester_utils.h"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c
index d134a30e2ed83a343bbb884ddc45efa457c9bf6a..996c1f369f6010c2dfe80f06939e49193e17551f 100644
--- a/coreapi/callbacks.c
+++ b/coreapi/callbacks.c
@@ -18,21 +18,6 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "c-wrapper/internal/c-sal.h"
-#include "sal/call-op.h"
-#include "sal/message-op.h"
-#include "sal/refer-op.h"
-
-#include "linphone/api/c-content.h"
-#include "linphone/core.h"
-#include "linphone/utils/utils.h"
-
-#include "conference_private.h"
-#include "linphone/lpconfig.h"
-#include "mediastreamer2/mediastream.h"
-#include "private.h"
-#include <bctoolbox/defs.h>
-
 // stat
 #ifndef _WIN32
 #include <sys/stat.h>
@@ -40,11 +25,25 @@
 #include <unistd.h>
 #endif
 
+#include <bctoolbox/defs.h>
+
+#include "mediastreamer2/mediastream.h"
+
 #include "account/account.h"
 #include "c-wrapper/c-wrapper.h"
+#include "c-wrapper/internal/c-sal.h"
 #include "call/call.h"
 #include "chat/chat-message/chat-message-p.h"
 #include "chat/chat-room/chat-room.h"
+#include "conference_private.h"
+#include "linphone/api/c-content.h"
+#include "linphone/core.h"
+#include "linphone/lpconfig.h"
+#include "linphone/utils/utils.h"
+#include "private.h"
+#include "sal/call-op.h"
+#include "sal/message-op.h"
+#include "sal/refer-op.h"
 #ifdef HAVE_ADVANCED_IM
 #include "chat/chat-room/client-group-chat-room-p.h"
 #include "chat/chat-room/server-group-chat-room-p.h"
@@ -103,17 +102,16 @@ static void call_received(SalCallOp *h) {
 
 	if (!fromAddr) fromAddr = linphone_address_new(h->getFrom().c_str());
 	LinphoneAddress *toAddr = linphone_address_new(h->getTo().c_str());
+	std::shared_ptr<Address> to = Address::toCpp(toAddr)->toSharedPtr();
+	std::shared_ptr<Address> from = Address::toCpp(fromAddr)->toSharedPtr();
 
 	if (sal_address_has_param(h->getRemoteContactAddress(), "text")) {
 #ifdef HAVE_ADVANCED_IM
 		if (linphone_core_conference_server_enabled(lc)) {
-			shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
-			    ConferenceId(ConferenceAddress(Address(h->getTo())), ConferenceAddress(Address(h->getTo()))));
+			shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ConferenceId(to, to));
 			if (chatRoom) {
 				L_GET_PRIVATE(static_pointer_cast<ServerGroupChatRoom>(chatRoom))->confirmJoining(h);
-			} else if (_linphone_core_is_conference_creation(lc, toAddr)) {
-				linphone_address_unref(toAddr);
-				linphone_address_unref(fromAddr);
+			} else if (_linphone_core_is_conference_creation(lc, to->toC())) {
 				string oneToOneChatRoom =
 				    L_C_TO_STRING(sal_custom_header_find(h->getRecvCustomHeaders(), "One-To-One-Chat-Room"));
 				if (oneToOneChatRoom == "true") {
@@ -124,8 +122,8 @@ static void call_received(SalCallOp *h) {
 						h->release();
 						return;
 					}
-					IdentityAddress from(h->getFrom());
-					list<IdentityAddress> identAddresses = Utils::parseResourceLists(h->getRemoteBody());
+					std::shared_ptr<Address> fromOp = Address::create(h->getFrom());
+					list<std::shared_ptr<Address>> identAddresses = Utils::parseResourceLists(h->getRemoteBody());
 					if (identAddresses.size() != 1) {
 						h->decline(SalReasonNotAcceptable);
 						h->release();
@@ -135,10 +133,10 @@ static void call_received(SalCallOp *h) {
 					    sal_custom_header_find(h->getRecvCustomHeaders(), "End-To-End-Encrypted");
 					bool encrypted = endToEndEncryptedStr && strcmp(endToEndEncryptedStr, "true") == 0;
 
-					ConferenceAddress confAddr =
+					std::shared_ptr<Address> confAddr =
 					    L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb->findOneToOneConferenceChatRoomAddress(
-					        from, identAddresses.front(), encrypted);
-					if (confAddr.isValid()) {
+					        fromOp, identAddresses.front(), encrypted);
+					if (confAddr && confAddr->isValid()) {
 						shared_ptr<AbstractChatRoom> chatRoom =
 						    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ConferenceId(confAddr, confAddr));
 						L_GET_PRIVATE(static_pointer_cast<ServerGroupChatRoom>(chatRoom))->confirmRecreation(h);
@@ -164,28 +162,25 @@ static void call_received(SalCallOp *h) {
 
 			const char *oneToOneChatRoomStr = sal_custom_header_find(h->getRecvCustomHeaders(), "One-To-One-Chat-Room");
 			if (oneToOneChatRoomStr && (strcmp(oneToOneChatRoomStr, "true") == 0)) {
-				list<IdentityAddress> participantList = Utils::parseResourceLists(h->getRemoteBody());
+				list<std::shared_ptr<Address>> participantList = Utils::parseResourceLists(h->getRemoteBody());
 				if (participantList.size() == 1) {
-					IdentityAddress participant = participantList.front();
+					std::shared_ptr<Address> participant = participantList.front();
 					shared_ptr<AbstractChatRoom> chatRoom =
-					    L_GET_PRIVATE_FROM_C_OBJECT(lc)->findExhumableOneToOneChatRoom(
-					        IdentityAddress(h->getTo()), participant, endToEndEncrypted == "true");
+					    L_GET_PRIVATE_FROM_C_OBJECT(lc)->findExhumableOneToOneChatRoom(to, participant,
+					                                                                   endToEndEncrypted == "true");
 					if (chatRoom) {
 						lInfo() << "Found exhumable chat room [" << chatRoom->getConferenceId() << "]";
 						L_GET_PRIVATE(static_pointer_cast<ClientGroupChatRoom>(chatRoom))
 						    ->onRemotelyExhumedConference(h);
 						// For tests purposes
 						linphone_core_notify_chat_room_exhumed(lc, L_GET_C_BACK_PTR(chatRoom));
-
-						linphone_address_unref(toAddr);
-						linphone_address_unref(fromAddr);
 						return;
 					}
 				}
 			}
 
-			shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
-			    ConferenceId(ConferenceAddress(Address(h->getFrom())), ConferenceAddress(Address(h->getTo()))));
+			shared_ptr<AbstractChatRoom> chatRoom =
+			    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ConferenceId(from, to));
 			if (chatRoom && chatRoom->getCapabilities() & ChatRoom::Capabilities::Basic) {
 				lError()
 				    << "Invalid basic chat room found. It should have been a ClientGroupChatRoom... Recreating it...";
@@ -194,9 +189,7 @@ static void call_received(SalCallOp *h) {
 			}
 			if (!chatRoom) {
 				chatRoom = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createClientGroupChatRoom(
-				    h->getSubject(),
-				    ConferenceId(ConferenceAddress(Address(h->getRemoteContact())),
-				                 ConferenceAddress(Address(h->getTo()))),
+				    h->getSubject(), ConferenceId(LinphonePrivate::Address::create(h->getRemoteContact()), to),
 				    h->getRemoteBody(), endToEndEncrypted == "true",
 				    ((ephemerable == "true") && (!ephemeralLifeTime.empty()))
 				        ? AbstractChatRoom::EphemeralMode::AdminManaged
@@ -208,8 +201,6 @@ static void call_received(SalCallOp *h) {
 				L_GET_PRIVATE(static_pointer_cast<ClientGroupChatRoom>(chatRoom))->addOneToOneCapability();
 			L_GET_PRIVATE(static_pointer_cast<ClientGroupChatRoom>(chatRoom))->confirmJoining(h);
 		}
-		linphone_address_unref(toAddr);
-		linphone_address_unref(fromAddr);
 		return;
 #else
 		ms_warning("Advanced IM such as group chat is disabled!");
@@ -221,8 +212,7 @@ static void call_received(SalCallOp *h) {
 		// Create a conference if remote is trying to schedule one or it is calling a conference focus
 		if (linphone_core_conference_server_enabled(lc)) {
 			shared_ptr<MediaConference::Conference> conference =
-			    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(
-			        ConferenceId(ConferenceAddress(h->getTo()), ConferenceAddress(h->getTo())));
+			    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(ConferenceId(to, to));
 			const auto &remoteMd = h->getRemoteMediaDescription();
 			const auto times = remoteMd->times;
 			time_t startTime = -1;
@@ -236,8 +226,7 @@ static void call_received(SalCallOp *h) {
 #ifdef HAVE_DB_STORAGE
 				std::shared_ptr<ConferenceInfo> confInfo =
 				    L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb->isInitialized()
-				        ? L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb->getConferenceInfoFromURI(
-				              ConferenceAddress(h->getTo()))
+				        ? L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb->getConferenceInfoFromURI(to)
 				        : nullptr;
 				if (confInfo) {
 					std::shared_ptr<MediaConference::LocalConference>(
@@ -254,8 +243,8 @@ static void call_received(SalCallOp *h) {
 						LinphoneErrorInfo *ei = linphone_error_info_new();
 						linphone_error_info_set(ei, nullptr, LinphoneReasonNotFound, 404, "Conference not found",
 						                        nullptr);
-						L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(LinphoneCallIncoming, fromAddr, toAddr,
-						                                                       ei, h->getCallId());
+						L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(LinphoneCallIncoming, from, to, ei,
+						                                                       h->getCallId());
 						h->release();
 						sal_error_info_reset(&sei);
 						return;
@@ -265,8 +254,6 @@ static void call_received(SalCallOp *h) {
 						    new MediaConference::LocalConference(L_GET_CPP_PTR_FROM_C_OBJECT(lc), h),
 						    [](MediaConference::LocalConference *c) { c->unref(); });
 						localConference->confirmCreation();
-						linphone_address_unref(toAddr);
-						linphone_address_unref(fromAddr);
 						return;
 					}
 				}
@@ -297,7 +284,7 @@ static void call_received(SalCallOp *h) {
 					LinphoneErrorInfo *ei = linphone_error_info_new();
 					linphone_error_info_set(ei, nullptr, LinphoneReasonMovedPermanently, 302, "Moved permanently",
 					                        nullptr);
-					L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(LinphoneCallIncoming, fromAddr, toAddr, ei,
+					L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(LinphoneCallIncoming, from, to, ei,
 					                                                       h->getCallId());
 					h->release();
 					sal_error_info_reset(&sei);
@@ -314,35 +301,30 @@ static void call_received(SalCallOp *h) {
 		h->decline(SalReasonBusy);
 		LinphoneErrorInfo *ei = linphone_error_info_new();
 		linphone_error_info_set(ei, nullptr, LinphoneReasonBusy, 486, "Busy - too many calls", nullptr);
-		L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(LinphoneCallIncoming, fromAddr, toAddr, ei,
-		                                                       h->getCallId());
+		L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(LinphoneCallIncoming, from, to, ei, h->getCallId());
 		h->release();
 		return;
 	}
 
 	if (linphone_config_get_int(linphone_core_get_config(lc), "sip", "reject_duplicated_calls", 1)) {
 		/* Check if I'm the caller */
-		LinphoneAddress *fromAddressToSearchIfMe = nullptr;
-		if (h->getPrivacy() == SalPrivacyNone) fromAddressToSearchIfMe = linphone_address_clone(fromAddr);
-		else if (pAssertedId) fromAddressToSearchIfMe = linphone_address_new(pAssertedId);
+		std::shared_ptr<Address> fromAddressToSearchIfMe = nullptr;
+		if (h->getPrivacy() == SalPrivacyNone) fromAddressToSearchIfMe = from->clone()->toSharedPtr();
+		else if (pAssertedId) fromAddressToSearchIfMe = Address::create(pAssertedId);
 		else ms_warning("Hidden from identity, don't know if it's me");
-		if (fromAddressToSearchIfMe && L_GET_PRIVATE_FROM_C_OBJECT(lc)->isAlreadyInCallWithAddress(
-		                                   *L_GET_CPP_PTR_FROM_C_OBJECT(fromAddressToSearchIfMe))) {
-			char *addr = linphone_address_as_string(fromAddr);
+
+		if (fromAddressToSearchIfMe &&
+		    L_GET_PRIVATE_FROM_C_OBJECT(lc)->isAlreadyInCallWithAddress(fromAddressToSearchIfMe)) {
 			ms_warning(
 			    "Receiving a call while one with same address [%s] is initiated, refusing this one with busy message",
-			    addr);
+			    from->toString().c_str());
 			h->decline(SalReasonBusy);
 			LinphoneErrorInfo *ei = linphone_error_info_new();
 			linphone_error_info_set(ei, nullptr, LinphoneReasonBusy, 486, "Busy - duplicated call", nullptr);
-			L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(LinphoneCallIncoming, fromAddr, toAddr, ei,
-			                                                       h->getCallId());
+			L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(LinphoneCallIncoming, from, to, ei, h->getCallId());
 			h->release();
-			linphone_address_unref(fromAddressToSearchIfMe);
-			ms_free(addr);
 			return;
 		}
-		if (fromAddressToSearchIfMe) linphone_address_unref(fromAddressToSearchIfMe);
 	}
 
 	auto *call = [&] {
@@ -352,8 +334,7 @@ static void call_received(SalCallOp *h) {
 
 	if (call && call->getState() == LinphonePrivate::CallSession::State::PushIncomingReceived) {
 		lInfo() << "There is already a call created on PushIncomingReceived, do configure";
-		call->configure(LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_OBJECT(fromAddr),
-		                *L_GET_CPP_PTR_FROM_C_OBJECT(toAddr), nullptr, h, nullptr);
+		call->configure(LinphoneCallIncoming, from, to, nullptr, h, nullptr);
 		call->initiateIncoming();
 	} else {
 		LinphoneCallLog *calllog = linphone_core_find_call_log(
@@ -365,28 +346,23 @@ static void call_received(SalCallOp *h) {
 			lInfo() << "The call " << h->getCallId() << " is already declined by callkit";
 			h->decline(SalReasonDeclined);
 			h->release();
-			linphone_address_unref(fromAddr);
-			linphone_address_unref(toAddr);
 			linphone_call_log_unref(calllog);
 			return;
 		}
 		if (calllog) linphone_call_log_unref(calllog);
-		call = LinphonePrivate::Call::toCpp(linphone_call_new_incoming(lc, fromAddr, toAddr, h));
+		call = LinphonePrivate::Call::toCpp(linphone_call_new_incoming(lc, from->toC(), to->toC(), h));
 	}
 
 	call->startIncomingNotification();
-
-	linphone_address_unref(fromAddr);
-	linphone_address_unref(toAddr);
 }
 
 static void call_rejected(SalCallOp *h) {
 	LinphoneCore *lc = static_cast<LinphoneCore *>(h->getSal()->getUserPointer());
 	LinphoneErrorInfo *ei = linphone_error_info_new();
 	linphone_error_info_from_sal_op(ei, h);
-	L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(
-	    LinphoneCallIncoming, linphone_address_new(h->getFrom().c_str()), linphone_address_new(h->getTo().c_str()), ei,
-	    h->getCallId());
+	std::shared_ptr<Address> from = Address::create(h->getFrom());
+	std::shared_ptr<Address> to = Address::create(h->getTo());
+	L_GET_CPP_PTR_FROM_C_OBJECT(lc)->reportEarlyCallFailed(LinphoneCallIncoming, from, to, ei, h->getCallId());
 }
 
 static void call_ringing(SalOp *h) {
@@ -592,19 +568,18 @@ static void dtmf_received(SalOp *op, char dtmf) {
 
 static void call_refer_received(SalOp *op, const SalAddress *referTo) {
 	LinphonePrivate::CallSession *session = static_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
-	char *addrStr = sal_address_as_string_uri_only(referTo);
-	Address referToAddr(addrStr);
+	std::shared_ptr<Address> referToAddr = Address::create();
+	referToAddr->setImpl(referTo);
 	string method;
-	if (referToAddr.isValid()) method = referToAddr.getMethodParam();
+	if (referToAddr && referToAddr->isValid()) method = referToAddr->getMethodParam();
 
 	if (session && (method.empty() || (method == "INVITE"))) {
 		auto sessionRef = session->getSharedFromThis();
 		L_GET_PRIVATE(sessionRef)->referred(referToAddr);
 	} else {
 		LinphoneCore *lc = static_cast<LinphoneCore *>(op->getSal()->getUserPointer());
-		linphone_core_notify_refer_received(lc, addrStr);
+		linphone_core_notify_refer_received(lc, L_STRING_TO_C(referToAddr->toString()));
 	}
-	bctbx_free(addrStr);
 }
 
 static void message_received(SalOp *op, const SalMessage *msg) {
@@ -637,7 +612,6 @@ static void convert_presence_to_xml_requested(BCTBX_UNUSED(SalOp *op),
                                               const char *contact,
                                               char **content) {
 	/*for backward compatibility because still used by notify. No loguer used for publish*/
-
 	if (linphone_presence_model_get_presentity((LinphonePresenceModel *)presence) == NULL) {
 		LinphoneAddress *presentity = linphone_address_new(contact);
 		linphone_presence_model_set_presentity((LinphonePresenceModel *)presence, presentity);
@@ -897,8 +871,7 @@ static void subscribe_received(SalSubscribeOp *op, const char *eventname, const
 		if (strcmp(linphone_event_get_name(lev), "conference") == 0) linphone_event_set_internal(lev, TRUE);
 		linphone_event_set_state(lev, LinphoneSubscriptionIncomingReceived);
 		LinphoneContent *ct = linphone_content_from_sal_body_handler(body_handler);
-		Address to(op->getTo());
-		LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(lc, L_GET_C_BACK_PTR(&to));
+		LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(lc, Address(op->getTo()).toC());
 		if (proxy && linphone_proxy_config_get_realm(proxy)) {
 			op->setRealm(linphone_proxy_config_get_realm(proxy));
 		}
@@ -981,38 +954,39 @@ static void on_notify_response(SalOp *op) {
 
 static void refer_received(SalOp *op, const SalAddress *refer_to) {
 	char *refer_uri = sal_address_as_string(refer_to);
-	LinphonePrivate::Address addr(refer_uri);
+	std::shared_ptr<LinphonePrivate::Address> referAddr = LinphonePrivate::Address::create(refer_uri);
 	bctbx_free(refer_uri);
 	LinphoneCore *lc = static_cast<LinphoneCore *>(op->getSal()->getUserPointer());
+	std::shared_ptr<LinphonePrivate::Address> to = LinphonePrivate::Address::create(op->getTo());
+	std::shared_ptr<LinphonePrivate::Address> from = LinphonePrivate::Address::create(op->getFrom());
 	if (sal_address_has_param(refer_to, "text")) {
-		if (addr.isValid()) {
+		if (referAddr && referAddr->isValid()) {
 
 			if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
 				static_cast<SalReferOp *>(op)->reply(SalReasonDeclined);
 				return;
 			}
 
-			if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) {
+			if (referAddr->hasUriParam("method") && (referAddr->getUriParamValue("method") == "BYE")) {
 				if (linphone_core_conference_server_enabled(lc)) {
 					// Removal of a participant at the server side
-					shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
-					    ConferenceId(ConferenceAddress(op->getTo()), ConferenceAddress(op->getTo())));
+					shared_ptr<AbstractChatRoom> chatRoom =
+					    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ConferenceId(to, to));
 					if (chatRoom) {
-						std::shared_ptr<Participant> participant =
-						    chatRoom->findParticipant(IdentityAddress(op->getFrom()));
+						std::shared_ptr<Participant> participant = chatRoom->findParticipant(from);
 						if (!participant || !participant->isAdmin()) {
 							static_cast<SalReferOp *>(op)->reply(SalReasonDeclined);
 							return;
 						}
-						participant = chatRoom->findParticipant(addr);
+						participant = chatRoom->findParticipant(referAddr);
 						if (participant) chatRoom->removeParticipant(participant);
 						static_cast<SalReferOp *>(op)->reply(SalReasonNone);
 						return;
 					}
 				} else {
 					// The server asks a participant to leave a chat room
-					LinphoneChatRoom *cr = L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
-					    ConferenceId(addr, IdentityAddress(op->getTo()))));
+					LinphoneChatRoom *cr =
+					    L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ConferenceId(referAddr, to)));
 					if (cr) {
 						L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave();
 						static_cast<SalReferOp *>(op)->reply(SalReasonNone);
@@ -1023,29 +997,29 @@ static void refer_received(SalOp *op, const SalAddress *refer_to) {
 			} else {
 				if (linphone_core_conference_server_enabled(lc)) {
 #ifdef HAVE_ADVANCED_IM
-					shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
-					    ConferenceId(ConferenceAddress(op->getTo()), ConferenceAddress(op->getTo())));
+					shared_ptr<AbstractChatRoom> chatRoom =
+					    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ConferenceId(to, to));
 					LinphoneChatRoom *cr = L_GET_C_BACK_PTR(chatRoom);
 					if (cr) {
-						Address fromAddr(op->getFrom());
-						shared_ptr<Participant> participant = chatRoom->findParticipant(fromAddr);
+						shared_ptr<Participant> participant = chatRoom->findParticipant(from);
 						if (!participant || !participant->isAdmin()) {
 							static_cast<SalReferOp *>(op)->reply(SalReasonForbidden);
 							return;
 						}
-						if (addr.hasParam("admin")) {
-							participant = chatRoom->findParticipant(addr);
+						if (referAddr->hasParam("admin")) {
+							participant = chatRoom->findParticipant(referAddr);
 							if (participant) {
-								bool value = Utils::stob(addr.getParamValue("admin"));
+								bool value = Utils::stob(referAddr->getParamValue("admin"));
 								chatRoom->setParticipantAdminStatus(participant, value);
 								static_cast<SalReferOp *>(op)->reply(SalReasonNone);
 								return;
 							}
 						} else {
-							participant = static_pointer_cast<ServerGroupChatRoom>(chatRoom)->findParticipant(addr);
+							participant =
+							    static_pointer_cast<ServerGroupChatRoom>(chatRoom)->findParticipant(referAddr);
 							if (!participant) {
-								bool ret = static_pointer_cast<ServerGroupChatRoom>(chatRoom)->addParticipant(
-								    IdentityAddress(addr));
+								bool ret =
+								    static_pointer_cast<ServerGroupChatRoom>(chatRoom)->addParticipant(referAddr);
 								static_cast<SalReferOp *>(op)->reply(ret ? SalReasonNone : SalReasonNotAcceptable);
 								return;
 							}
@@ -1058,27 +1032,25 @@ static void refer_received(SalOp *op, const SalAddress *refer_to) {
 			}
 		}
 	} else {
-		shared_ptr<MediaConference::Conference> conference = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(
-		    ConferenceId(ConferenceAddress(op->getTo()), ConferenceAddress(op->getTo())));
+		shared_ptr<MediaConference::Conference> conference =
+		    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(ConferenceId(to, to));
 
 		if (conference) {
-			Address fromAddr(op->getFrom());
-			auto from = conference->findParticipant(fromAddr);
-			if (!from || !from->isAdmin()) {
+			auto participant = conference->findParticipant(from);
+			if (!participant || !participant->isAdmin()) {
 				static_cast<SalReferOp *>(op)->reply(SalReasonForbidden);
 				return;
 			}
 
-			if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) {
-				auto participant = conference->findParticipant(IdentityAddress(op->getFrom()));
-				if (participant) conference->removeParticipant(addr);
+			if (referAddr->hasUriParam("method") && (referAddr->getUriParamValue("method") == "BYE")) {
+				if (participant) conference->removeParticipant(referAddr);
 				static_cast<SalReferOp *>(op)->reply(SalReasonNone);
 				return;
 			} else {
-				auto participant = conference->findParticipant(addr);
-				if (addr.hasParam("admin")) {
+				auto participant = conference->findParticipant(referAddr);
+				if (referAddr->hasParam("admin")) {
 					if (participant) {
-						bool value = Utils::stob(addr.getParamValue("admin"));
+						bool value = Utils::stob(referAddr->getParamValue("admin"));
 						conference->setParticipantAdminStatus(participant, value);
 						static_cast<SalReferOp *>(op)->reply(SalReasonNone);
 						return;
@@ -1086,7 +1058,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to) {
 				} else {
 					if (!participant) {
 						bool ret = static_pointer_cast<MediaConference::LocalConference>(conference)
-						               ->addParticipant(IdentityAddress(addr));
+						               ->addParticipant(referAddr);
 						static_cast<SalReferOp *>(op)->reply(ret ? SalReasonNone : SalReasonNotAcceptable);
 						return;
 					}
diff --git a/coreapi/chat.c b/coreapi/chat.c
index b7dd9b29cc4e70766b03c35f3b4fc1a660c59c02..d6ce2cd5bef01171a6d9184f7011defdaab4bc3b 100644
--- a/coreapi/chat.c
+++ b/coreapi/chat.c
@@ -20,14 +20,15 @@
 
 #include <bctoolbox/defs.h>
 
-#include <linphone/utils/utils.h>
-
 #include "belle-sip/belle-sip.h"
+
+#include "ortp/b64.h"
+
 #include "linphone/core.h"
 #include "linphone/lpconfig.h"
 #include "linphone/wrapper_utils.h"
-#include "ortp/b64.h"
 #include "private.h"
+#include <linphone/utils/utils.h>
 
 #include "c-wrapper/c-wrapper.h"
 #include "call/call.h"
@@ -138,18 +139,14 @@ LinphoneChatRoom *linphone_core_create_chat_room_6(LinphoneCore *lc,
 	shared_ptr<LinphonePrivate::ChatRoomParams> chatRoomParams =
 	    params ? LinphonePrivate::ChatRoomParams::toCpp(params)->clone()->toSharedPtr() : nullptr;
 	// If a participant has an invalid address, the pointer to its address is NULL.
-	// For the purpose of building an std::list from a bctbx_list_t, replace it by an empty IdentityAddress (that is
-	// invalid)
-	const list<LinphonePrivate::IdentityAddress> participantsList = L_GET_CPP_LIST_FROM_C_LIST_2(
-	    participants, LinphoneAddress *, LinphonePrivate::IdentityAddress, [](LinphoneAddress *addr) {
-		    return addr ? LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))
-		                : LinphonePrivate::IdentityAddress();
-	    });
+	// For the purpose of building an std::list from a bctbx_list_t, replace it by an empty Address (that is invalid)
+	const list<std::shared_ptr<LinphonePrivate::Address>> participantsList =
+	    LinphonePrivate::Address::getCppListFromCList(participants);
 	bool withGruu = chatRoomParams ? chatRoomParams->getChatRoomBackend() ==
 	                                     LinphonePrivate::ChatRoomParams::ChatRoomBackend::FlexisipChat
 	                               : false;
-	LinphonePrivate::IdentityAddress identityAddress =
-	    localAddr ? LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr))
+	shared_ptr<const LinphonePrivate::Address> identityAddress =
+	    localAddr ? LinphonePrivate::Address::toCpp(localAddr)->getSharedFromThis()
 	              : L_GET_PRIVATE_FROM_C_OBJECT(lc)->getDefaultLocalAddress(nullptr, withGruu);
 	shared_ptr<LinphonePrivate::AbstractChatRoom> room =
 	    L_GET_PRIVATE_FROM_C_OBJECT(lc)->createChatRoom(chatRoomParams, identityAddress, participantsList);
@@ -168,18 +165,16 @@ LinphoneChatRoom *linphone_core_search_chat_room(const LinphoneCore *lc,
                                                  const bctbx_list_t *participants) {
 	shared_ptr<LinphonePrivate::ChatRoomParams> chatRoomParams =
 	    params ? LinphonePrivate::ChatRoomParams::toCpp(params)->clone()->toSharedPtr() : nullptr;
-	const list<LinphonePrivate::IdentityAddress> participantsList = L_GET_CPP_LIST_FROM_C_LIST_2(
-	    participants, LinphoneAddress *, LinphonePrivate::IdentityAddress,
-	    [](LinphoneAddress *addr) { return LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)); });
+	const list<std::shared_ptr<LinphonePrivate::Address>> participantsList =
+	    LinphonePrivate::Address::getCppListFromCList(participants);
 	bool withGruu = chatRoomParams ? chatRoomParams->getChatRoomBackend() ==
 	                                     LinphonePrivate::ChatRoomParams::ChatRoomBackend::FlexisipChat
 	                               : false;
-	LinphonePrivate::IdentityAddress identityAddress =
-	    localAddr ? LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr))
+	shared_ptr<const LinphonePrivate::Address> identityAddress =
+	    localAddr ? LinphonePrivate::Address::toCpp(localAddr)->getSharedFromThis()
 	              : L_GET_PRIVATE_FROM_C_OBJECT(lc)->getDefaultLocalAddress(nullptr, withGruu);
-	LinphonePrivate::IdentityAddress remoteAddress =
-	    remoteAddr ? LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(remoteAddr))
-	               : LinphonePrivate::IdentityAddress();
+	shared_ptr<const LinphonePrivate::Address> remoteAddress =
+	    remoteAddr ? LinphonePrivate::Address::toCpp(remoteAddr)->getSharedFromThis() : nullptr;
 	shared_ptr<LinphonePrivate::AbstractChatRoom> room = L_GET_PRIVATE_FROM_C_OBJECT(lc)->searchChatRoom(
 	    chatRoomParams, identityAddress, remoteAddress, participantsList);
 	if (room) return L_GET_C_BACK_PTR(room);
diff --git a/coreapi/conference.cc b/coreapi/conference.cc
index 74b99fe4910cbad1b88beb3476c3708c0be3a5f7..e4c3d9e7d99fe02bdcc6ee0f61a5004a0902e3c3 100644
--- a/coreapi/conference.cc
+++ b/coreapi/conference.cc
@@ -24,6 +24,7 @@
 #include <typeinfo>
 
 #include <bctoolbox/defs.h>
+
 #include <mediastreamer2/msvolume.h>
 
 #include "linphone/core.h"
@@ -66,7 +67,7 @@ LINPHONE_BEGIN_NAMESPACE
 namespace MediaConference {
 
 Conference::Conference(const shared_ptr<Core> &core,
-                       const IdentityAddress &myAddress,
+                       const std::shared_ptr<Address> &myAddress,
                        CallSessionListener *listener,
                        const std::shared_ptr<LinphonePrivate::ConferenceParams> params)
     : LinphonePrivate::Conference(core, myAddress, listener, params) {
@@ -115,7 +116,7 @@ void Conference::setInputAudioDevice(const shared_ptr<AudioDevice> &audioDevice)
 		    currentInputDevice ? ((audioDevice != currentInputDevice) || (*audioDevice != *currentInputDevice)) : true;
 
 		if (!change) {
-			lInfo() << "Ignoring request to change input audio device of conference " << getConferenceAddress()
+			lInfo() << "Ignoring request to change input audio device of conference " << *getConferenceAddress()
 			        << " to [" << audioDevice->toString() << "] (" << audioDevice
 			        << ") because it is the same as the one currently used";
 			return;
@@ -125,20 +126,20 @@ void Conference::setInputAudioDevice(const shared_ptr<AudioDevice> &audioDevice)
 			AudioControlInterface *aci = getAudioControlInterface();
 			if (aci) {
 				lInfo() << "Set input audio device [" << audioDevice->toString() << "] (" << audioDevice
-				        << ") to audio control interface " << aci << " for conference " << getConferenceAddress();
+				        << ") to audio control interface " << aci << " for conference " << *getConferenceAddress();
 				aci->setInputDevice(audioDevice);
 				linphone_conference_notify_audio_device_changed(toC(), audioDevice->toC());
 			} else {
 				lError() << "Unable to set input audio device [" << audioDevice->toString() << "] (" << audioDevice
-				         << ") of conference " << getConferenceAddress() << " because audio control interface is NULL";
+				         << ") of conference " << *getConferenceAddress() << " because audio control interface is NULL";
 			}
 		} else {
 			lError() << "Unable to set input audio device to [" << audioDevice->toString() << "] (" << audioDevice
-			         << ") for conference " << getConferenceAddress() << " due to missing record capability";
+			         << ") for conference " << *getConferenceAddress() << " due to missing record capability";
 		}
 	} else {
 		lError() << "Unable to set undefined input audio device (" << audioDevice << ") for conference "
-		         << getConferenceAddress();
+		         << *getConferenceAddress();
 	}
 }
 
@@ -152,7 +153,7 @@ void Conference::setOutputAudioDevice(const shared_ptr<AudioDevice> &audioDevice
 		                  : true;
 
 		if (!change) {
-			lInfo() << "Ignoring request to change output audio device of conference " << getConferenceAddress()
+			lInfo() << "Ignoring request to change output audio device of conference " << *getConferenceAddress()
 			        << " to [" << audioDevice->toString() << "] (" << audioDevice
 			        << ") because it is the same as the one currently used";
 			return;
@@ -161,20 +162,20 @@ void Conference::setOutputAudioDevice(const shared_ptr<AudioDevice> &audioDevice
 			AudioControlInterface *aci = getAudioControlInterface();
 			if (aci) {
 				lInfo() << "Set output audio device [" << audioDevice->toString() << "] (" << audioDevice
-				        << ") to audio control interface " << aci << " for conference " << getConferenceAddress();
+				        << ") to audio control interface " << aci << " for conference " << *getConferenceAddress();
 				aci->setOutputDevice(audioDevice);
 				linphone_conference_notify_audio_device_changed(toC(), audioDevice->toC());
 			} else {
 				lError() << "Unable to set output audio device [" << audioDevice->toString() << "] (" << audioDevice
-				         << ") of conference " << getConferenceAddress() << " because audio control interface is NULL";
+				         << ") of conference " << *getConferenceAddress() << " because audio control interface is NULL";
 			}
 		} else {
 			lError() << "Unable to set output audio device to [" << audioDevice->toString() << "] (" << audioDevice
-			         << ") for conference " << getConferenceAddress() << " due to missing play capability";
+			         << ") for conference " << *getConferenceAddress() << " due to missing play capability";
 		}
 	} else {
 		lError() << "Unable to set undefined output audio device (" << audioDevice << ") for conference "
-		         << getConferenceAddress();
+		         << *getConferenceAddress();
 	}
 }
 
@@ -185,7 +186,7 @@ shared_ptr<AudioDevice> Conference::getInputAudioDevice() const {
 	}
 
 	lError() << "Unable to retrieve input audio device from undefined audio control interface of conference "
-	         << getConferenceAddress();
+	         << *getConferenceAddress();
 	return nullptr;
 }
 
@@ -196,14 +197,14 @@ shared_ptr<AudioDevice> Conference::getOutputAudioDevice() const {
 	}
 
 	lError() << "Unable to retrieve output audio device from undefined audio control interface of conference "
-	         << getConferenceAddress();
+	         << *getConferenceAddress();
 	return nullptr;
 }
 
-void Conference::setConferenceAddress(const ConferenceAddress &conferenceAddress) {
+void Conference::setConferenceAddress(const std::shared_ptr<Address> &conferenceAddress) {
 	if ((getState() == ConferenceInterface::State::Instantiated) ||
 	    (getState() == ConferenceInterface::State::CreationPending)) {
-		if (!conferenceAddress.isValid()) {
+		if (!conferenceAddress || !conferenceAddress->isValid()) {
 			lError() << "Cannot set the conference address to " << conferenceAddress;
 			shared_ptr<CallSession> session = getMe()->getSession();
 			LinphoneErrorInfo *ei = linphone_error_info_new();
@@ -216,7 +217,7 @@ void Conference::setConferenceAddress(const ConferenceAddress &conferenceAddress
 
 		LinphonePrivate::Conference::setConferenceAddress(conferenceAddress);
 		setState(ConferenceInterface::State::CreationPending);
-		lInfo() << "Conference " << this << " has been given the address " << conferenceAddress.asString();
+		lInfo() << "Conference " << this << " has been given the address " << conferenceAddress;
 	} else {
 		lDebug() << "Cannot set the conference address of the Conference in state " << getState() << " to "
 		         << conferenceAddress;
@@ -244,25 +245,27 @@ bool Conference::isConferenceStarted() const {
 	return conferenceStarted;
 }
 
-bool Conference::addParticipant(const IdentityAddress &participantAddress) {
+bool Conference::addParticipant(const std::shared_ptr<Address> &participantAddress) {
 	bool success = LinphonePrivate::Conference::addParticipant(participantAddress);
 
+	const auto conferenceAddressStr =
+	    (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<address-not-defined>"));
 	if (success == true) {
-		lInfo() << "Participant with address " << participantAddress << " has been added to conference "
-		        << getConferenceAddress();
+		lInfo() << "Participant with address " << *participantAddress << " has been added to conference "
+		        << conferenceAddressStr;
 		time_t creationTime = time(nullptr);
 		std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(participantAddress);
 		notifyParticipantAdded(creationTime, false, p);
 	} else {
-		lError() << "Unable to add participant with address " << participantAddress << " to conference "
-		         << getConferenceAddress();
+		lError() << "Unable to add participant with address " << *participantAddress << " to conference "
+		         << conferenceAddressStr;
 	}
 
 	return success;
 }
 
 bool Conference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call) {
-	const Address &remoteAddress = *call->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = call->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	bool success = false;
 	// Add a new participant only if it is not in the conference
@@ -270,24 +273,24 @@ bool Conference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call) {
 		auto session = call->getActiveSession();
 		p = Participant::create(this, remoteAddress);
 		p->setFocus(false);
-		Address toAddr;
+		std::shared_ptr<Address> toAddr;
 		if (session) {
 			auto op = session->getPrivate()->getOp();
 			if (op) {
-				toAddr = Address(op->getTo());
+				toAddr = Address::create(op->getTo());
 			}
 		}
-		if (toAddr.isValid()) {
-			p->setPreserveSession(!toAddr.hasUriParam("conf-id"));
+		if (toAddr && toAddr->isValid()) {
+			p->setPreserveSession(!toAddr->hasUriParam("conf-id"));
 		} else {
 			p->setPreserveSession(true);
 		}
 
 		// Pass admin information on if it is available in the contact address
-		Address remoteContactAddress(call->getRemoteContact());
+		std::shared_ptr<Address> remoteContactAddress = Address::create(call->getRemoteContact());
 
-		if (remoteContactAddress.hasParam("admin")) {
-			bool value = Utils::stob(remoteContactAddress.getParamValue("admin"));
+		if (remoteContactAddress->hasParam("admin")) {
+			bool value = Utils::stob(remoteContactAddress->getParamValue("admin"));
 			p->setAdmin(value);
 		}
 		participants.push_back(p);
@@ -296,8 +299,8 @@ bool Conference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call) {
 		notifyParticipantAdded(creationTime, false, p);
 		success = true;
 	} else {
-		lWarning() << "Participant with address " << call->getRemoteAddress()->asString()
-		           << " is already part of conference " << getConferenceAddress();
+		lWarning() << "Participant with address " << call->getRemoteAddress()->toString()
+		           << " is already part of conference " << *getConferenceAddress();
 		success = false;
 	}
 
@@ -307,7 +310,7 @@ bool Conference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call) {
 }
 
 bool Conference::addParticipantDevice(std::shared_ptr<LinphonePrivate::Call> call) {
-	const Address &remoteAddress = *call->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = call->getRemoteAddress();
 	auto p = findParticipant(remoteAddress);
 	if (p) {
 		const auto &session = call->getActiveSession();
@@ -316,13 +319,13 @@ bool Conference::addParticipantDevice(std::shared_ptr<LinphonePrivate::Call> cal
 			shared_ptr<ParticipantDevice> device = p->addDevice(session);
 			// If there is already a call for this participant, then he/she is joining the conference
 			device->setState(ParticipantDevice::State::Joining);
-			lInfo() << "Participant with address " << call->getRemoteAddress()->asString()
-			        << " has added device with session " << session << " (address " << device->getAddress()
-			        << ") to conference " << getConferenceAddress();
+			lInfo() << "Participant with address " << call->getRemoteAddress()->toString()
+			        << " has added device with session " << session << " (address " << *device->getAddress()
+			        << ") to conference " << *getConferenceAddress();
 			return true;
 		} else {
-			lDebug() << "Participant with address " << call->getRemoteAddress()->asString() << " to conference "
-			         << getConferenceAddress() << " has already a device with session " << session;
+			lDebug() << "Participant with address " << call->getRemoteAddress()->toString() << " to conference "
+			         << *getConferenceAddress() << " has already a device with session " << session;
 		}
 	}
 
@@ -330,7 +333,7 @@ bool Conference::addParticipantDevice(std::shared_ptr<LinphonePrivate::Call> cal
 }
 
 int Conference::removeParticipantDevice(const std::shared_ptr<LinphonePrivate::CallSession> &session) {
-	const Address &remoteAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	if (p) {
 		std::shared_ptr<ParticipantDevice> device = p->findDevice(session);
@@ -352,8 +355,8 @@ int Conference::removeParticipantDevice(const std::shared_ptr<LinphonePrivate::C
 			time_t creationTime = time(nullptr);
 			notifyParticipantDeviceRemoved(creationTime, false, p, device);
 
-			lInfo() << "Removing device with session " << session << " from participant " << p->getAddress()
-			        << " in conference " << getConferenceAddress();
+			lInfo() << "Removing device with session " << session << " from participant " << *p->getAddress()
+			        << " in conference " << *getConferenceAddress();
 			p->removeDevice(session);
 
 			auto op = session->getPrivate()->getOp();
@@ -369,7 +372,7 @@ int Conference::removeParticipantDevice(const std::shared_ptr<LinphonePrivate::C
 }
 
 int Conference::removeParticipant(std::shared_ptr<LinphonePrivate::Call> call) {
-	const Address &remoteAddress = *call->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = call->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	if (!p) {
 		lDebug() << "Unable to participant with address " << remoteAddress;
@@ -380,16 +383,16 @@ int Conference::removeParticipant(std::shared_ptr<LinphonePrivate::Call> call) {
 
 int Conference::removeParticipant(const std::shared_ptr<LinphonePrivate::CallSession> &session,
                                   BCTBX_UNUSED(const bool preserveSession)) {
-	const Address &pAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &pAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(pAddress);
 	removeParticipantDevice(session);
 	if (!p) {
-		lInfo() << "Participant removal failed: Participant with address " << pAddress
-		        << " has not been found in conference " << getConferenceAddress();
+		lInfo() << "Participant removal failed: Participant with address " << *pAddress
+		        << " has not been found in conference " << *getConferenceAddress();
 		return -1;
 	}
 	if (p->getDevices().empty()) {
-		lInfo() << "Remove participant with address " << pAddress << " from conference " << getConferenceAddress();
+		lInfo() << "Remove participant with address " << *pAddress << " from conference " << *getConferenceAddress();
 		participants.remove(p);
 		time_t creationTime = time(nullptr);
 		notifyParticipantRemoved(creationTime, false, p);
@@ -398,15 +401,15 @@ int Conference::removeParticipant(const std::shared_ptr<LinphonePrivate::CallSes
 	return -1;
 }
 
-int Conference::removeParticipant(const IdentityAddress &addr) {
+int Conference::removeParticipant(const std::shared_ptr<Address> &addr) {
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(addr);
 	return removeParticipant(p);
 }
 
 bool Conference::removeParticipant(const std::shared_ptr<LinphonePrivate::Participant> &participant) {
 	if (!participant) return false;
-	lInfo() << "Removing participant with address " << participant->getAddress() << " from conference "
-	        << getConferenceAddress();
+	lInfo() << "Removing participant with address " << *participant->getAddress() << " from conference "
+	        << *getConferenceAddress();
 	// Delete all devices of a participant
 	auto deviceIt = participant->getDevices().begin();
 	while (deviceIt != participant->getDevices().end()) {
@@ -479,7 +482,7 @@ void Conference::notifyStateChanged(LinphonePrivate::ConferenceInterface::State
 	LinphonePrivate::Conference::notifyStateChanged(state);
 }
 
-void Conference::onConferenceTerminated(BCTBX_UNUSED(const IdentityAddress &addr)) {
+void Conference::onConferenceTerminated(BCTBX_UNUSED(const std::shared_ptr<Address> &addr)) {
 	// Keep a reference to the conference to be able to set the state to Deleted
 	shared_ptr<Conference> ref = getSharedFromThis();
 	// If core is in Global Shutdown state, then do not remove it from the map as it will be freed by Core::uninit()
@@ -493,7 +496,7 @@ void Conference::setParticipantAdminStatus(
     BCTBX_UNUSED(const std::shared_ptr<LinphonePrivate::Participant> &participant), BCTBX_UNUSED(bool isAdmin)) {
 }
 
-void Conference::join(BCTBX_UNUSED(const IdentityAddress &participantAddress)) {
+void Conference::join(BCTBX_UNUSED(const std::shared_ptr<Address> &participantAddress)) {
 }
 
 void Conference::join() {
@@ -525,7 +528,7 @@ void Conference::transferStateChanged(LinphoneCore *lc, LinphoneCall *transfered
 }
 
 LocalConference::LocalConference(const shared_ptr<Core> &core,
-                                 const IdentityAddress &myAddress,
+                                 const std::shared_ptr<Address> &myAddress,
                                  CallSessionListener *listener,
                                  const std::shared_ptr<LinphonePrivate::ConferenceParams> params)
     : Conference(core, myAddress, listener, params) {
@@ -557,7 +560,7 @@ LocalConference::LocalConference(const shared_ptr<Core> &core,
 
 	// Update proxy contact address to add conference ID
 	// Do not use myAddress directly as it may lack some parameter like gruu
-	LinphoneAddress *cAddress = L_GET_C_BACK_PTR(&(myAddress.asAddress()));
+	LinphoneAddress *cAddress = myAddress->toC();
 	LinphoneAccount *account = linphone_core_lookup_known_account(core->getCCore(), cAddress);
 	char *contactAddressStr = nullptr;
 	if (account && Account::toCpp(account)->getOp()) {
@@ -566,10 +569,10 @@ LocalConference::LocalConference(const shared_ptr<Core> &core,
 		contactAddressStr =
 		    ms_strdup(linphone_core_find_best_identity(core->getCCore(), const_cast<LinphoneAddress *>(cAddress)));
 	}
-	Address contactAddress(contactAddressStr);
+	std::shared_ptr<Address> contactAddress = Address::create(contactAddressStr);
 	char confId[LinphonePrivate::MediaConference::LocalConference::confIdLength];
 	belle_sip_random_token(confId, sizeof(confId));
-	contactAddress.setUriParam("conf-id", confId);
+	contactAddress->setUriParam("conf-id", confId);
 	if (contactAddressStr) {
 		ms_free(contactAddressStr);
 	}
@@ -584,7 +587,7 @@ LocalConference::LocalConference(const shared_ptr<Core> &core,
 }
 
 LocalConference::LocalConference(const std::shared_ptr<Core> &core, SalCallOp *op)
-    : Conference(core, ConferenceAddress(op->getTo()), nullptr, ConferenceParams::create(core->getCCore())) {
+    : Conference(core, Address::create(op->getTo()), nullptr, ConferenceParams::create(core->getCCore())) {
 
 #ifdef HAVE_ADVANCED_IM
 	LinphoneCore *lc = core->getCCore();
@@ -621,18 +624,19 @@ void LocalConference::updateConferenceInformation(SalCallOp *op) {
 	auto remoteContact = op->getRemoteContactAddress();
 	if (remoteContact) {
 		char *salAddress = sal_address_as_string(remoteContact);
-		Address address = Address(std::string(salAddress));
+		std::shared_ptr<Address> address = Address::create(std::string(salAddress));
 		if (salAddress) {
 			ms_free(salAddress);
 		}
 		auto invited = std::find_if(invitedAddresses.begin(), invitedAddresses.end(), [&address](const auto &invitee) {
-			               return address.weakEqual(invitee.asAddress());
+			               return address->weakEqual(*invitee);
 		               }) != invitedAddresses.end();
 
-		auto remoteAddress = IdentityAddress((op->getDir() == SalOp::Dir::Incoming) ? op->getFrom() : op->getTo());
+		std::shared_ptr<Address> remoteAddress =
+		    Address::create((op->getDir() == SalOp::Dir::Incoming) ? op->getFrom() : op->getTo());
 
-		if (findParticipantDevice(remoteAddress, address) || invited || address.weakEqual(organizer.asAddress())) {
-			lInfo() << "Updating conference informations of conference " << getConferenceAddress();
+		if (findParticipantDevice(remoteAddress, address) || invited || address->weakEqual(*organizer)) {
+			lInfo() << "Updating conference informations of conference " << *getConferenceAddress();
 			const auto &remoteMd = op->getRemoteMediaDescription();
 
 			const auto times = remoteMd->times;
@@ -707,7 +711,7 @@ void LocalConference::updateConferenceInformation(SalCallOp *op) {
 			if (mainDb) {
 				lInfo()
 				    << "Inserting conference information to database in order to be able to recreate the conference "
-				    << getConferenceAddress() << " in case of restart";
+				    << *getConferenceAddress() << " in case of restart";
 				mainDb->insertConferenceInfo(conferenceInfo);
 			}
 #endif
@@ -722,7 +726,7 @@ void LocalConference::updateConferenceInformation(SalCallOp *op) {
 			lWarning() << "Device with address " << address
 			           << " is not allowed to update the conference because they have not been invited nor are "
 			              "participants to conference "
-			           << getConferenceAddress() << " nor are the organizer";
+			           << *getConferenceAddress() << " nor are the organizer";
 		}
 	}
 }
@@ -736,7 +740,7 @@ void LocalConference::configure(SalCallOp *op) {
 #ifdef HAVE_DB_STORAGE
 	auto &mainDb = getCore()->getPrivate()->mainDb;
 	if (mainDb) {
-		info = getCore()->getPrivate()->mainDb->getConferenceInfoFromURI(Address(op->getTo()));
+		info = getCore()->getPrivate()->mainDb->getConferenceInfoFromURI(Address::create(op->getTo()));
 	}
 #endif // HAVE_DB_STORAGE
 
@@ -770,7 +774,7 @@ void LocalConference::configure(SalCallOp *op) {
 		if (!op->getSubject().empty()) {
 			subject = op->getSubject();
 		}
-		organizer = IdentityAddress(op->getFrom());
+		organizer = Address::create(op->getFrom());
 
 		startTime = startTimeSdp;
 		if (startTime <= 0) {
@@ -826,7 +830,8 @@ void LocalConference::configure(SalCallOp *op) {
 	if (!isUpdate && !info) {
 		// Set joining mode only when creating a conference
 		bool immediateStart = (startTimeSdp < 0);
-		const auto joiningMode = (immediateStart) ? ConferenceParams::JoiningMode::DialOut : ConferenceParams::JoiningMode::DialIn;
+		const auto joiningMode =
+		    (immediateStart) ? ConferenceParams::JoiningMode::DialOut : ConferenceParams::JoiningMode::DialIn;
 		confParams->setJoiningMode(joiningMode);
 	}
 
@@ -838,14 +843,14 @@ void LocalConference::configure(SalCallOp *op) {
 		msp.getPrivate()->setStartTime(startTime);
 		msp.getPrivate()->setEndTime(endTime);
 
-		Address conferenceAddress;
+		std::shared_ptr<Address> conferenceAddress;
 		if (info) {
-			conferenceAddress = info->getUri().asAddress();
+			conferenceAddress = info->getUri();
 		} else if (admin) {
-			conferenceAddress = Address(op->getTo());
+			conferenceAddress = Address::create(op->getTo());
 		}
 		shared_ptr<CallSession> session = getMe()->createSession(*this, &msp, true, nullptr);
-		session->configure(LinphoneCallIncoming, nullptr, op, organizer.asAddress(), conferenceAddress);
+		session->configure(LinphoneCallIncoming, nullptr, op, organizer, conferenceAddress);
 	}
 
 	getMe()->setAdmin(true);
@@ -867,9 +872,10 @@ void LocalConference::configure(SalCallOp *op) {
 	}
 }
 
-std::list<IdentityAddress> LocalConference::getAllowedAddresses() const {
+std::list<std::shared_ptr<Address>> LocalConference::getAllowedAddresses() const {
 	auto allowedAddresses = invitedAddresses;
-	auto organizerIt = std::find(invitedAddresses.begin(), invitedAddresses.end(), organizer);
+	auto organizerIt = std::find_if(invitedAddresses.begin(), invitedAddresses.end(),
+	                                [this](const auto &address) { return address->weakEqual(*organizer); });
 	if (organizerIt == invitedAddresses.end()) {
 		allowedAddresses.push_back(organizer);
 	}
@@ -895,16 +901,22 @@ void LocalConference::confirmCreation() {
 		/* Assign a random conference address to this new conference, with domain
 		 * set according to the proxy config used to receive the INVITE.
 		 */
-		LinphoneProxyConfig *cfg = session->getPrivate()->getDestProxy();
-		if (!cfg) cfg = linphone_core_get_default_proxy_config(L_GET_C_BACK_PTR(getCore()));
-		LinphoneAddress *addr = linphone_address_clone(linphone_proxy_config_get_identity_address(cfg));
+		auto account = session->getPrivate()->getDestAccount();
+		if (!account) {
+			const auto cAccount = linphone_core_get_default_account(getCore()->getCCore());
+			if (cAccount) {
+				account = Account::toCpp(cAccount)->getSharedFromThis();
+			}
+		}
 
 		char confId[LinphonePrivate::MediaConference::LocalConference::confIdLength];
-		belle_sip_random_token(confId, sizeof(confId));
-		linphone_address_set_uri_param(addr, "conf-id", confId);
-		Address conferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr));
-		linphone_address_unref(addr);
-		setConferenceId(ConferenceId(conferenceAddress, conferenceAddress));
+		if (account) {
+			const auto accountParams = account->getAccountParams();
+			std::shared_ptr<Address> conferenceAddress = accountParams->getIdentityAddress()->clone()->toSharedPtr();
+			belle_sip_random_token(confId, sizeof(confId));
+			conferenceAddress->setUriParam("conf-id", confId);
+			setConferenceId(ConferenceId(conferenceAddress, conferenceAddress));
+		}
 
 		const_cast<LinphonePrivate::CallSessionParamsPrivate *>(L_GET_PRIVATE(session->getParams()))
 		    ->setInConference(true);
@@ -913,13 +925,20 @@ void LocalConference::confirmCreation() {
 
 		const auto &conferenceInfo = createOrGetConferenceInfo();
 #ifdef HAVE_DB_STORAGE
-		// 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() << "Inserting conference information to database in order to be able to recreate the conference "
-			        << getConferenceAddress() << " in case of restart";
-			mainDb->insertConferenceInfo(conferenceInfo);
+		/// Method startIncomingNotification can move the conference to the CreationFailed state if the organizer
+		/// doesn't have any of the codecs the server supports
+		if (getState() != ConferenceInterface::State::CreationFailed) {
+			// 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) {
+				const auto conferenceAddressStr = (getConferenceAddress() ? getConferenceAddress()->toString()
+				                                                          : std::string("<address-not-defined>"));
+				lInfo()
+				    << "Inserting conference information to database in order to be able to recreate the conference "
+				    << conferenceAddressStr << " in case of restart";
+				mainDb->insertConferenceInfo(conferenceInfo);
+			}
 		}
 #endif
 		auto callLog = session->getLog();
@@ -944,13 +963,14 @@ std::shared_ptr<ConferenceInfo> LocalConference::createOrGetConferenceInfo() con
 	}
 #endif // HAVE_DB_STORAGE
 
-	std::list<IdentityAddress> participantAddresses;
+	std::list<std::shared_ptr<Address>> participantAddresses;
 	if (!invitedAddresses.empty()) {
 		participantAddresses = invitedAddresses;
 	}
 	for (const auto &p : getParticipants()) {
 		const auto &pAddress = p->getAddress();
-		auto pIt = std::find(participantAddresses.begin(), participantAddresses.end(), pAddress);
+		auto pIt = std::find_if(participantAddresses.begin(), participantAddresses.end(),
+		                        [&pAddress](const auto &address) { return address->weakEqual(*pAddress); });
 		if (pIt == participantAddresses.end()) {
 			participantAddresses.push_back(pAddress);
 		}
@@ -961,7 +981,7 @@ std::shared_ptr<ConferenceInfo> LocalConference::createOrGetConferenceInfo() con
 
 void LocalConference::finalizeCreation() {
 	if (getState() == ConferenceInterface::State::CreationPending) {
-		const ConferenceAddress &conferenceAddress = getConferenceAddress();
+		const std::shared_ptr<Address> &conferenceAddress = getConferenceAddress();
 		setConferenceId(ConferenceId(conferenceAddress, conferenceAddress));
 		shared_ptr<CallSession> session = me->getSession();
 		if (session) {
@@ -979,7 +999,7 @@ void LocalConference::finalizeCreation() {
 			}
 
 			if (!createdConference) {
-				Address addr(conferenceAddress.asAddress());
+				auto addr = *conferenceAddress;
 				addr.setParam("isfocus");
 				if (session->getState() == CallSession::State::Idle) {
 					lInfo() << " Scheduling redirection to [" << addr << "] for Call session [" << session << "]";
@@ -1005,17 +1025,10 @@ void LocalConference::subscribeReceived(shared_ptr<EventSubscribe> event) {
 			// A client joins when the conference receives the SUBSCRIBE. This allows to ensure that no NOTIFY is missed
 			// and we don't have to necessarely wait for the client reINVITE or ICE reINVITE to start sending NOTIFYs
 			// regarding the conference to him/her
-			const LinphoneAddress *lAddr = event->getFrom();
-			char *addrStr = linphone_address_as_string(lAddr);
-			Address participantAddress(addrStr);
-			bctbx_free(addrStr);
-
+			const auto &participantAddress = event->getFrom();
 			auto participant = findParticipant(participantAddress);
 			if (participant) {
-				const LinphoneAddress *lContactAddr = event->getRemoteContact();
-				char *contactAddrStr = linphone_address_as_string(lContactAddr);
-				IdentityAddress contactAddr(contactAddrStr);
-				bctbx_free(contactAddrStr);
+				const auto &contactAddr = event->getRemoteContact();
 				auto device = participant->findDevice(contactAddr);
 				if (device) {
 					participantDeviceJoined(participant, device);
@@ -1041,7 +1054,7 @@ void LocalConference::setParticipantAdminStatus(const shared_ptr<Participant> &p
 	}
 }
 
-void LocalConference::onConferenceTerminated(const IdentityAddress &addr) {
+void LocalConference::onConferenceTerminated(const std::shared_ptr<Address> &addr) {
 #ifdef HAVE_ADVANCED_IM
 	if (eventHandler) {
 		eventHandler->setConference(nullptr);
@@ -1096,7 +1109,8 @@ void LocalConference::addLocalEndpoint() {
 	}
 }
 
-int LocalConference::inviteAddresses(const list<const LinphoneAddress *> &addresses, const LinphoneCallParams *params) {
+int LocalConference::inviteAddresses(const list<std::shared_ptr<Address>> &addresses,
+                                     const LinphoneCallParams *params) {
 
 	const auto &coreCurrentCall = getCore()->getCurrentCall();
 	const bool startingConference = (getState() == ConferenceInterface::State::CreationPending);
@@ -1107,10 +1121,7 @@ int LocalConference::inviteAddresses(const list<const LinphoneAddress *> &addres
 	auto lc = getCore()->getCCore();
 
 	for (const auto &address : addresses) {
-		LinphoneCall *call = nullptr;
-		char *cAddress = linphone_address_as_string(address);
-		Address cppAddress(cAddress);
-		free(cAddress);
+		std::shared_ptr<Call> call = nullptr;
 
 		/*
 		 * In the case of a conference server, it is enough to look if there is already a participant with the same
@@ -1123,27 +1134,27 @@ int LocalConference::inviteAddresses(const list<const LinphoneAddress *> &addres
 		 * Note that this scenario is not possible for a conference server as it is a passive component.
 		 */
 		if (linphone_core_conference_server_enabled(lc)) {
-			auto participant = findParticipant(cppAddress);
+			auto participant = findParticipant(address);
 			if (participant) {
 				const auto &devices = participant->getDevices();
 				if (!devices.empty()) {
 					const auto &device = devices.front();
 					if (!device->getCallId().empty()) {
-						call = linphone_core_get_call_by_callid(lc, device->getCallId().c_str());
+						call = getCore()->getCallByCallId(device->getCallId());
 					} else if (device->getSession()) {
 						const auto &session = device->getSession();
 						const auto &calls = getCore()->getCalls();
-						auto it = std::find_if(calls.cbegin(), calls.cend(), [&session](const auto &call) {
-							return (call->getActiveSession() == session);
+						auto it = std::find_if(calls.cbegin(), calls.cend(), [&session](const auto &c) {
+							return (c->getActiveSession() == session);
 						});
 						if (it != calls.cend()) {
-							call = (*it)->toC();
+							call = (*it);
 						}
 					}
 				}
 			}
 		} else {
-			call = linphone_core_get_call_by_remote_address2(lc, address);
+			call = getCore()->getCallByRemoteAddress(address);
 		}
 		if (!call) {
 			/* Start a new call by indicating that it has to be put into the conference directly */
@@ -1158,22 +1169,22 @@ int LocalConference::inviteAddresses(const list<const LinphoneAddress *> &addres
 			linphone_call_params_set_in_conference(new_params, TRUE);
 			linphone_call_params_set_start_time(new_params, confParams->getStartTime());
 
-			const Address &conferenceAddress = getConferenceAddress().asAddress();
-			const string &confId = conferenceAddress.getUriParamValue("conf-id");
+			const std::shared_ptr<Address> &conferenceAddress = getConferenceAddress();
+			const string &confId = conferenceAddress->getUriParamValue("conf-id");
 			linphone_call_params_set_conference_id(new_params, confId.c_str());
 
-			call = linphone_core_invite_address_with_params_2(lc, address, new_params,
-			                                                  L_STRING_TO_C(confParams->getSubject()), NULL);
+			call = Call::toCpp(linphone_core_invite_address_with_params_2(
+			                       lc, address->toC(), new_params, L_STRING_TO_C(confParams->getSubject()), NULL))
+			           ->getSharedFromThis();
 
 			if (!confParams->getAccount()) {
 				// Set proxy configuration used for the conference
-				auto callProxyCfg = linphone_call_get_dest_proxy(call);
-				if (callProxyCfg) {
-					auto callAccount = linphone_core_lookup_account_by_identity(
-					    lc, linphone_proxy_config_get_identity_address(callProxyCfg));
+				auto callAccount = call->getDestAccount();
+				if (callAccount) {
 					confParams->setAccount(callAccount);
 				} else {
-					confParams->setAccount(linphone_core_lookup_known_account(lc, address));
+					confParams->setAccount(
+					    Account::toCpp(linphone_core_lookup_known_account(lc, address->toC()))->getSharedFromThis());
 				}
 			}
 
@@ -1182,22 +1193,22 @@ int LocalConference::inviteAddresses(const list<const LinphoneAddress *> &addres
 			if (!call) {
 				lError() << "LocalConference::inviteAddresses(): could not invite participant";
 			} else {
-				addParticipant(Call::toCpp(call)->getSharedFromThis());
-				auto participant = findParticipant(cppAddress);
+				addParticipant(call);
+				auto participant = findParticipant(address);
 				participant->setPreserveSession(false);
 			}
 			linphone_call_params_unref(new_params);
 		} else {
 			/* There is already a call to this address, so simply join it to the local conference if not already done */
-			if (!linphone_call_params_get_in_conference(linphone_call_get_current_params(call))) {
-				addParticipant(Call::toCpp(call)->getSharedFromThis());
-				auto participant = findParticipant(cppAddress);
+			if (!call->getCurrentParams()->getPrivate()->getInConference()) {
+				addParticipant(call);
+				auto participant = findParticipant(address);
 				participant->setPreserveSession(true);
 			}
 		}
 		/* If the local participant is not yet created, created it and it to the conference */
 		addLocalEndpoint();
-		Call::toCpp(call)->setConference(toC());
+		call->setConference(toC());
 	}
 
 	// If current call is not NULL and the conference is in the creating pending state or instantied, then try to change
@@ -1215,7 +1226,7 @@ int LocalConference::inviteAddresses(const list<const LinphoneAddress *> &addres
 }
 
 int LocalConference::participantDeviceAlerting(const std::shared_ptr<LinphonePrivate::CallSession> &session) {
-	const Address &remoteAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	if (p) {
 		std::shared_ptr<ParticipantDevice> device = p->findDevice(session);
@@ -1223,8 +1234,8 @@ int LocalConference::participantDeviceAlerting(const std::shared_ptr<LinphonePri
 			return participantDeviceAlerting(p, device);
 		} else {
 			lDebug() << "Participant alerting: Unable to find device with session " << session
-			         << " among devices of participant " << p->getAddress().asString() << " of conference "
-			         << getConferenceAddress();
+			         << " among devices of participant " << p->getAddress()->toString() << " of conference "
+			         << *getConferenceAddress();
 		}
 	}
 	return -1;
@@ -1233,7 +1244,7 @@ int LocalConference::participantDeviceAlerting(const std::shared_ptr<LinphonePri
 int LocalConference::participantDeviceAlerting(
     BCTBX_UNUSED(const std::shared_ptr<LinphonePrivate::Participant> &participant),
     const std::shared_ptr<LinphonePrivate::ParticipantDevice> &device) {
-	lInfo() << "Device " << device->getAddress() << " changed state to alerting";
+	lInfo() << "Device " << *device->getAddress() << " changed state to alerting";
 	device->updateMediaCapabilities();
 	device->updateStreamAvailabilities();
 	device->setState(ParticipantDevice::State::Alerting);
@@ -1241,7 +1252,7 @@ int LocalConference::participantDeviceAlerting(
 }
 
 int LocalConference::participantDeviceJoined(const std::shared_ptr<LinphonePrivate::CallSession> &session) {
-	const Address &remoteAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	if (p) {
 		std::shared_ptr<ParticipantDevice> device = p->findDevice(session);
@@ -1249,8 +1260,8 @@ int LocalConference::participantDeviceJoined(const std::shared_ptr<LinphonePriva
 			return participantDeviceJoined(p, device);
 		} else {
 			lDebug() << "Participant joined: Unable to find device with session " << session
-			         << " among devices of participant " << p->getAddress().asString() << " of conference "
-			         << getConferenceAddress();
+			         << " among devices of participant " << p->getAddress()->toString() << " of conference "
+			         << *getConferenceAddress();
 		}
 	}
 	return -1;
@@ -1262,7 +1273,7 @@ int LocalConference::participantDeviceJoined(
 	int success = -1;
 	if ((device->updateMediaCapabilities() || (device->getState() != ParticipantDevice::State::Present)) &&
 	    (getState() == ConferenceInterface::State::Created)) {
-		lInfo() << "Device " << device->getAddress() << " joined conference " << getConferenceAddress();
+		lInfo() << "Device " << *device->getAddress() << " joined conference " << *getConferenceAddress();
 		device->updateMediaCapabilities();
 		device->updateStreamAvailabilities();
 		device->setState(ParticipantDevice::State::Present);
@@ -1272,7 +1283,7 @@ int LocalConference::participantDeviceJoined(
 }
 
 int LocalConference::participantDeviceLeft(const std::shared_ptr<LinphonePrivate::CallSession> &session) {
-	const Address &remoteAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	if (p) {
 		std::shared_ptr<ParticipantDevice> device = p->findDevice(session);
@@ -1280,8 +1291,8 @@ int LocalConference::participantDeviceLeft(const std::shared_ptr<LinphonePrivate
 			return participantDeviceLeft(p, device);
 		} else {
 			lWarning() << "Participant left: Unable to find device with session " << session
-			           << " among devices of participant " << p->getAddress().asString() << " of conference "
-			           << getConferenceAddress();
+			           << " among devices of participant " << p->getAddress()->toString() << " of conference "
+			           << *getConferenceAddress();
 		}
 	}
 	return -1;
@@ -1293,7 +1304,7 @@ int LocalConference::participantDeviceLeft(
 	int success = -1;
 	if ((device->updateMediaCapabilities() || (device->getState() != ParticipantDevice::State::OnHold)) &&
 	    (getState() == ConferenceInterface::State::Created)) {
-		lInfo() << "Device " << device->getAddress() << " left conference " << getConferenceAddress();
+		lInfo() << "Device " << *device->getAddress() << " left conference " << *getConferenceAddress();
 		device->updateStreamAvailabilities();
 		device->setState(ParticipantDevice::State::OnHold);
 		return 0;
@@ -1302,7 +1313,7 @@ int LocalConference::participantDeviceLeft(
 }
 int LocalConference::participantDeviceMediaCapabilityChanged(
     const std::shared_ptr<LinphonePrivate::CallSession> &session) {
-	const Address &remoteAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	int success = -1;
 	if (p) {
@@ -1311,14 +1322,14 @@ int LocalConference::participantDeviceMediaCapabilityChanged(
 			success = participantDeviceMediaCapabilityChanged(p, device);
 		} else {
 			lWarning() << "Participant media capability changed: Unable to find device with session " << session
-			           << " among devices of participant " << p->getAddress().asString() << " of conference "
-			           << getConferenceAddress();
+			           << " among devices of participant " << p->getAddress()->toString() << " of conference "
+			           << *getConferenceAddress();
 		}
 	}
 	return success;
 }
 
-int LocalConference::participantDeviceMediaCapabilityChanged(const IdentityAddress &addr) {
+int LocalConference::participantDeviceMediaCapabilityChanged(const std::shared_ptr<Address> &addr) {
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(addr);
 	int success = -1;
 	for (const auto &d : p->getDevices()) {
@@ -1335,7 +1346,7 @@ int LocalConference::participantDeviceMediaCapabilityChanged(
 	    ((getState() == ConferenceInterface::State::CreationPending) ||
 	     (getState() == ConferenceInterface::State::Created)) &&
 	    (device->getState() == ParticipantDevice::State::Present)) {
-		lInfo() << "Device " << device->getAddress() << " in conference " << getConferenceAddress()
+		lInfo() << "Device " << *device->getAddress() << " in conference " << *getConferenceAddress()
 		        << " changed its media capabilities";
 		device->updateStreamAvailabilities();
 		time_t creationTime = time(nullptr);
@@ -1348,7 +1359,7 @@ int LocalConference::participantDeviceMediaCapabilityChanged(
 int LocalConference::participantDeviceSsrcChanged(const std::shared_ptr<LinphonePrivate::CallSession> &session,
                                                   const LinphoneStreamType type,
                                                   uint32_t ssrc) {
-	const Address &remoteAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	int success = -1;
 	if (p) {
@@ -1357,27 +1368,27 @@ int LocalConference::participantDeviceSsrcChanged(const std::shared_ptr<Linphone
 			bool updated = device->setSsrc(type, ssrc);
 			if (updated) {
 				lInfo() << "Setting " << std::string(linphone_stream_type_to_string(type))
-				        << " ssrc of participant device " << device->getAddress().asString() << " in conference "
-				        << getConferenceAddress() << " to " << ssrc;
+				        << " ssrc of participant device " << device->getAddress()->toString() << " in conference "
+				        << *getConferenceAddress() << " to " << ssrc;
 				time_t creationTime = time(nullptr);
 				notifyParticipantDeviceMediaCapabilityChanged(creationTime, false, p, device);
 			} else {
-				lInfo() << "Leaving unchanged ssrc of participant device " << device->getAddress().asString()
-				        << " in conference " << getConferenceAddress() << " whose value is " << ssrc;
+				lInfo() << "Leaving unchanged ssrc of participant device " << device->getAddress()->toString()
+				        << " in conference " << *getConferenceAddress() << " whose value is " << ssrc;
 			}
 			return 0;
 		}
 	}
 	lInfo() << "Unable to set " << std::string(linphone_stream_type_to_string(type)) << " ssrc to " << ssrc
 	        << " because participant device with session " << session << " cannot be found in conference "
-	        << getConferenceAddress();
+	        << *getConferenceAddress();
 	return success;
 }
 
 int LocalConference::participantDeviceSsrcChanged(const std::shared_ptr<LinphonePrivate::CallSession> &session,
                                                   uint32_t audioSsrc,
                                                   uint32_t videoSsrc) {
-	const Address &remoteAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	int success = -1;
 	if (p) {
@@ -1388,8 +1399,8 @@ int LocalConference::participantDeviceSsrcChanged(const std::shared_ptr<Linphone
 				time_t creationTime = time(nullptr);
 				notifyParticipantDeviceMediaCapabilityChanged(creationTime, false, p, device);
 			} else {
-				lInfo() << "Leaving unchanged ssrcs of participant device " << device->getAddress().asString()
-				        << " in conference " << getConferenceAddress() << " whose values are";
+				lInfo() << "Leaving unchanged ssrcs of participant device " << device->getAddress()->toString()
+				        << " in conference " << *getConferenceAddress() << " whose values are";
 				lInfo() << "- audio -> " << audioSsrc;
 				lInfo() << "- video -> " << videoSsrc;
 			}
@@ -1398,7 +1409,7 @@ int LocalConference::participantDeviceSsrcChanged(const std::shared_ptr<Linphone
 	}
 	lInfo() << "Unable to set audio ssrc to " << audioSsrc << " and video ssrc to " << videoSsrc
 	        << " because participant device with session " << session << " cannot be found in conference "
-	        << getConferenceAddress();
+	        << *getConferenceAddress();
 	return success;
 }
 
@@ -1413,23 +1424,26 @@ int LocalConference::getParticipantDeviceVolume(const std::shared_ptr<LinphonePr
 	return AUDIOSTREAMVOLUMES_NOT_FOUND;
 }
 
-bool LocalConference::dialOutAddresses(const std::list<const LinphoneAddress *> &addressList) {
+bool LocalConference::dialOutAddresses(const std::list<std::shared_ptr<Address>> &addressList) {
 	auto new_params = linphone_core_create_call_params(getCore()->getCCore(), nullptr);
 	linphone_call_params_enable_video(new_params, confParams->videoEnabled());
 
 	linphone_call_params_set_in_conference(new_params, TRUE);
 
-	const Address &conferenceAddress = getConferenceAddress().asAddress();
-	const string &confId = conferenceAddress.getUriParamValue("conf-id");
+	const std::shared_ptr<Address> &conferenceAddress = getConferenceAddress();
+	const string &confId = conferenceAddress->getUriParamValue("conf-id");
 	linphone_call_params_set_conference_id(new_params, confId.c_str());
 
-	std::list<IdentityAddress> addresses;
+	std::list<std::shared_ptr<Address>> addresses;
 	if (!invitedAddresses.empty()) {
 		addresses = invitedAddresses;
 	}
+
+	// Add participants already in the conference to the list of addresses if they are not part of the invitees
 	for (const auto &p : getParticipants()) {
 		const auto &pAddress = p->getAddress();
-		auto pIt = std::find(addresses.begin(), addresses.end(), pAddress);
+		auto pIt = std::find_if(addresses.begin(), addresses.end(),
+		                        [&pAddress](const auto &address) { return (pAddress->weakEqual(*address)); });
 		if (pIt == addresses.end()) {
 			addresses.push_back(pAddress);
 		}
@@ -1447,7 +1461,8 @@ bool LocalConference::dialOutAddresses(const std::list<const LinphoneAddress *>
 	}
 
 	Content sipfrag;
-	sipfrag.setBodyFromLocale("From: <" + organizer.asString() + ">");
+	const auto organizerUri = organizer->getUri();
+	sipfrag.setBodyFromLocale("From: <" + organizerUri.toString() + ">");
 	sipfrag.setContentType(ContentType::SipFrag);
 	L_GET_CPP_PTR_FROM_C_OBJECT(new_params)->addCustomContent(sipfrag);
 	auto success = (inviteAddresses(addressList, new_params) == 0);
@@ -1476,7 +1491,7 @@ bool LocalConference::addParticipants(const std::list<std::shared_ptr<Call>> &ca
 	return success;
 }
 
-bool LocalConference::addParticipants(const std::list<IdentityAddress> &addresses) {
+bool LocalConference::addParticipants(const std::list<std::shared_ptr<Address>> &addresses) {
 	return Conference::addParticipants(addresses);
 }
 
@@ -1511,13 +1526,9 @@ bool LocalConference::addParticipantDevice(std::shared_ptr<LinphonePrivate::Call
 
 bool LocalConference::tryAddMeDevice() {
 	if (confParams->localParticipantEnabled() && me->getDevices().empty() && confParams->getAccount()) {
-		char *devAddrStr =
-		    linphone_account_get_contact_address(confParams->getAccount())
-		        ? linphone_address_as_string(linphone_account_get_contact_address(confParams->getAccount()))
-		        : nullptr;
-		if (devAddrStr) {
-			Address devAddr(devAddrStr);
-			ms_free(devAddrStr);
+		const auto &contactAddress = confParams->getAccount()->getContactAddress();
+		if (contactAddress) {
+			std::shared_ptr<Address> devAddr = contactAddress->clone()->toSharedPtr();
 			auto meDev = me->addDevice(devAddr);
 			const auto &meSession = me->getSession();
 
@@ -1551,20 +1562,21 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 
 	const auto &remoteAddress = call->getRemoteAddress();
 	if (linphone_call_params_get_in_conference(linphone_call_get_current_params(call->toC()))) {
-		lError() << "Call (local address " << call->getLocalAddress().asString() << " remote address "
-		         << (remoteAddress ? remoteAddress->asString() : "Unknown") << ") is already in conference "
-		         << getConferenceAddress();
+		lError() << "Call (local address " << call->getLocalAddress()->toString() << " remote address "
+		         << (remoteAddress ? remoteAddress->toString() : "Unknown") << ") is already in conference "
+		         << *getConferenceAddress();
 		return false;
 	}
 
 	if (confParams->getParticipantListType() == ConferenceParams::ParticipantListType::Closed) {
 		const auto allowedAddresses = getAllowedAddresses();
-		auto p = std::find(allowedAddresses.begin(), allowedAddresses.end(), IdentityAddress(*remoteAddress));
+		auto p = std::find_if(allowedAddresses.begin(), allowedAddresses.end(),
+		                      [&remoteAddress](const auto &address) { return (remoteAddress->weakEqual(*address)); });
 		if (p == allowedAddresses.end()) {
-			lError() << "Unable to add call (local address " << call->getLocalAddress().asString() << " remote address "
-			         << (remoteAddress ? remoteAddress->asString() : "Unknown") << ") because participant "
-			         << *remoteAddress << " is not in the list of allowed participants of conference "
-			         << getConferenceAddress();
+			lError() << "Unable to add call (local address " << call->getLocalAddress()->toString()
+			         << " remote address " << (remoteAddress ? remoteAddress->toString() : "Unknown")
+			         << ") because participant " << *remoteAddress
+			         << " is not in the list of allowed participants of conference " << *getConferenceAddress();
 			LinphoneErrorInfo *ei = linphone_error_info_new();
 			linphone_error_info_set(ei, NULL, LinphoneReasonUnknown, 403, "Call forbidden to join the conference",
 			                        NULL);
@@ -1579,10 +1591,10 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 	// If conference must start immediately, then the organizer will call the conference server and the other
 	// participants will be dialed out
 	if ((initialState == ConferenceInterface::State::CreationPending) && dialout &&
-	    !remoteAddress->weakEqual(organizer.asAddress())) {
+	    !remoteAddress->weakEqual(*organizer)) {
 		lError() << "The conference must immediately start (start time: " << confParams->getStartTime()
 		         << " end time: " << confParams->getEndTime() << "). Unable to add participant "
-		         << remoteAddress->asString()
+		         << remoteAddress->toString()
 		         << " because participants will be dialed out by the conference server as soon as " << organizer
 		         << " dials in";
 		return false;
@@ -1590,7 +1602,7 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 
 #if 0
 	if (!isConferenceStarted()) {
-		lError() << "Unable to add call (local address " << call->getLocalAddress().asString() << " remote address " <<  (remoteAddress ? remoteAddress->asString() : "Unknown") << ") because participant " << *remoteAddress << " is not in the list of allowed participants of conference " << getConferenceAddress();
+		lError() << "Unable to add call (local address " << call->getLocalAddress()->toString() << " remote address " <<  (remoteAddress ? remoteAddress->toString() : "Unknown") << ") because participant " << *remoteAddress << " is not in the list of allowed participants of conference " << *getConferenceAddress();
 		LinphoneErrorInfo *ei = linphone_error_info_new();
 		linphone_error_info_set(ei, NULL, LinphoneReasonUnknown, 403, "Conference not started yet", NULL);
 		call->terminate(ei);
@@ -1599,7 +1611,7 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 	}
 
 	if (isConferenceEnded()) {
-		lError() << "Unable to add call (local address " << call->getLocalAddress().asString() << " remote address " <<  (remoteAddress ? remoteAddress->asString() : "Unknown") << ") because participant " << *remoteAddress << " is not in the list of allowed participants of conference " << getConferenceAddress();
+		lError() << "Unable to add call (local address " << call->getLocalAddress()->toString() << " remote address " <<  (remoteAddress ? remoteAddress->toString() : "Unknown") << ") because participant " << *remoteAddress << " is not in the list of allowed participants of conference " << *getConferenceAddress();
 		LinphoneErrorInfo *ei = linphone_error_info_new();
 		linphone_error_info_set(ei, NULL, LinphoneReasonUnknown, 403, "Conference already terminated", NULL);
 		call->terminate(ei);
@@ -1608,8 +1620,8 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 	}
 #endif
 
-	const Address &conferenceAddress = getConferenceAddress().asAddress();
-	const string &confId = conferenceAddress.getUriParamValue("conf-id");
+	const std::shared_ptr<Address> &conferenceAddress = getConferenceAddress();
+	const string &confId = conferenceAddress->getUriParamValue("conf-id");
 	const string &callConfId = call->getConferenceId();
 
 	const auto &coreCurrentCall = getCore()->getCurrentCall();
@@ -1629,7 +1641,7 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 		LinphoneCallState state = static_cast<LinphoneCallState>(call->getState());
 
 		auto participantDevice = (remoteContactAddress && remoteContactAddress->isValid())
-		                             ? findParticipantDevice(*session->getRemoteAddress(), *remoteContactAddress)
+		                             ? findParticipantDevice(session->getRemoteAddress(), remoteContactAddress)
 		                             : nullptr;
 		if (participantDevice) {
 			auto deviceSession = participantDevice->getSession();
@@ -1646,14 +1658,14 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 
 		if (!confParams->getAccount()) {
 			// Set proxy configuration used for the conference
-			auto callProxyCfg = linphone_call_get_dest_proxy(call->toC());
-			if (callProxyCfg) {
-				auto callAccount = linphone_core_lookup_account_by_identity(
-				    getCore()->getCCore(), linphone_proxy_config_get_identity_address(callProxyCfg));
+			auto callAccount = call->getDestAccount();
+			if (callAccount) {
 				confParams->setAccount(callAccount);
 			} else {
-				confParams->setAccount(linphone_core_lookup_known_account(getCore()->getCCore(),
-				                                                          linphone_call_get_to_address(call->toC())));
+				confParams->setAccount(
+				    Account::toCpp(linphone_core_lookup_known_account(getCore()->getCCore(),
+				                                                      linphone_call_get_to_address(call->toC())))
+				        ->getSharedFromThis());
 			}
 		}
 
@@ -1703,8 +1715,8 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 
 				break;
 			default:
-				lError() << "Call " << call << " (local address " << call->getLocalAddress().asString()
-				         << " remote address " << (remoteAddress ? remoteAddress->asString() : "Unknown")
+				lError() << "Call " << call << " (local address " << call->getLocalAddress()->toString()
+				         << " remote address " << (remoteAddress ? remoteAddress->toString() : "Unknown")
 				         << ") is in state " << Utils::toString(call->getState())
 				         << ", hence it cannot be added to the conference right now";
 				return false;
@@ -1733,7 +1745,7 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 					// Calling enter here because update will lock sound resources
 					enter();
 				}
-				if (contactAddress.isValid() && !contactAddress.hasParam("isfocus")) {
+				if (contactAddress && contactAddress->isValid() && !contactAddress->hasParam("isfocus")) {
 					const MediaSessionParams *params = session->getMediaParams();
 					MediaSessionParams *currentParams = params->clone();
 					call->update(currentParams);
@@ -1741,8 +1753,8 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 				}
 			} break;
 			default:
-				lError() << "Call " << call << " (local address " << call->getLocalAddress().asString()
-				         << " remote address " << (remoteAddress ? remoteAddress->asString() : "Unknown")
+				lError() << "Call " << call << " (local address " << call->getLocalAddress()->toString()
+				         << " remote address " << (remoteAddress ? remoteAddress->toString() : "Unknown")
 				         << ") is in state " << Utils::toString(call->getState())
 				         << ", hence the call cannot be updated following it becoming part of the conference";
 				return false;
@@ -1766,11 +1778,11 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 
 		// If no resource list is provided in the INVITE, there is not need to call participants
 		if ((initialState == ConferenceInterface::State::CreationPending) && dialout && !resourceList.isEmpty()) {
-			list<const LinphoneAddress *> addresses;
+			list<std::shared_ptr<Address>> addresses;
 			for (auto &addr : invitedAddresses) {
 				// Do not invite organizer as it is already dialing in
-				if (addr != organizer) {
-					addresses.push_back(L_GET_C_BACK_PTR(&(addr.asAddress())));
+				if (*addr != *organizer) {
+					addresses.push_back(addr);
 				}
 			}
 			dialOutAddresses(addresses);
@@ -1779,12 +1791,13 @@ bool LocalConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> call
 		return true;
 	}
 
-	lError() << "Unable to add call (local address " << call->getLocalAddress().asString() << " remote address "
-	         << (remoteAddress ? remoteAddress->asString() : "Unknown") << ") to conference " << getConferenceAddress();
+	lError() << "Unable to add call (local address " << call->getLocalAddress()->toString() << " remote address "
+	         << (remoteAddress ? remoteAddress->toString() : "Unknown") << ") to conference "
+	         << *getConferenceAddress();
 	return false;
 }
 
-bool LocalConference::addParticipant(const IdentityAddress &participantAddress) {
+bool LocalConference::addParticipant(const std::shared_ptr<Address> &participantAddress) {
 #if 0
 	if (!isConferenceEnded() && isConferenceStarted()) {
 #endif
@@ -1793,12 +1806,15 @@ bool LocalConference::addParticipant(const IdentityAddress &participantAddress)
 	    (initialState == ConferenceInterface::State::Created)) {
 
 		const auto allowedAddresses = getAllowedAddresses();
-		auto p = std::find(allowedAddresses.begin(), allowedAddresses.end(), participantAddress);
+		auto p =
+		    std::find_if(allowedAddresses.begin(), allowedAddresses.end(), [&participantAddress](const auto &address) {
+			    return (participantAddress->weakEqual(*address));
+		    });
 		if (p == allowedAddresses.end()) {
 			invitedAddresses.push_back(participantAddress);
 		}
 
-		std::list<const LinphoneAddress *> addressesList{L_GET_C_BACK_PTR(&(participantAddress.asAddress()))};
+		std::list<std::shared_ptr<Address>> addressesList{participantAddress};
 		return dialOutAddresses(addressesList);
 	}
 #if 0
@@ -1806,7 +1822,7 @@ bool LocalConference::addParticipant(const IdentityAddress &participantAddress)
 		const auto & endTime = confParams->getEndTime();
 		const auto & startTime = confParams->getStartTime();
 		const auto now = time(NULL);
-		lError() << "Could not add participant " << participantAddress << " to the conference because the conference " << getConferenceAddress() << " is not active right now.";
+		lError() << "Could not add participant " << *participantAddress << " to the conference because the conference " << *getConferenceAddress() << " is not active right now.";
 		if (startTime >= 0) {
 			lError() << "Expected start time (" << startTime << "): " << ctime(&startTime);
 		} else {
@@ -1829,18 +1845,14 @@ void LocalConference::setLocalParticipantStreamCapability(const LinphoneMediaDir
                                                           const LinphoneStreamType type) {
 	if (confParams->localParticipantEnabled() && !me->getDevices().empty() && confParams->getAccount() &&
 	    (type != LinphoneStreamTypeUnknown)) {
-		char *devAddrStr =
-		    linphone_account_get_contact_address(confParams->getAccount())
-		        ? linphone_address_as_string(linphone_account_get_contact_address(confParams->getAccount()))
-		        : nullptr;
-		if (devAddrStr) {
-			Address devAddr(devAddrStr);
-			ms_free(devAddrStr);
+		const auto &contactAddress = confParams->getAccount()->getContactAddress();
+		if (contactAddress) {
+			std::shared_ptr<Address> devAddr = contactAddress->clone()->toSharedPtr();
 			const auto &meDev = me->findDevice(devAddr);
 			if (meDev) {
 				lInfo() << "Setting direction of stream of type " << std::string(linphone_stream_type_to_string(type))
 				        << " to " << std::string(linphone_media_direction_to_string(direction)) << " of device "
-				        << meDev->getAddress();
+				        << meDev->getAddress()->toString();
 				const auto mediaChanged = meDev->setStreamCapability(direction, type);
 				meDev->updateStreamAvailabilities();
 				for (const auto &p : getParticipants()) {
@@ -1854,8 +1866,8 @@ void LocalConference::setLocalParticipantStreamCapability(const LinphoneMediaDir
 					notifyParticipantDeviceMediaCapabilityChanged(creationTime, false, me, meDev);
 				}
 			} else {
-				lError() << "Unable to find device with address " << devAddr << " among those in the local participant "
-				         << me->getAddress();
+				lError() << "Unable to find device with address " << devAddr->toString()
+				         << " among those in the local participant " << me->getAddress()->toString();
 			}
 		}
 	}
@@ -1867,7 +1879,7 @@ bool LocalConference::finalizeParticipantAddition(std::shared_ptr<LinphonePrivat
 	if (device) {
 		const auto deviceState = device->getState();
 		if (deviceState == ParticipantDevice::State::Joining) {
-			const Address &remoteAddress = *call->getRemoteAddress();
+			const std::shared_ptr<Address> &remoteAddress = call->getRemoteAddress();
 			const auto &p = findParticipant(remoteAddress);
 			if (device && p) {
 				participantDeviceJoined(p, device);
@@ -1876,10 +1888,10 @@ bool LocalConference::finalizeParticipantAddition(std::shared_ptr<LinphonePrivat
 			device->setState(ParticipantDevice::State::Joining);
 			auto contactAddress = newParticipantSession->getContactAddress();
 
-			if (contactAddress.isValid() && !contactAddress.hasParam("isfocus")) {
+			if (contactAddress && contactAddress->isValid() && !contactAddress->hasParam("isfocus")) {
 				getCore()->doLater([this, call] {
-					const Address &conferenceAddress = getConferenceAddress().asAddress();
-					const string &confId = conferenceAddress.getUriParamValue("conf-id");
+					const std::shared_ptr<Address> &conferenceAddress = getConferenceAddress();
+					const string &confId = conferenceAddress->getUriParamValue("conf-id");
 
 					LinphoneCallParams *params = linphone_core_create_call_params(getCore()->getCCore(), call->toC());
 					linphone_call_params_set_in_conference(params, TRUE);
@@ -1912,16 +1924,16 @@ int LocalConference::removeParticipant(const std::shared_ptr<LinphonePrivate::Ca
 	if (call) {
 		if (linphone_call_get_conference(call->toC()) != toC()) {
 			const auto &remoteAddress = call->getRemoteAddress();
-			lError() << "Call (local address " << call->getLocalAddress().asString() << " remote address "
-			         << (remoteAddress ? remoteAddress->asString() : "Unknown") << ") is not part of conference "
-			         << getConferenceAddress();
+			lError() << "Call (local address " << call->getLocalAddress()->toString() << " remote address "
+			         << (remoteAddress ? remoteAddress->toString() : "Unknown") << ") is not part of conference "
+			         << *getConferenceAddress();
 			return -1;
 		}
 	}
 
 	CallSession::State sessionState = session->getState();
 
-	const Address &remoteAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> participant = findParticipant(remoteAddress);
 	if (participant) {
 		Conference::removeParticipant(session, preserveSession);
@@ -1931,7 +1943,7 @@ int LocalConference::removeParticipant(const std::shared_ptr<LinphonePrivate::Ca
 		if ((sessionState != LinphonePrivate::CallSession::State::Released) &&
 		    (sessionState != LinphonePrivate::CallSession::State::End)) {
 			lError() << "Trying to remove participant " << *session->getRemoteAddress() << " with session " << session
-			         << " which is not part of conference " << getConferenceAddress();
+			         << " which is not part of conference " << *getConferenceAddress();
 		}
 		return -1;
 	}
@@ -1991,8 +2003,8 @@ int LocalConference::removeParticipant(const std::shared_ptr<LinphonePrivate::Ca
 
 				if (lastSession) {
 					lInfo() << "Participant [" << remainingParticipant << "] with "
-					        << lastSession->getRemoteAddress()->asString() << " is the last call in conference "
-					        << getConferenceAddress() << ", we will reconnect directly to it.";
+					        << lastSession->getRemoteAddress()->toString() << " is the last call in conference "
+					        << *getConferenceAddress() << ", we will reconnect directly to it.";
 
 					const MediaSessionParams *params = lastSession->getMediaParams();
 					// If only one participant is in the conference, the conference is destroyed.
@@ -2048,7 +2060,7 @@ int LocalConference::removeParticipant(const std::shared_ptr<LinphonePrivate::Ca
 	return err ? 0 : -1;
 }
 
-int LocalConference::removeParticipant(const IdentityAddress &addr) {
+int LocalConference::removeParticipant(const std::shared_ptr<Address> &addr) {
 	const std::shared_ptr<LinphonePrivate::Participant> participant = findParticipant(addr);
 	if (!participant) return -1;
 	return removeParticipant(participant) ? 0 : -1;
@@ -2062,8 +2074,8 @@ bool LocalConference::removeParticipant(const std::shared_ptr<LinphonePrivate::P
 			success &= (removeParticipant(d->getSession(), false) == 0);
 		}
 	} else {
-		lInfo() << "Remove participant with address " << participant->getAddress() << " from conference "
-		        << getConferenceAddress();
+		lInfo() << "Remove participant with address " << *participant->getAddress() << " from conference "
+		        << *getConferenceAddress();
 		participants.remove(participant);
 		time_t creationTime = time(nullptr);
 		notifyParticipantRemoved(creationTime, false, participant);
@@ -2134,7 +2146,9 @@ void LocalConference::subscriptionStateChanged(shared_ptr<EventSubscribe> event,
 #endif // _MSC_VER
 
 int LocalConference::terminate() {
-	lInfo() << "Terminate conference " << getConferenceAddress();
+	const auto conferenceAddressStr =
+	    (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<address-not-defined>"));
+	lInfo() << "Terminate conference " << conferenceAddressStr;
 	// Take a ref because the conference may be immediately go to deleted state if terminate is called when there are 0
 	// participants
 	const auto ref = getSharedFromThis();
@@ -2180,7 +2194,7 @@ int LocalConference::enter() {
 		if (linphone_core_get_current_call(getCore()->getCCore()))
 			linphone_call_pause(linphone_core_get_current_call(getCore()->getCCore()));
 
-		lInfo() << getMe()->getAddress().asString() << " is rejoining conference " << getConferenceAddress();
+		lInfo() << getMe()->getAddress()->toString() << " is rejoining conference " << *getConferenceAddress();
 		addLocalEndpoint();
 		if (me->getDevices().size() > 0) {
 			participantDeviceJoined(me, me->getDevices().front());
@@ -2206,7 +2220,7 @@ void LocalConference::removeLocalEndpoint() {
 
 void LocalConference::leave() {
 	if (isIn()) {
-		lInfo() << getMe()->getAddress() << " is leaving conference " << getConferenceAddress();
+		lInfo() << getMe()->getAddress() << " is leaving conference " << *getConferenceAddress();
 		if (me->getDevices().size() > 0) {
 			participantDeviceLeft(me, me->getDevices().front());
 		}
@@ -2310,12 +2324,12 @@ bool LocalConference::isIn() const {
 	return mIsIn;
 }
 
-IdentityAddress LocalConference::getOrganizer() const {
+const std::shared_ptr<Address> LocalConference::getOrganizer() const {
 	return organizer;
 }
 
-AudioControlInterface *LocalConference::getAudioControlInterface()const{
-	return mMixerSession ? dynamic_cast<AudioControlInterface*>(mMixerSession->getMixerByType(SalAudio)) : nullptr;
+AudioControlInterface *LocalConference::getAudioControlInterface() const {
+	return mMixerSession ? dynamic_cast<AudioControlInterface *>(mMixerSession->getMixerByType(SalAudio)) : nullptr;
 }
 
 VideoControlInterface *LocalConference::getVideoControlInterface() const {
@@ -2358,21 +2372,22 @@ void LocalConference::callStateChangedCb(LinphoneCore *lc,
 			case LinphoneCallStateStreamsRunning: {
 				if (!addParticipantDevice(cppCall)) {
 					// If the participant is already in the conference
-					const Address &remoteAddress = *cppCall->getRemoteAddress();
+					const std::shared_ptr<Address> &remoteAddress = cppCall->getRemoteAddress();
 					const auto &participant = findParticipant(remoteAddress);
 					const auto &device = findParticipantDevice(session);
 					const auto &deviceState =
 					    device ? device->getState() : ParticipantDevice::State::ScheduledForJoining;
+					auto remoteContactAddress = session->getRemoteContactAddress();
 					if (participant) {
 						if (device) {
 							const auto deviceAddr = device->getAddress();
-							const auto &remoteContactAddress(*cppCall->getActiveSession()->getRemoteContactAddress());
-							const IdentityAddress newDeviceAddress(remoteContactAddress);
-							if (deviceAddr != newDeviceAddress) {
+							const std::shared_ptr<Address> newDeviceAddress = remoteContactAddress;
+							if (*deviceAddr != *newDeviceAddress) {
 								// The remote contact address of the device changed during the call. This may be caused
 								// by a call that started before the registration was completed
 								lInfo() << "Updating address of participant device " << device << " with session "
-								        << device->getSession() << " from " << deviceAddr << " to " << newDeviceAddress;
+								        << device->getSession() << " from " << *deviceAddr << " to "
+								        << *newDeviceAddress;
 								auto otherDevice = participant->findDevice(newDeviceAddress);
 								// If a device with the same address has been found, then remove it from the participant
 								// list and copy subscription event. Otherwise, notify that it has been added
@@ -2414,13 +2429,12 @@ void LocalConference::callStateChangedCb(LinphoneCore *lc,
 								}
 							}
 						}
-						auto remoteContactAddress = (*session->getRemoteContactAddress());
-						bool admin = remoteContactAddress.hasParam("admin") &&
-						             Utils::stob(remoteContactAddress.getParamValue("admin"));
+						bool admin = remoteContactAddress->hasParam("admin") &&
+						             Utils::stob(remoteContactAddress->getParamValue("admin"));
 						setParticipantAdminStatus(participant, admin);
 					} else {
 						lError() << "Unable to update admin status and device address as no participant with address "
-						         << remoteAddress << " has been found in conference " << getConferenceAddress();
+						         << remoteAddress << " has been found in conference " << *getConferenceAddress();
 					}
 					if (device) {
 						if (deviceState == ParticipantDevice::State::Present) {
@@ -2437,7 +2451,8 @@ void LocalConference::callStateChangedCb(LinphoneCore *lc,
 								finalizeParticipantAddition(cppCall);
 							} else {
 								auto contactAddress = session->getContactAddress();
-								if (contactAddress.isValid() && contactAddress.hasParam("isfocus")) {
+								if (contactAddress && contactAddress->isValid() &&
+								    contactAddress->hasParam("isfocus")) {
 									device->setState(ParticipantDevice::State::Joining);
 								}
 							}
@@ -2445,9 +2460,8 @@ void LocalConference::callStateChangedCb(LinphoneCore *lc,
 							participantDeviceJoined(session);
 						}
 					} else {
-						auto remoteContactAddress = (*session->getRemoteContactAddress());
-						lError() << "Unable to update device with address " << remoteContactAddress
-						         << " because it was not found in conference " << getConferenceAddress();
+						lError() << "Unable to update device with address " << *remoteContactAddress
+						         << " because it was not found in conference " << *getConferenceAddress();
 					}
 				}
 			} break;
@@ -2456,8 +2470,8 @@ void LocalConference::callStateChangedCb(LinphoneCore *lc,
 				// If a call in a local conference is paused by remote, it means that the remote participant temporarely
 				// left the call, hence notify that no audio and video is available
 				lInfo() << "Call in conference has been put on hold by remote device, hence participant "
-				        << session->getRemoteAddress()->asString() << " temporarely left conference "
-				        << getConferenceAddress();
+				        << session->getRemoteAddress()->toString() << " temporarely left conference "
+				        << *getConferenceAddress();
 				participantDeviceLeft(session);
 				break;
 			case LinphoneCallStateUpdatedByRemote: {
@@ -2477,7 +2491,7 @@ void LocalConference::callStateChangedCb(LinphoneCore *lc,
 						     (conferenceProtocol->second >= Utils::Version(1, 0))) ||
 						    !CallSession::isPredefinedSubject(subject)) {
 							// Handle subject change
-							lInfo() << "conference " << getConferenceAddress() << " changed subject to \"" << subject
+							lInfo() << "conference " << *getConferenceAddress() << " changed subject to \"" << subject
 							        << "\"";
 							setSubject(subject);
 						}
@@ -2486,9 +2500,9 @@ void LocalConference::callStateChangedCb(LinphoneCore *lc,
 			} break;
 			case LinphoneCallStateEnd:
 			case LinphoneCallStateError:
-				lInfo() << "Removing terminated call (local address " << session->getLocalAddress().asString()
-				        << " remote address " << session->getRemoteAddress()->asString() << ") from conference " << this
-				        << " (" << getConferenceAddress() << ")";
+				lInfo() << "Removing terminated call (local address " << session->getLocalAddress()->toString()
+				        << " remote address " << session->getRemoteAddress()->toString() << ") from conference " << this
+				        << " (" << *getConferenceAddress() << ")";
 				if (session->getErrorInfo() &&
 				    (linphone_error_info_get_reason(session->getErrorInfo()) == LinphoneReasonBusy)) {
 					removeParticipantDevice(session);
@@ -2600,9 +2614,9 @@ shared_ptr<ConferenceParticipantDeviceEvent> LocalConference::notifyParticipantD
 
 RemoteConference::RemoteConference(const shared_ptr<Core> &core,
                                    const std::shared_ptr<LinphonePrivate::CallSession> &focusSession,
-                                   const ConferenceAddress &confAddr,
+                                   const std::shared_ptr<Address> &confAddr,
                                    const ConferenceId &conferenceId,
-                                   const std::list<IdentityAddress> &invitees,
+                                   const std::list<std::shared_ptr<Address>> &invitees,
                                    CallSessionListener *listener,
                                    const std::shared_ptr<LinphonePrivate::ConferenceParams> params)
     : Conference(core, conferenceId.getLocalAddress(), listener, params) {
@@ -2612,7 +2626,7 @@ RemoteConference::RemoteConference(const shared_ptr<Core> &core,
 	confParams->enableLocalParticipant(false);
 	pendingSubject = confParams->getSubject();
 
-	IdentityAddress organizer;
+	std::shared_ptr<Address> organizer;
 #ifdef HAVE_DB_STORAGE
 	auto &mainDb = getCore()->getPrivate()->mainDb;
 	if (mainDb) {
@@ -2623,7 +2637,7 @@ RemoteConference::RemoteConference(const shared_ptr<Core> &core,
 		}
 	}
 #endif
-	getMe()->setAdmin(((organizer == IdentityAddress()) || (organizer == getMe()->getAddress())));
+	getMe()->setAdmin((organizer == nullptr) || organizer->weakEqual(*(getMe()->getAddress())));
 
 	invitedAddresses = invitees;
 
@@ -2636,7 +2650,7 @@ RemoteConference::RemoteConference(const shared_ptr<Core> &core,
 }
 
 RemoteConference::RemoteConference(const shared_ptr<Core> &core,
-                                   const IdentityAddress &focusAddr,
+                                   const std::shared_ptr<Address> &focusAddr,
                                    const ConferenceId &conferenceId,
                                    CallSessionListener *listener,
                                    const std::shared_ptr<LinphonePrivate::ConferenceParams> params)
@@ -2663,8 +2677,8 @@ RemoteConference::RemoteConference(const shared_ptr<Core> &core,
                                    const std::shared_ptr<LinphonePrivate::ConferenceParams> params)
     : Conference(core, conferenceId.getLocalAddress(), listener, params) {
 
-	focus = Participant::create(this, *focusCall->getRemoteContactAddress(), focusCall->getActiveSession());
-	lInfo() << "Create focus '" << focus->getAddress() << "' from address : " << focusCall->getRemoteContact();
+	focus = Participant::create(this, focusCall->getRemoteContactAddress(), focusCall->getActiveSession());
+	lInfo() << "Create focus '" << *focus->getAddress() << "' from address : " << focusCall->getRemoteContact();
 	pendingSubject = confParams->getSubject();
 	setConferenceId(conferenceId);
 
@@ -2673,15 +2687,15 @@ RemoteConference::RemoteConference(const shared_ptr<Core> &core,
 #ifdef HAVE_DB_STORAGE
 	auto &mainDb = getCore()->getPrivate()->mainDb;
 	if (mainDb) {
-		const auto &confInfo = mainDb->getConferenceInfoFromURI(ConferenceAddress(*conferenceAddress));
+		const auto &confInfo = mainDb->getConferenceInfoFromURI(conferenceAddress);
 		// me is admin if the organizer is the same as me
-		getMe()->setAdmin((confInfo && (confInfo->getOrganizerAddress() == getMe()->getAddress())));
+		getMe()->setAdmin((confInfo && (confInfo->getOrganizerAddress()->weakEqual(*getMe()->getAddress()))));
 	}
 #endif
 
 	setState(ConferenceInterface::State::Instantiated);
 
-	setConferenceAddress(*conferenceAddress);
+	setConferenceAddress(conferenceAddress);
 
 	finalizeCreation();
 }
@@ -2712,7 +2726,7 @@ void RemoteConference::finalizeCreation() {
 				eventHandler->subscribe(getConferenceId());
 			} else {
 #endif // HAVE_ADVANCED_IM
-				lInfo() << "Unable to send SUBSCRIBE to finalize creation of conference " << getConferenceAddress()
+				lInfo() << "Unable to send SUBSCRIBE to finalize creation of conference " << *getConferenceAddress()
 				        << " because conference event package (RFC 4575) is disabled or the SDK was not compiled with "
 				           "ENABLE_ADVANCED_IM flag set to on";
 #ifdef HAVE_ADVANCED_IM
@@ -2738,16 +2752,18 @@ std::shared_ptr<ConferenceInfo> RemoteConference::createOrGetConferenceInfo() co
 
 	auto session = static_pointer_cast<MediaSession>(getMainSession());
 	const auto referer = (session ? L_GET_PRIVATE(session->getMediaParams())->getReferer() : nullptr);
-	const auto organizer = (referer) ? IdentityAddress(*referer->getRemoteAddress()) : getMe()->getAddress();
+	const auto organizer = (referer) ? referer->getRemoteAddress() : getMe()->getAddress();
 
-	std::list<IdentityAddress> participantAddresses;
+	std::list<std::shared_ptr<Address>> participantAddresses;
 	if (!invitedAddresses.empty()) {
 		participantAddresses = invitedAddresses;
 	}
 
+	// Add participants that are not part of the invitees'list
 	for (const auto &p : getParticipants()) {
 		const auto &pAddress = p->getAddress();
-		auto pIt = std::find(participantAddresses.begin(), participantAddresses.end(), pAddress);
+		auto pIt = std::find_if(participantAddresses.begin(), participantAddresses.end(),
+		                        [&pAddress](const auto &address) { return (pAddress->weakEqual(*address)); });
 		if (pIt == participantAddresses.end()) {
 			participantAddresses.push_back(pAddress);
 		}
@@ -2804,12 +2820,13 @@ void RemoteConference::notifyStateChanged(LinphonePrivate::ConferenceInterface::
 	Conference::notifyStateChanged(state);
 }
 
-bool RemoteConference::dialOutAddresses (BCTBX_UNUSED(const list<const LinphoneAddress *> &addressList)) {
+bool RemoteConference::dialOutAddresses(BCTBX_UNUSED(const std::list<std::shared_ptr<Address>> &addressList)) {
 	lError() << "RemoteConference::dialOutAddresses() not implemented";
 	return false;
 }
 
-int RemoteConference::inviteAddresses (BCTBX_UNUSED(const list<const LinphoneAddress *> &addresses), BCTBX_UNUSED(const LinphoneCallParams *params)) {
+int RemoteConference::inviteAddresses(BCTBX_UNUSED(const list<std::shared_ptr<Address>> &addresses),
+                                      BCTBX_UNUSED(const LinphoneCallParams *params)) {
 	lError() << "RemoteConference::inviteAddresses() not implemented";
 	return -1;
 }
@@ -2859,7 +2876,7 @@ int RemoteConference::participantDeviceMediaCapabilityChanged(
 	return -1;
 }
 
-int RemoteConference::participantDeviceMediaCapabilityChanged(BCTBX_UNUSED(const IdentityAddress &addr)) {
+int RemoteConference::participantDeviceMediaCapabilityChanged(BCTBX_UNUSED(const std::shared_ptr<Address> &addr)) {
 	lError() << "RemoteConference::participantDeviceMediaCapabilityChanged() not implemented";
 	return -1;
 }
@@ -2953,18 +2970,18 @@ bool RemoteConference::addParticipantDevice(std::shared_ptr<LinphonePrivate::Cal
 	return success;
 }
 
-bool RemoteConference::addParticipant(const IdentityAddress &participantAddress) {
+bool RemoteConference::addParticipant(const std::shared_ptr<Address> &participantAddress) {
 	// Search call that matches participant session
 	const std::list<std::shared_ptr<Call>> &coreCalls = getCore()->getCalls();
 	auto callIt = std::find_if(coreCalls.cbegin(), coreCalls.cend(), [&](const std::shared_ptr<Call> &c) {
-		return (IdentityAddress(*c->getRemoteAddress()) == participantAddress);
+		return (participantAddress->weakEqual(*c->getRemoteAddress()));
 	});
 	bool ret = false;
 	if (callIt != coreCalls.cend()) {
 		std::shared_ptr<Call> call = *callIt;
 		ret = addParticipant(call);
 	} else {
-		const list<IdentityAddress> addresses{participantAddress};
+		const list<std::shared_ptr<Address>> addresses{participantAddress};
 		ret = addParticipants(addresses);
 	}
 	return ret;
@@ -2976,24 +2993,25 @@ bool RemoteConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> cal
 	if (getMe()->isAdmin() && !isConferenceEnded() && isConferenceStarted()) {
 #endif
 	if (getMe()->isAdmin()) {
-		LinphoneAddress *addr;
+		std::shared_ptr<Address> focusAddress = focus->getAddress();
 		LinphoneCallParams *params;
 		std::shared_ptr<LinphonePrivate::Call> focusCall = nullptr;
 		const auto &remoteAddress = call->getRemoteAddress();
+		const auto conferenceAddressStr =
+		    (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<address-not-defined>"));
+		const auto remoteAddressStr = (remoteAddress ? remoteAddress->toString() : "Unknown");
 		switch (state) {
 			case ConferenceInterface::State::None:
 			case ConferenceInterface::State::Instantiated:
 			case ConferenceInterface::State::CreationFailed: {
-				lInfo() << "Calling the conference focus (" << focus->getAddress() << ")";
-				addr = L_GET_C_BACK_PTR(&(focus->getAddress().asAddress()));
-				if (!addr) return false;
+				lInfo() << "Calling the conference focus (" << focusAddress << ")";
 				params = linphone_core_create_call_params(getCore()->getCCore(), nullptr);
 				// Participant with the focus call is admin
 				L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomContactParameter("admin", Utils::toString(true));
 				linphone_call_params_enable_video(params, confParams->videoEnabled());
 				Conference::setSubject(pendingSubject);
-				auto focusCallC = linphone_core_invite_address_with_params_2(getCore()->getCCore(), addr, params,
-				                                                             L_STRING_TO_C(pendingSubject), nullptr);
+				auto focusCallC = linphone_core_invite_address_with_params_2(
+				    getCore()->getCCore(), focusAddress->toC(), params, L_STRING_TO_C(pendingSubject), nullptr);
 				linphone_call_params_unref(params);
 				if (focusCallC) {
 					focusCall = Call::toCpp(focusCallC)->getSharedFromThis();
@@ -3002,16 +3020,15 @@ bool RemoteConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> cal
 				}
 				auto callIt = std::find(m_pendingCalls.begin(), m_pendingCalls.end(), call);
 				if (callIt == m_pendingCalls.end()) {
-					lInfo() << "Adding call (local address " << call->getLocalAddress().asString() << " remote address "
-					        << (remoteAddress ? remoteAddress->asString() : "Unknown")
-					        << ") to the list of call to add to conference " << getConferenceAddress() << " (" << this
-					        << ")";
+					lInfo() << "Adding call (local address " << call->getLocalAddress()->toString()
+					        << " remote address " << remoteAddressStr << ") to the list of call to add to conference "
+					        << conferenceAddressStr << " (" << this << ")";
 					m_pendingCalls.push_back(call);
-					Conference::addParticipant(*call->getRemoteAddress());
+					Conference::addParticipant(call->getRemoteAddress());
 				} else {
-					lError() << "Trying to add call (local address " << call->getLocalAddress().asString()
-					         << " remote address " << (remoteAddress ? remoteAddress->asString() : "Unknown")
-					         << ") twice to conference " << getConferenceAddress() << " (" << this << ")";
+					lError() << "Trying to add call (local address " << call->getLocalAddress()->toString()
+					         << " remote address " << remoteAddressStr << ") twice to conference "
+					         << conferenceAddressStr << " (" << this << ")";
 				}
 			}
 				return true;
@@ -3019,36 +3036,34 @@ bool RemoteConference::addParticipant(std::shared_ptr<LinphonePrivate::Call> cal
 			case ConferenceInterface::State::Created:
 				if (focus->getSession()) {
 					if (focusIsReady()) {
-						Conference::addParticipant(*call->getRemoteAddress());
+						Conference::addParticipant(call->getRemoteAddress());
 						transferToFocus(call);
 					} else {
 						auto callIt = std::find(m_pendingCalls.begin(), m_pendingCalls.end(), call);
 						if (callIt == m_pendingCalls.end()) {
-							lInfo() << "Adding call (local address " << call->getLocalAddress().asString()
-							        << " remote address " << (remoteAddress ? remoteAddress->asString() : "Unknown")
-							        << ") to the list of call to add to conference " << getConferenceAddress() << " ("
+							lInfo() << "Adding call (local address " << call->getLocalAddress()->toString()
+							        << " remote address " << remoteAddressStr
+							        << ") to the list of call to add to conference " << *getConferenceAddress() << " ("
 							        << this << ")";
 							m_pendingCalls.push_back(call);
 							Conference::addParticipant(call);
 						} else {
-							lError() << "Trying to add call (local address " << call->getLocalAddress().asString()
-							         << " remote address " << (remoteAddress ? remoteAddress->asString() : "Unknown")
-							         << ") twice to conference " << getConferenceAddress() << " (" << this << ")";
+							lError() << "Trying to add call (local address " << call->getLocalAddress()->toString()
+							         << " remote address " << remoteAddressStr << ") twice to conference "
+							         << conferenceAddressStr << " (" << this << ")";
 						}
 					}
 				} else {
-					lInfo() << "Calling the conference focus (" << focus->getAddress() << ")";
-					addr = L_GET_C_BACK_PTR(&(focus->getAddress().asAddress()));
-					if (!addr) return false;
+					lInfo() << "Calling the conference focus (" << focusAddress << ")";
 					params = linphone_core_create_call_params(getCore()->getCCore(), nullptr);
 					// Participant with the focus call is admin
 					L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomContactParameter("admin", Utils::toString(true));
 					linphone_call_params_enable_video(params, confParams->videoEnabled());
 					Conference::setSubject(pendingSubject);
-					focusCall =
-					    Call::toCpp(linphone_core_invite_address_with_params_2(getCore()->getCCore(), addr, params,
-					                                                           L_STRING_TO_C(pendingSubject), nullptr))
-					        ->getSharedFromThis();
+					focusCall = Call::toCpp(linphone_core_invite_address_with_params_2(
+					                            getCore()->getCCore(), focusAddress->toC(), params,
+					                            L_STRING_TO_C(pendingSubject), nullptr))
+					                ->getSharedFromThis();
 					focusCall->setConference(toC());
 					focus->setSession(focusCall->getActiveSession());
 					m_pendingCalls.push_back(call);
@@ -3092,13 +3107,14 @@ bool RemoteConference::finalizeParticipantAddition(BCTBX_UNUSED(std::shared_ptr<
 
 // Removes own address and existing participants from the list.
 // Also removes gruu from kept addresses
-list<IdentityAddress> RemoteConference::cleanAddressesList(const list<IdentityAddress> &addresses) const {
-	list<IdentityAddress> cleanedList(addresses);
-
+list<std::shared_ptr<Address>>
+RemoteConference::cleanAddressesList(const list<std::shared_ptr<Address>> &addresses) const {
+	list<std::shared_ptr<Address>> cleanedList(addresses);
 	cleanedList.sort();
 	cleanedList.unique();
 	for (auto it = cleanedList.begin(); it != cleanedList.end();) {
-		if (findParticipant(*it) || (getMe()->getAddress() == *it)) {
+		auto address = (*it);
+		if (findParticipant(address) || (address->weakEqual(*getMe()->getAddress()))) {
 			it = cleanedList.erase(it);
 		} else {
 			it++;
@@ -3134,22 +3150,22 @@ bool RemoteConference::addParticipants(const std::list<std::shared_ptr<Call>> &c
 	return false;
 }
 
-bool RemoteConference::addParticipants(const list<IdentityAddress> &addresses) {
+bool RemoteConference::addParticipants(const list<std::shared_ptr<Address>> &addresses) {
 #if 0
 	if (getMe()->isAdmin() && !isConferenceEnded()) {
 #endif
 	if (getMe()->isAdmin()) {
 		if ((state == ConferenceInterface::State::Instantiated) ||
 		    (state == ConferenceInterface::State::CreationPending)) {
-			getCore()->createConferenceOnServer(confParams, getMe()->getAddress().asAddress(), addresses);
+			getCore()->createConferenceOnServer(confParams, getMe()->getAddress(), addresses);
 		} else {
 			SalReferOp *referOp = new SalReferOp(getCore()->getCCore()->sal.get());
-			LinphoneAddress *lAddr = L_GET_C_BACK_PTR(&(getConferenceAddress().asAddress()));
+			LinphoneAddress *lAddr = getConferenceAddress()->toC();
 			linphone_configure_op(getCore()->getCCore(), referOp, lAddr, nullptr, true);
 			for (const auto &addr : addresses) {
-				Address referToAddr = addr.asAddress();
-				referToAddr.setParam("isfocus");
-				referOp->sendRefer(referToAddr.getInternalAddress());
+				std::shared_ptr<Address> referToAddr = addr;
+				referToAddr->setParam("isfocus");
+				referOp->sendRefer(referToAddr->getImpl());
 			}
 			referOp->unref();
 		}
@@ -3167,15 +3183,15 @@ bool RemoteConference::addParticipants(const list<IdentityAddress> &addresses) {
 
 int RemoteConference::removeParticipant(const std::shared_ptr<LinphonePrivate::CallSession> &session,
                                         BCTBX_UNUSED(const bool preserveSession)) {
-	const Address &remoteAddress = *session->getRemoteAddress();
+	const std::shared_ptr<Address> &remoteAddress = session->getRemoteAddress();
 	std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(remoteAddress);
 	if (getMe()->isAdmin()) {
 		if (p) {
 			return removeParticipant(p) ? 0 : -1;
 		}
 	} else {
-		lError() << "Unable to remove participant " << p->getAddress().asString() << " because focus "
-		         << getMe()->getAddress().asString() << " is not admin";
+		lError() << "Unable to remove participant " << p->getAddress()->toString() << " because focus "
+		         << getMe()->getAddress()->toString() << " is not admin";
 	}
 	return -1;
 }
@@ -3184,22 +3200,24 @@ bool RemoteConference::removeParticipant(const std::shared_ptr<LinphonePrivate::
 	if (getMe()->isAdmin()) {
 		return (removeParticipant(participant->getAddress()) == 0) ? true : false;
 	} else {
-		lError() << "Unable to remove participant " << participant->getAddress().asString() << " because focus "
-		         << getMe()->getAddress().asString() << " is not admin";
+		lError() << "Unable to remove participant " << participant->getAddress()->toString() << " because focus "
+		         << getMe()->getAddress()->toString() << " is not admin";
 	}
 	return false;
 }
 
-int RemoteConference::removeParticipant(const IdentityAddress &addr) {
+int RemoteConference::removeParticipant(const std::shared_ptr<Address> &addr) {
 	auto session = getMainSession();
 	if (getMe()->isAdmin()) {
+		const auto conferenceAddressStr =
+		    (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<address-not-defined>"));
 		std::shared_ptr<LinphonePrivate::Participant> p = findParticipant(addr);
 		if (p) {
 			switch (state) {
 				case ConferenceInterface::State::Created:
 				case ConferenceInterface::State::TerminationPending: {
 					if (!findParticipant(addr)) {
-						lError() << "Conference: could not remove participant \'" << addr
+						lError() << "Conference: could not remove participant \'" << *addr
 						         << "\': not in the participants list";
 						return -1;
 					}
@@ -3208,30 +3226,30 @@ int RemoteConference::removeParticipant(const IdentityAddress &addr) {
 					LinphoneAddress *lAddr = linphone_address_new(session->getRemoteContact().c_str());
 					linphone_configure_op(cCore, referOp, lAddr, nullptr, false);
 					linphone_address_unref(lAddr);
-					Address referToAddr = addr.asAddress();
-					referToAddr.setMethodParam("BYE");
-					auto res = referOp->sendRefer(referToAddr.getInternalAddress());
+					std::shared_ptr<Address> referToAddr = addr;
+					referToAddr->setMethodParam("BYE");
+					auto res = referOp->sendRefer(referToAddr->getImpl());
 					referOp->unref();
 
 					if (res != 0) {
-						lError() << "Conference: could not remove participant \'" << addr
+						lError() << "Conference: could not remove participant \'" << *addr
 						         << "\': REFER with BYE has failed";
 						return -1;
 					}
 				} break;
 				default:
-					lError() << "Could not remove participant " << addr << " from conference " << getConferenceAddress()
+					lError() << "Could not remove participant " << *addr << " from conference " << conferenceAddressStr
 					         << ". Bad conference state (" << Utils::toString(state) << ")";
 					return -1;
 			}
 			return 0;
 		} else {
-			lWarning() << "Unable to remove participant " << addr.asString()
-			           << " because it is not part of the conference " << getConferenceAddress();
+			lWarning() << "Unable to remove participant " << *addr << " because it is not part of the conference "
+			           << conferenceAddressStr;
 		}
 	} else {
-		lWarning() << "Unable to remove participant " << addr.asString() << " because local participant "
-		           << getMe()->getAddress().asString() << " is not admin.";
+		lWarning() << "Unable to remove participant " << *addr << " because local participant "
+		           << *getMe()->getAddress() << " is not admin.";
 	}
 	return -1;
 }
@@ -3268,7 +3286,7 @@ int RemoteConference::terminate() {
 
 int RemoteConference::enter() {
 	const auto &conferenceAddress = getConferenceAddress();
-	if (!conferenceAddress.isValid()) {
+	if (!conferenceAddress || !conferenceAddress->isValid()) {
 		lError() << "Could not enter in the conference because its conference address (" << conferenceAddress
 		         << ") is not valid";
 		return -1;
@@ -3300,14 +3318,14 @@ int RemoteConference::enter() {
 		L_GET_CPP_PTR_FROM_C_OBJECT(new_params)
 		    ->addCustomContactParameter("admin", Utils::toString(getMe()->isAdmin()));
 
-		const Address &address = getConferenceAddress().asAddress();
-		const string &confId = address.getUriParamValue("conf-id");
+		const std::shared_ptr<Address> &address = getConferenceAddress();
+		const string &confId = address->getUriParamValue("conf-id");
 		linphone_call_params_set_conference_id(new_params, confId.c_str());
 
 		std::string subject = getMe()->isAdmin() ? getSubject() : std::string();
 
-		auto cCall = linphone_core_invite_address_with_params_2(getCore()->getCCore(), L_GET_C_BACK_PTR(&address),
-		                                                        new_params, L_STRING_TO_C(subject), nullptr);
+		auto cCall = linphone_core_invite_address_with_params_2(getCore()->getCCore(), address->toC(), new_params,
+		                                                        L_STRING_TO_C(subject), nullptr);
 
 		linphone_call_params_unref(new_params);
 
@@ -3327,17 +3345,17 @@ void RemoteConference::leave() {
 	LinphoneCallState callState = static_cast<LinphoneCallState>(session->getState());
 	switch (callState) {
 		case LinphoneCallPaused:
-			lInfo() << getMe()->getAddress() << " is leaving conference " << getConferenceAddress()
+			lInfo() << getMe()->getAddress() << " is leaving conference " << *getConferenceAddress()
 			        << " while focus call is paused.";
 			break;
 		case LinphoneCallStreamsRunning:
-			lInfo() << getMe()->getAddress() << " is leaving conference " << getConferenceAddress()
+			lInfo() << getMe()->getAddress() << " is leaving conference " << *getConferenceAddress()
 			        << ". Focus call is going to be paused.";
 			session->pause();
 			participantDeviceLeft(me, me->getDevices().front());
 			break;
 		default:
-			lError() << getMe()->getAddress() << " cannot leave conference " << getConferenceAddress()
+			lError() << getMe()->getAddress() << " cannot leave conference " << *getConferenceAddress()
 			         << " because focus call is in state " << linphone_call_state_to_string(callState);
 	}
 }
@@ -3353,12 +3371,12 @@ bool RemoteConference::isIn() const {
 	       focusContactAddress->hasUriParam("conf-id");
 }
 
-IdentityAddress RemoteConference::getOrganizer() const {
-	IdentityAddress organizer;
+const std::shared_ptr<Address> RemoteConference::getOrganizer() const {
+	std::shared_ptr<Address> organizer = nullptr;
 #ifdef HAVE_DB_STORAGE
 	auto &mainDb = getCore()->getPrivate()->mainDb;
-	if (mainDb)  {
-		const auto & confInfo = mainDb->getConferenceInfoFromURI(getConferenceAddress());
+	if (mainDb) {
+		const auto &confInfo = mainDb->getConferenceInfoFromURI(getConferenceAddress());
 		// me is admin if the organizer is the same as me
 		if (confInfo) {
 			organizer = confInfo->getOrganizerAddress();
@@ -3368,7 +3386,7 @@ IdentityAddress RemoteConference::getOrganizer() const {
 	return organizer;
 }
 
-bool RemoteConference::focusIsReady () const {
+bool RemoteConference::focusIsReady() const {
 	LinphoneCallState focusState;
 	const auto &session = getMainSession();
 	if (!session || !session->getRemoteContactAddress()) return false;
@@ -3378,27 +3396,27 @@ bool RemoteConference::focusIsReady () const {
 
 bool RemoteConference::transferToFocus(std::shared_ptr<LinphonePrivate::Call> call) {
 	auto session = getMainSession();
-	Address referToAddr(*session->getRemoteContactAddress());
-	const Address &remoteAddress = *call->getRemoteAddress();
+	std::shared_ptr<Address> referToAddr(session->getRemoteContactAddress());
+	const std::shared_ptr<Address> &remoteAddress = call->getRemoteAddress();
 	std::shared_ptr<Participant> participant = findParticipant(remoteAddress);
 	if (participant) {
-		referToAddr.setParam("admin", Utils::toString(participant->isAdmin()));
+		referToAddr->setParam("admin", Utils::toString(participant->isAdmin()));
 		const auto &remoteAddress = call->getRemoteAddress();
-		lInfo() << "Transfering call (local address " << call->getLocalAddress().asString() << " remote address "
-		        << (remoteAddress ? remoteAddress->asString() : "Unknown") << ") to focus " << referToAddr;
+		lInfo() << "Transfering call (local address " << call->getLocalAddress()->toString() << " remote address "
+		        << (remoteAddress ? remoteAddress->toString() : "Unknown") << ") to focus " << referToAddr;
 #ifdef HAVE_DB_STORAGE
 		const auto &participantAddress = participant->getAddress();
 		updateParticipantsInConferenceInfo(participantAddress);
 #endif
-		if (call->transfer(referToAddr.asString()) == 0) {
+		if (call->transfer(referToAddr->toString()) == 0) {
 			m_transferingCalls.push_back(call);
 			return true;
 		} else {
-			lError() << "Conference: could not transfer call " << call << " to " << referToAddr.asString();
+			lError() << "Conference: could not transfer call " << call << " to " << referToAddr->toString();
 			return false;
 		}
 	} else {
-		lError() << "Conference: could not transfer call " << call << " to " << referToAddr.asString()
+		lError() << "Conference: could not transfer call " << call << " to " << referToAddr->toString()
 		         << " because participant with session " << call->getActiveSession()
 		         << " cannot be found  - guessed address " << referToAddr;
 		return false;
@@ -3419,18 +3437,15 @@ void RemoteConference::reset() {
 
 void RemoteConference::onFocusCallStateChanged(LinphoneCallState state) {
 	auto session = getMainSession();
-	Address focusContactAddress;
+	std::shared_ptr<Address> focusContactAddress;
 	std::shared_ptr<Call> call = nullptr;
 
-	ConferenceId confId = getConferenceId();
-	Address peerAddress(confId.getPeerAddress().asAddress());
+	// Take a ref as conference may be deleted when the call goes to states PausedByRemote or End
+	shared_ptr<Conference> ref = getSharedFromThis();
 	SalCallOp *op = nullptr;
 
 	if (session) {
-		auto focusContactAddressPtr = session->getRemoteContactAddress();
-		if (focusContactAddressPtr) {
-			focusContactAddress = *focusContactAddressPtr;
-		}
+		focusContactAddress = session->getRemoteContactAddress();
 		op = session->getPrivate()->getOp();
 		call = op ? getCore()->getCallByCallId(op->getCallId()) : nullptr;
 	}
@@ -3452,14 +3467,14 @@ void RemoteConference::onFocusCallStateChanged(LinphoneCallState state) {
 			for (const auto &device : getParticipantDevices()) {
 				device->updateStreamAvailabilities();
 			}
-			if (focusContactAddress.hasParam("isfocus") &&
+			if (focusContactAddress->hasParam("isfocus") &&
 			    ((call && !call->mediaInProgress()) ||
 			     !!!linphone_config_get_int(linphone_core_get_config(session->getCore()->getCCore()), "sip",
 			                                "update_call_when_ice_completed", TRUE)) &&
 			    finalized && fullStateReceived && (getState() == ConferenceInterface::State::CreationPending)) {
 				auto requestStreams = [this]() -> LinphoneStatus {
 					lInfo() << "Sending re-INVITE in order to get streams after joining conference "
-					        << getConferenceAddress();
+					        << *getConferenceAddress();
 					setState(ConferenceInterface::State::Created);
 					auto ret = updateMainSession();
 					return ret;
@@ -3467,11 +3482,9 @@ void RemoteConference::onFocusCallStateChanged(LinphoneCallState state) {
 
 				if (requestStreams() != 0) {
 					lInfo() << "Delaying re-INVITE in order to get streams after joining conference "
-					        << getConferenceAddress()
+					        << *getConferenceAddress()
 					        << " because the dialog is not available yet to accept this transaction";
-					if (call) {
-						call->getActiveSession()->addPendingAction(requestStreams);
-					}
+					scheduleUpdate = true;
 				}
 			}
 		}
@@ -3479,7 +3492,7 @@ void RemoteConference::onFocusCallStateChanged(LinphoneCallState state) {
 		case LinphoneCallConnected:
 		case LinphoneCallPaused:
 		case LinphoneCallUpdatedByRemote:
-			if (focusContactAddress.hasParam("isfocus")) {
+			if (focusContactAddress->hasParam("isfocus")) {
 				setConferenceAddress(focusContactAddress);
 				it = m_pendingCalls.begin();
 				while (it != m_pendingCalls.end()) {
@@ -3492,11 +3505,11 @@ void RemoteConference::onFocusCallStateChanged(LinphoneCallState state) {
 				}
 
 				if (!finalized) {
-					setConferenceId(
-					    ConferenceId(ConferenceAddress(focusContactAddress), getConferenceId().getLocalAddress()));
+					setConferenceId(ConferenceId(std::shared_ptr<Address>(focusContactAddress),
+					                             getConferenceId().getLocalAddress()));
 					if (call) {
-						if (focusContactAddress.hasUriParam("conf-id")) {
-							call->setConferenceId(focusContactAddress.getUriParamValue("conf-id"));
+						if (focusContactAddress->hasUriParam("conf-id")) {
+							call->setConferenceId(focusContactAddress->getUriParamValue("conf-id"));
 						}
 						if (!call->mediaInProgress() ||
 						    !!!linphone_config_get_int(linphone_core_get_config(session->getCore()->getCCore()), "sip",
@@ -3508,10 +3521,10 @@ void RemoteConference::onFocusCallStateChanged(LinphoneCallState state) {
 			}
 			BCTBX_NO_BREAK; /* Intentional no break */
 		case LinphoneCallPausedByRemote:
-			if (!focusContactAddress.hasParam("isfocus") && (state != LinphoneCallConnected)) {
+			if (!focusContactAddress->hasParam("isfocus") && (state != LinphoneCallConnected)) {
 				// The call was in conference and the focus removed its attribute to show that the call exited the
 				// conference
-				lInfo() << "Ending conference " << this << "(" << getConferenceAddress()
+				lInfo() << "Ending conference " << this << "(" << *getConferenceAddress()
 				        << ") because server removed isfocus attribute from its remote address " << focusContactAddress;
 				endConference();
 			}
@@ -3527,18 +3540,34 @@ void RemoteConference::onFocusCallStateChanged(LinphoneCallState state) {
 			}
 			break;
 		case LinphoneCallEnd:
-			lInfo() << "Ending conference " << this << "(" << getConferenceAddress()
+			lInfo() << "Ending conference " << this << "(" << *getConferenceAddress()
 			        << ") because focus call (local address "
-			        << (session ? session->getLocalAddress().asString() : "<unknown>") << " remote address "
-			        << (session ? session->getRemoteAddress()->asString() : "<unknown>") << ") has ended";
+			        << (session ? session->getLocalAddress()->toString() : "<unknown>") << " remote address "
+			        << (session ? session->getRemoteAddress()->toString() : "<unknown>") << ") has ended";
 			endConference();
 			break;
 		default:
 			break;
 	}
+
+	const auto &confState = ref->getState();
+	// Do not send updates if the conference is ending or about to end
+	if ((confState != ConferenceInterface::State::Terminated) &&
+	    (confState != ConferenceInterface::State::TerminationPending) && scheduleUpdate) {
+		lInfo() << "Executing scheduled update of the focus session of conference "
+		        << (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<address-not-defined>"));
+		if (updateMainSession() == 0) {
+			scheduleUpdate = false;
+		} else {
+			lInfo() << "Scheduled update of the focus session of conference "
+			        << (getConferenceAddress() ? getConferenceAddress()->toString()
+			                                   : std::string("<address-not-defined>"))
+			        << " cannot be executed right now - Retrying at the next state change";
+		}
+	}
 }
 
-void RemoteConference::onConferenceTerminated(const IdentityAddress &addr) {
+void RemoteConference::onConferenceTerminated(const std::shared_ptr<Address> &addr) {
 	auto session = getMainSession();
 	std::shared_ptr<Call> call = nullptr;
 	SalCallOp *op = nullptr;
@@ -3754,8 +3783,8 @@ void RemoteConference::setParticipantAdminStatus(const shared_ptr<Participant> &
 	if (isAdmin == participant->isAdmin()) return;
 
 	if (!getMe()->isAdmin()) {
-		lError() << "Unable to set admin status of participant " << participant->getAddress().asString() << " to "
-		         << (isAdmin ? "true" : "false") << " because focus " << getMe()->getAddress().asString()
+		lError() << "Unable to set admin status of participant " << participant->getAddress()->toString() << " to "
+		         << (isAdmin ? "true" : "false") << " because focus " << getMe()->getAddress()->toString()
 		         << " is not admin";
 		return;
 	}
@@ -3767,15 +3796,15 @@ void RemoteConference::setParticipantAdminStatus(const shared_ptr<Participant> &
 	LinphoneAddress *lAddr = linphone_address_new(session->getRemoteContact().c_str());
 	linphone_configure_op(cCore, referOp, lAddr, nullptr, false);
 	linphone_address_unref(lAddr);
-	Address referToAddr = participant->getAddress().asAddress();
-	referToAddr.setParam("admin", Utils::toString(isAdmin));
-	referOp->sendRefer(referToAddr.getInternalAddress());
+	std::shared_ptr<Address> referToAddr = participant->getAddress();
+	referToAddr->setParam("admin", Utils::toString(isAdmin));
+	referOp->sendRefer(referToAddr->getImpl());
 	referOp->unref();
 }
 
 void RemoteConference::setSubject(const std::string &subject) {
 	if (!getMe()->isAdmin()) {
-		lError() << "Unable to update conference subject because focus " << getMe()->getAddress().asString()
+		lError() << "Unable to update conference subject because focus " << getMe()->getAddress()->toString()
 		         << " is not admin";
 		return;
 	}
@@ -3818,24 +3847,23 @@ bool RemoteConference::update(const LinphonePrivate::ConferenceParamsInterface &
 	if (getMe()->isAdmin()) {
 		ret = Conference::update(newParameters);
 	} else {
-		lError() << "Unable to update conference parameters because focus " << getMe()->getAddress().asString()
+		lError() << "Unable to update conference parameters because focus " << getMe()->getAddress()->toString()
 		         << " is not admin";
 	}
-
 	return ret;
 }
 
 std::shared_ptr<Call> RemoteConference::getCall() const {
 	auto session = getMainSession();
 	if (session) {
-		return getCore()->getCallByRemoteAddress(*session->getRemoteAddress());
+		return getCore()->getCallByRemoteAddress(session->getRemoteAddress());
 	}
 	return nullptr;
 }
 
 void RemoteConference::onParticipantAdded(const shared_ptr<ConferenceParticipantEvent> &event,
                                           const std::shared_ptr<Participant> &participant) {
-	const IdentityAddress &pAddr = event->getParticipantAddress();
+	const std::shared_ptr<Address> &pAddr = event->getParticipantAddress();
 
 #ifdef HAVE_DB_STORAGE
 	const auto &participantAddress = participant->getAddress();
@@ -3851,11 +3879,11 @@ void RemoteConference::onParticipantAdded(const shared_ptr<ConferenceParticipant
 				if (!eventHandler) {
 					eventHandler = std::make_shared<RemoteConferenceEventHandler>(this, this);
 				}
-				lInfo() << "Subscribing me (address " << pAddr << ") to conference " << getConferenceAddress();
+				lInfo() << "Subscribing me (address " << *pAddr << ") to conference " << *getConferenceAddress();
 				eventHandler->subscribe(getConferenceId());
 			} else {
 #endif // HAVE_ADVANCED_IM
-				lInfo() << "Unable to send SUBSCRIBE following me " << participant->getAddress()
+				lInfo() << "Unable to send SUBSCRIBE following me " << *participant->getAddress()
 				        << " being added because conference event package (RFC 4575) is disabled or the SDK was not "
 				           "compiled with ENABLE_ADVANCED_IM flag set to on";
 #ifdef HAVE_ADVANCED_IM
@@ -3863,22 +3891,22 @@ void RemoteConference::onParticipantAdded(const shared_ptr<ConferenceParticipant
 #endif // HAVE_ADVANCED_IM
 		}
 	} else if (findParticipant(pAddr)) {
-		lInfo() << "Addition of participant with address " << pAddr << " to conference " << getConferenceAddress()
+		lInfo() << "Addition of participant with address " << *pAddr << " to conference " << *getConferenceAddress()
 		        << " has been successful";
 	} else {
-		lWarning() << "Addition of participant with address " << pAddr
+		lWarning() << "Addition of participant with address " << *pAddr
 		           << " has been failed because the participant is not part of the conference"
-		           << getConferenceAddress();
+		           << *getConferenceAddress();
 	}
 }
 
 void RemoteConference::onParticipantRemoved(const shared_ptr<ConferenceParticipantEvent> &event,
                                             BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
-	const IdentityAddress &pAddr = event->getParticipantAddress();
+	const std::shared_ptr<Address> &pAddr = event->getParticipantAddress();
 
 	if (isMe(pAddr)) {
-		lInfo() << "Unsubscribing all devices of me (address " << pAddr << ") from conference "
-		        << getConferenceAddress();
+		lInfo() << "Unsubscribing all devices of me (address " << *pAddr << ") from conference "
+		        << *getConferenceAddress();
 		// Unsubscribe all devices of me
 		std::for_each(getMe()->getDevices().cbegin(), getMe()->getDevices().cend(),
 		              [&](const std::shared_ptr<ParticipantDevice> &device) {
@@ -3890,12 +3918,12 @@ void RemoteConference::onParticipantRemoved(const shared_ptr<ConferenceParticipa
 			              }
 		              });
 	} else if (!findParticipant(pAddr)) {
-		lInfo() << "Removal of participant with address " << pAddr << " from conference " << getConferenceAddress()
+		lInfo() << "Removal of participant with address " << *pAddr << " from conference " << *getConferenceAddress()
 		        << " has been successful";
 	} else {
-		lWarning() << "Removal of participant with address " << pAddr
+		lWarning() << "Removal of participant with address " << *pAddr
 		           << " has been failed because the participant is still part of the conference"
-		           << getConferenceAddress();
+		           << *getConferenceAddress();
 	}
 }
 
@@ -3918,18 +3946,18 @@ void RemoteConference::onParticipantDeviceRemoved(
 	    !isMe(device->getAddress()) && (device->getTimeOfJoining() >= 0)) {
 		auto updateSession = [this, device]() -> LinphoneStatus {
 			lInfo() << "Sending re-INVITE in order to update streams because participant device "
-			        << device->getAddress() << " has been removed from conference " << getConferenceAddress();
+			        << *device->getAddress() << " has been removed from conference " << *getConferenceAddress();
 			auto ret = updateMainSession();
 			if (ret != 0) {
-				lInfo() << "re-INVITE to update streams because participant device " << device->getAddress()
-				        << " has been removed from conference " << getConferenceAddress()
+				lInfo() << "re-INVITE to update streams because participant device " << *device->getAddress()
+				        << " has been removed from conference " << *getConferenceAddress()
 				        << " cannot be sent right now";
 			}
 			return ret;
 		};
 
 		if (updateSession() != 0) {
-			session->addPendingAction(updateSession);
+			scheduleUpdate = true;
 		}
 	}
 }
@@ -3942,9 +3970,9 @@ void RemoteConference::onParticipantDeviceStateChanged(
 
 	auto callIt = std::find_if(m_pendingCalls.cbegin(), m_pendingCalls.cend(), [&device](const auto &call) {
 		if (!call) return false;
-		const auto &devAddr = device->getAddress().asAddress();
-		const auto &contactAddress = *(call->getActiveSession()->getRemoteContactAddress());
-		return (devAddr == contactAddress);
+		const auto &devAddr = device->getAddress();
+		const auto contactAddress = call->getActiveSession()->getRemoteContactAddress()->getUri();
+		return (*devAddr == contactAddress);
 	});
 
 	const auto &videoDir = device->getStreamCapability(LinphoneStreamTypeVideo);
@@ -3952,43 +3980,41 @@ void RemoteConference::onParticipantDeviceStateChanged(
 	    (callIt == m_pendingCalls.cend()) && isIn() && (device->getState() == ParticipantDevice::State::Present) &&
 	    ((videoDir == LinphoneMediaDirectionSendOnly) || (videoDir == LinphoneMediaDirectionSendRecv))) {
 		auto updateSession = [this, device]() -> LinphoneStatus {
-			lInfo() << "Sending re-INVITE in order to get streams for participant device " << device->getAddress()
-			        << " that joined recently the conference " << getConferenceAddress();
+			lInfo() << "Sending re-INVITE in order to get streams for participant device " << *device->getAddress()
+			        << " that joined recently the conference " << *getConferenceAddress();
 			auto ret = updateMainSession();
 			if (ret != 0) {
-				lInfo() << "re-INVITE to get streams for participant device " << device->getAddress()
-				        << " that recently joined the conference " << getConferenceAddress()
+				lInfo() << "re-INVITE to get streams for participant device " << *device->getAddress()
+				        << " that recently joined the conference " << *getConferenceAddress()
 				        << " cannot be sent right now";
 			}
 			return ret;
 		};
 
 		if (updateSession() != 0) {
-			session->addPendingAction(updateSession);
+			scheduleUpdate = true;
 		}
 	}
 }
 
 void RemoteConference::onParticipantDeviceMediaAvailabilityChanged(
+
     BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantDeviceEvent> &event),
     const std::shared_ptr<ParticipantDevice> &device) {
 	if ((!isMe(device->getAddress())) && (getState() == ConferenceInterface::State::Created) && isIn()) {
 		auto updateSession = [this, device]() -> LinphoneStatus {
-			lInfo() << "Sending re-INVITE because device " << device->getAddress()
+			lInfo() << "Sending re-INVITE because device " << *device->getAddress()
 			        << " has changed its stream availability";
 			auto ret = updateMainSession();
 			if (ret != 0) {
-				lInfo() << "re-INVITE due to device " << device->getAddress()
+				lInfo() << "re-INVITE due to device " << *device->getAddress()
 				        << " changing its stream availability cannot be sent right now";
 			}
 			return ret;
 		};
 
 		if (updateSession() != 0) {
-			auto session = static_pointer_cast<MediaSession>(getMainSession());
-			if (session) {
-				session->addPendingAction(updateSession);
-			}
+			scheduleUpdate = true;
 		}
 	}
 }
@@ -4006,13 +4032,13 @@ void RemoteConference::onFullStateReceived() {
 	// address of the call
 	auto &mainDb = getCore()->getPrivate()->mainDb;
 	if (mainDb) {
-		lInfo() << "Inserting conference information to database related to conference " << getConferenceAddress();
+		lInfo() << "Inserting conference information to database related to conference " << *getConferenceAddress();
 		mainDb->insertConferenceInfo(conferenceInfo);
 	}
 #endif // HAVE_DB_STORAGE
 
 	auto requestStreams = [this]() -> LinphoneStatus {
-		lInfo() << "Sending re-INVITE in order to get streams after joining conference " << getConferenceAddress();
+		lInfo() << "Sending re-INVITE in order to get streams after joining conference " << *getConferenceAddress();
 		setState(ConferenceInterface::State::Created);
 		auto ret = updateMainSession();
 		return ret;
@@ -4029,7 +4055,7 @@ void RemoteConference::onFullStateReceived() {
 	                                                               "sip", "update_call_when_ice_completed", TRUE))) {
 		requestStreams();
 	} else {
-		lInfo() << "Delaying re-INVITE in order to get streams after joining conference " << getConferenceAddress()
+		lInfo() << "Delaying re-INVITE in order to get streams after joining conference " << *getConferenceAddress()
 		        << " because ICE negotiations didn't end yet";
 	}
 
@@ -4052,7 +4078,7 @@ void RemoteConference::onAvailableMediaChanged(
 		};
 
 		if (updateSession() != 0) {
-			session->addPendingAction(updateSession);
+			scheduleUpdate = true;
 		}
 	}
 }
diff --git a/coreapi/conference_private.h b/coreapi/conference_private.h
index a4f87846652546885117dc390901b314b991c7ba..870c769a50e6afbd2f287263100a96fc8ef28006 100644
--- a/coreapi/conference_private.h
+++ b/coreapi/conference_private.h
@@ -122,15 +122,15 @@ class LINPHONE_PUBLIC Conference : public bellesip::HybridObject<LinphoneConfere
 #endif // HAVE_ADVANCED_IM
 public:
 	Conference(const std::shared_ptr<Core> &core,
-	           const IdentityAddress &myAddress,
+	           const std::shared_ptr<Address> &myAddress,
 	           CallSessionListener *listener,
 	           const std::shared_ptr<ConferenceParams> params);
 	virtual ~Conference();
 
-	virtual int inviteAddresses(const std::list<const LinphoneAddress *> &addresses,
+	virtual int inviteAddresses(const std::list<std::shared_ptr<Address>> &addresses,
 	                            const LinphoneCallParams *params) = 0;
-	virtual bool dialOutAddresses(const std::list<const LinphoneAddress *> &addressList) = 0;
-	virtual bool addParticipant(const IdentityAddress &participantAddress) override;
+	virtual bool dialOutAddresses(const std::list<std::shared_ptr<Address>> &addressList) = 0;
+	virtual bool addParticipant(const std::shared_ptr<Address> &participantAddress) override;
 	virtual bool addParticipant(std::shared_ptr<LinphonePrivate::Call> call) override;
 	virtual bool finalizeParticipantAddition(std::shared_ptr<LinphonePrivate::Call> call) = 0;
 
@@ -140,7 +140,7 @@ public:
 	int removeParticipant(std::shared_ptr<LinphonePrivate::Call> call);
 	virtual int removeParticipant(const std::shared_ptr<LinphonePrivate::CallSession> &session,
 	                              const bool preserveSession);
-	virtual int removeParticipant(const IdentityAddress &addr) = 0;
+	virtual int removeParticipant(const std::shared_ptr<Address> &addr) = 0;
 	virtual bool removeParticipant(const std::shared_ptr<LinphonePrivate::Participant> &participant) override;
 
 	virtual bool
@@ -148,7 +148,7 @@ public:
 
 	virtual int
 	participantDeviceMediaCapabilityChanged(const std::shared_ptr<LinphonePrivate::CallSession> &session) = 0;
-	virtual int participantDeviceMediaCapabilityChanged(const IdentityAddress &addr) = 0;
+	virtual int participantDeviceMediaCapabilityChanged(const std::shared_ptr<Address> &addr) = 0;
 	virtual int
 	participantDeviceMediaCapabilityChanged(const std::shared_ptr<LinphonePrivate::Participant> &participant,
 	                                        const std::shared_ptr<LinphonePrivate::ParticipantDevice> &device) = 0;
@@ -177,7 +177,7 @@ public:
 	virtual int enter() = 0;
 	virtual void leave() override = 0;
 
-	virtual IdentityAddress getOrganizer() const = 0;
+	virtual const std::shared_ptr<Address> getOrganizer() const = 0;
 
 	bool isConferenceEnded() const;
 	bool isConferenceStarted() const;
@@ -209,9 +209,8 @@ public:
 	                                       bool isAdmin) override;
 
 	virtual void join() override;
-	virtual void join(const IdentityAddress &participantAddress) override;
-
-	virtual void onConferenceTerminated(const IdentityAddress &addr) override;
+	virtual void join(const std::shared_ptr<Address> &participantAddress) override;
+	virtual void onConferenceTerminated(const std::shared_ptr<Address> &addr) override;
 
 	void setID(const std::string &conferenceID) {
 		mConferenceID = conferenceID;
@@ -220,12 +219,12 @@ public:
 		return mConferenceID;
 	}
 
-	void setConferenceAddress(const ConferenceAddress &conferenceAddress);
+	void setConferenceAddress(const std::shared_ptr<Address> &conferenceAddress);
 	void setConferenceId(const ConferenceId &conferenceId);
 	virtual void notifyStateChanged(LinphonePrivate::ConferenceInterface::State state) override;
 
 protected:
-	std::list<IdentityAddress> invitedAddresses;
+	std::list<std::shared_ptr<Address>> invitedAddresses;
 	std::shared_ptr<LinphonePrivate::ConferenceInfo> conferenceInfo = nullptr;
 
 	// Legacy member
@@ -250,33 +249,33 @@ protected:
 class LINPHONE_PUBLIC LocalConference : public Conference {
 public:
 	LocalConference(const std::shared_ptr<Core> &core,
-	                const IdentityAddress &myAddress,
+	                const std::shared_ptr<Address> &myAddress,
 	                CallSessionListener *listener,
 	                const std::shared_ptr<ConferenceParams> params);
 	LocalConference(const std::shared_ptr<Core> &core, SalCallOp *op);
 
 	virtual ~LocalConference();
 
-	virtual int inviteAddresses(const std::list<const LinphoneAddress *> &addresses,
+	virtual int inviteAddresses(const std::list<std::shared_ptr<Address>> &addresses,
 	                            const LinphoneCallParams *params) override;
-	virtual bool dialOutAddresses(const std::list<const LinphoneAddress *> &addressList) override;
+	virtual bool dialOutAddresses(const std::list<std::shared_ptr<Address>> &addressList) override;
 	virtual bool addParticipants(const std::list<std::shared_ptr<LinphonePrivate::Call>> &call) override;
-	virtual bool addParticipants(const std::list<IdentityAddress> &addresses) override;
+	virtual bool addParticipants(const std::list<std::shared_ptr<Address>> &addresses) override;
 	virtual bool addParticipant(std::shared_ptr<LinphonePrivate::Call> call) override;
-	virtual bool addParticipant(const IdentityAddress &participantAddress) override;
+	virtual bool addParticipant(const std::shared_ptr<Address> &participantAddress) override;
 	virtual bool finalizeParticipantAddition(std::shared_ptr<LinphonePrivate::Call> call) override;
 	virtual bool addParticipantDevice(std::shared_ptr<LinphonePrivate::Call> call) override;
 
 	virtual int removeParticipant(const std::shared_ptr<LinphonePrivate::CallSession> &session,
 	                              const bool preserveSession) override;
-	virtual int removeParticipant(const IdentityAddress &addr) override;
+	virtual int removeParticipant(const std::shared_ptr<Address> &addr) override;
 	virtual bool removeParticipant(const std::shared_ptr<LinphonePrivate::Participant> &participant) override;
 	virtual bool update(const ConferenceParamsInterface &params) override;
 	virtual int terminate() override;
 	virtual void finalizeCreation() override;
-	virtual void onConferenceTerminated(const IdentityAddress &addr) override;
+	virtual void onConferenceTerminated(const std::shared_ptr<Address> &addr) override;
 	virtual void setSubject(const std::string &subject) override;
-	virtual IdentityAddress getOrganizer() const override;
+	virtual const std::shared_ptr<Address> getOrganizer() const override;
 
 	virtual int enter() override;
 	virtual void leave() override;
@@ -298,7 +297,7 @@ public:
 
 	virtual int
 	participantDeviceMediaCapabilityChanged(const std::shared_ptr<LinphonePrivate::CallSession> &session) override;
-	virtual int participantDeviceMediaCapabilityChanged(const IdentityAddress &addr) override;
+	virtual int participantDeviceMediaCapabilityChanged(const std::shared_ptr<Address> &addr) override;
 	virtual int
 	participantDeviceMediaCapabilityChanged(const std::shared_ptr<LinphonePrivate::Participant> &participant,
 	                                        const std::shared_ptr<LinphonePrivate::ParticipantDevice> &device) override;
@@ -376,7 +375,7 @@ protected:
 private:
 	std::unique_ptr<MixerSession> mMixerSession;
 	bool mIsIn = false;
-	IdentityAddress organizer;
+	std::shared_ptr<Address> organizer;
 	static constexpr int confIdLength = 10;
 
 	bool updateAllParticipantSessionsExcept(const std::shared_ptr<CallSession> &session);
@@ -387,7 +386,7 @@ private:
 	std::shared_ptr<CallSession> makeSession(const std::shared_ptr<ParticipantDevice> &device);
 	void chooseAnotherAdminIfNoneInConference();
 	void checkIfTerminated();
-	std::list<IdentityAddress> getAllowedAddresses() const;
+	std::list<std::shared_ptr<Address>> getAllowedAddresses() const;
 	void configure(SalCallOp *op);
 
 	void addLocalEndpoint();
@@ -406,7 +405,7 @@ private:
 class LINPHONE_PUBLIC RemoteConference : public Conference, public ConferenceListenerInterface {
 public:
 	RemoteConference(const std::shared_ptr<Core> &core,
-	                 const IdentityAddress &focusAddr,
+	                 const std::shared_ptr<Address> &focusAddr,
 	                 const ConferenceId &conferenceId,
 	                 CallSessionListener *listener,
 	                 const std::shared_ptr<ConferenceParams> params);
@@ -417,27 +416,27 @@ public:
 	                 const std::shared_ptr<ConferenceParams> params);
 	RemoteConference(const std::shared_ptr<Core> &core,
 	                 const std::shared_ptr<LinphonePrivate::CallSession> &focusSession,
-	                 const ConferenceAddress &confAddr,
+	                 const std::shared_ptr<Address> &confAddr,
 	                 const ConferenceId &conferenceId,
-	                 const std::list<IdentityAddress> &invitees,
+	                 const std::list<std::shared_ptr<Address>> &invitees,
 	                 CallSessionListener *listener,
 	                 const std::shared_ptr<LinphonePrivate::ConferenceParams> params);
 
 	virtual ~RemoteConference();
 
-	virtual int inviteAddresses(const std::list<const LinphoneAddress *> &addresses,
+	virtual int inviteAddresses(const std::list<std::shared_ptr<Address>> &addresses,
 	                            const LinphoneCallParams *params) override;
-	virtual bool dialOutAddresses(const std::list<const LinphoneAddress *> &addressList) override;
+	virtual bool dialOutAddresses(const std::list<std::shared_ptr<Address>> &addressList) override;
 	virtual bool addParticipants(const std::list<std::shared_ptr<LinphonePrivate::Call>> &call) override;
-	virtual bool addParticipants(const std::list<IdentityAddress> &addresses) override;
+	virtual bool addParticipants(const std::list<std::shared_ptr<Address>> &addresses) override;
 	virtual bool addParticipant(std::shared_ptr<LinphonePrivate::Call> call) override;
-	virtual bool addParticipant(const IdentityAddress &participantAddress) override;
+	virtual bool addParticipant(const std::shared_ptr<Address> &participantAddress) override;
 	virtual bool addParticipantDevice(std::shared_ptr<LinphonePrivate::Call> call) override;
 	virtual bool finalizeParticipantAddition(std::shared_ptr<LinphonePrivate::Call> call) override;
 
 	virtual int removeParticipant(const std::shared_ptr<LinphonePrivate::CallSession> &session,
 	                              const bool preserveSession) override;
-	virtual int removeParticipant(const IdentityAddress &addr) override;
+	virtual int removeParticipant(const std::shared_ptr<Address> &addr) override;
 	virtual bool removeParticipant(const std::shared_ptr<LinphonePrivate::Participant> &participant) override;
 	virtual int terminate() override;
 	virtual void finalizeCreation() override;
@@ -445,7 +444,7 @@ public:
 	virtual int enter() override;
 	virtual void leave() override;
 	virtual bool isIn() const override;
-	virtual IdentityAddress getOrganizer() const override;
+	virtual const std::shared_ptr<Address> getOrganizer() const override;
 
 	virtual int startRecording(const char *path) override;
 	virtual int stopRecording() override;
@@ -463,7 +462,7 @@ public:
 
 	virtual int
 	participantDeviceMediaCapabilityChanged(const std::shared_ptr<LinphonePrivate::CallSession> &session) override;
-	virtual int participantDeviceMediaCapabilityChanged(const IdentityAddress &addr) override;
+	virtual int participantDeviceMediaCapabilityChanged(const std::shared_ptr<Address> &addr) override;
 	virtual int
 	participantDeviceMediaCapabilityChanged(const std::shared_ptr<LinphonePrivate::Participant> &participant,
 	                                        const std::shared_ptr<LinphonePrivate::ParticipantDevice> &device) override;
@@ -514,7 +513,7 @@ public:
 	void setMainSession(const std::shared_ptr<LinphonePrivate::CallSession> &session);
 	virtual std::shared_ptr<Call> getCall() const override;
 
-	virtual void onConferenceTerminated(const IdentityAddress &addr) override;
+	virtual void onConferenceTerminated(const std::shared_ptr<Address> &addr) override;
 	virtual void onParticipantsCleared() override;
 
 #ifdef HAVE_ADVANCED_IM
@@ -544,13 +543,14 @@ private:
 	                                   LinphoneCallState newCallState);
 
 	bool finalized = false;
+	bool scheduleUpdate = false;
 	bool fullStateReceived = false;
 	std::string pendingSubject;
 	std::shared_ptr<Participant> focus;
 	std::list<std::shared_ptr<LinphonePrivate::Call>> m_pendingCalls;
 	std::list<std::shared_ptr<LinphonePrivate::Call>> m_transferingCalls;
 
-	std::list<IdentityAddress> cleanAddressesList(const std::list<IdentityAddress> &addresses) const;
+	std::list<std::shared_ptr<Address>> cleanAddressesList(const std::list<std::shared_ptr<Address>> &addresses) const;
 };
 
 } // end of namespace MediaConference
diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c
index 0d988e5f4bb19fb03d1384af366fab61f42a9070..30f05a7adbe3134ed5f4619f79f04b3c33f6191f 100644
--- a/coreapi/friendlist.c
+++ b/coreapi/friendlist.c
@@ -625,10 +625,10 @@ void linphone_friend_list_set_display_name(LinphoneFriendList *list, const char
 	}
 }
 
-const LinphoneAddress *linphone_friend_list_get_rls_address(const LinphoneFriendList *list) {
+LinphoneAddress *linphone_friend_list_get_rls_address(const LinphoneFriendList *list) {
 	return list->rls_addr;
 }
-const LinphoneAddress *_linphone_friend_list_get_rls_address(const LinphoneFriendList *list) {
+LinphoneAddress *_linphone_friend_list_get_rls_address(const LinphoneFriendList *list) {
 	if (list->rls_addr) return list->rls_addr;
 	else if (list->lc) {
 		const char *rls_uri = linphone_config_get_string(list->lc->config, "sip", "rls_uri", NULL);
@@ -1203,8 +1203,7 @@ static void linphone_friend_list_close_subscriptions(LinphoneFriendList *list) {
 	bctbx_list_for_each(list->friends, (void (*)(void *))linphone_friend_close_subscriptions);
 }
 
-static void _linphone_friend_list_send_list_subscription_with_body(LinphoneFriendList *list,
-                                                                   const LinphoneAddress *address) {
+static void _linphone_friend_list_send_list_subscription_with_body(LinphoneFriendList *list, LinphoneAddress *address) {
 	char *xml_content = create_resource_list_xml(list);
 	if (!xml_content) return;
 
@@ -1253,7 +1252,7 @@ static void _linphone_friend_list_send_list_subscription_with_body(LinphoneFrien
 }
 
 static void _linphone_friend_list_send_list_subscription_without_body(LinphoneFriendList *list,
-                                                                      const LinphoneAddress *address) {
+                                                                      LinphoneAddress *address) {
 	bctbx_list_t *elem = NULL;
 	int expires = linphone_config_get_int(list->lc->config, "sip", "rls_presence_expires", 3600);
 	list->expected_notification_version = 0;
@@ -1280,7 +1279,7 @@ static void _linphone_friend_list_send_list_subscription_without_body(LinphoneFr
 }
 
 static void linphone_friend_list_send_list_subscription(LinphoneFriendList *list) {
-	const LinphoneAddress *address = _linphone_friend_list_get_rls_address(list);
+	LinphoneAddress *address = _linphone_friend_list_get_rls_address(list);
 	if (!address) {
 		ms_warning("Friend list's [%p] has no RLS address, can't send subscription", list);
 		return;
@@ -1297,7 +1296,7 @@ static void linphone_friend_list_send_list_subscription(LinphoneFriendList *list
 
 void linphone_friend_list_update_subscriptions(LinphoneFriendList *list) {
 	LinphoneProxyConfig *cfg = NULL;
-	const LinphoneAddress *address = _linphone_friend_list_get_rls_address(list);
+	LinphoneAddress *address = _linphone_friend_list_get_rls_address(list);
 	bool_t only_when_registered = FALSE;
 	bool_t should_send_list_subscribe = FALSE;
 
diff --git a/coreapi/linphoneconference.c b/coreapi/linphoneconference.c
index 05f2bc1894bc4b75d3dce5a5dffc70ab09d3e877..394968a83ebc97ca5767d91e9b54d1d1d0b9742b 100644
--- a/coreapi/linphoneconference.c
+++ b/coreapi/linphoneconference.c
@@ -80,8 +80,8 @@ char *linphone_conference_state_to_string(LinphoneConferenceState state) {
 
 LinphoneConference *linphone_local_conference_new(LinphoneCore *core, LinphoneAddress *addr) {
 	return (new LinphonePrivate::MediaConference::LocalConference(
-	            L_GET_CPP_PTR_FROM_C_OBJECT(core), LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)),
-	            nullptr, ConferenceParams::create(core)))
+	            L_GET_CPP_PTR_FROM_C_OBJECT(core), LinphonePrivate::Address::toCpp(addr)->getSharedFromThis(), nullptr,
+	            ConferenceParams::create(core)))
 	    ->toC();
 }
 
@@ -89,16 +89,16 @@ LinphoneConference *linphone_local_conference_new_with_params(LinphoneCore *core
                                                               LinphoneAddress *addr,
                                                               const LinphoneConferenceParams *params) {
 	return (new LinphonePrivate::MediaConference::LocalConference(
-	            L_GET_CPP_PTR_FROM_C_OBJECT(core), LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)),
-	            nullptr, ConferenceParams::toCpp(const_cast<LinphoneConferenceParams *>(params))->getSharedFromThis()))
+	            L_GET_CPP_PTR_FROM_C_OBJECT(core), LinphonePrivate::Address::toCpp(addr)->getSharedFromThis(), nullptr,
+	            ConferenceParams::toCpp(const_cast<LinphoneConferenceParams *>(params))->getSharedFromThis()))
 	    ->toC();
 }
 
 LinphoneConference *linphone_remote_conference_new(LinphoneCore *core, LinphoneAddress *addr) {
 	return (new LinphonePrivate::MediaConference::RemoteConference(
-	            L_GET_CPP_PTR_FROM_C_OBJECT(core), LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)),
-	            ConferenceId(IdentityAddress(), LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))),
-	            nullptr, ConferenceParams::create(core)))
+	            L_GET_CPP_PTR_FROM_C_OBJECT(core), LinphonePrivate::Address::toCpp(addr)->getSharedFromThis(),
+	            ConferenceId(nullptr, LinphonePrivate::Address::toCpp(addr)->getSharedFromThis()), nullptr,
+	            ConferenceParams::create(core)))
 	    ->toC();
 }
 
@@ -108,9 +108,9 @@ LinphoneConference *linphone_remote_conference_new_with_params(LinphoneCore *cor
                                                                const LinphoneConferenceParams *params) {
 	LinphonePrivate::MediaConference::RemoteConference *conference =
 	    new LinphonePrivate::MediaConference::RemoteConference(
-	        L_GET_CPP_PTR_FROM_C_OBJECT(core), LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(focus)),
-	        ConferenceId(IdentityAddress(), LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))),
-	        nullptr, ConferenceParams::toCpp(const_cast<LinphoneConferenceParams *>(params))->getSharedFromThis());
+	        L_GET_CPP_PTR_FROM_C_OBJECT(core), LinphonePrivate::Address::toCpp(focus)->getSharedFromThis(),
+	        ConferenceId(nullptr, LinphonePrivate::Address::toCpp(addr)->getSharedFromThis()), nullptr,
+	        ConferenceParams::toCpp(const_cast<LinphoneConferenceParams *>(params))->getSharedFromThis());
 
 	return conference->toC();
 }
@@ -139,11 +139,16 @@ LinphoneStatus linphone_conference_add_participant(LinphoneConference *conferenc
 }
 
 LinphoneStatus linphone_conference_add_participant_2(LinphoneConference *conference, const LinphoneAddress *uri) {
-	return MediaConference::Conference::toCpp(conference)->addParticipant(*L_GET_CPP_PTR_FROM_C_OBJECT(uri)) ? 0 : -1;
+	return MediaConference::Conference::toCpp(conference)
+	               ->addParticipant(
+	                   LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(uri))->getSharedFromThis())
+	           ? 0
+	           : -1;
 }
 
 LinphoneStatus linphone_conference_remove_participant(LinphoneConference *conference, const LinphoneAddress *uri) {
-	LinphoneParticipant *participant = linphone_conference_find_participant(conference, uri);
+	LinphoneParticipant *participant =
+	    linphone_conference_find_participant(conference, const_cast<LinphoneAddress *>(uri));
 	return linphone_conference_remove_participant_2(conference, participant);
 }
 
@@ -159,7 +164,8 @@ LinphoneStatus linphone_conference_remove_participant_3(LinphoneConference *conf
 
 LinphoneParticipant *linphone_conference_find_participant(LinphoneConference *conference, const LinphoneAddress *uri) {
 	shared_ptr<LinphonePrivate::Participant> p =
-	    MediaConference::Conference::toCpp(conference)->findParticipant(*L_GET_CPP_PTR_FROM_C_OBJECT(uri));
+	    MediaConference::Conference::toCpp(conference)
+	        ->findParticipant(LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(uri))->getSharedFromThis());
 	if (p) {
 		return p->toC();
 	}
@@ -184,7 +190,8 @@ int linphone_conference_leave(LinphoneConference *conference) {
 }
 
 bool_t linphone_conference_is_me(const LinphoneConference *conference, const LinphoneAddress *uri) {
-	return MediaConference::Conference::toCpp(conference)->isMe(*L_GET_CPP_PTR_FROM_C_OBJECT(uri));
+	return MediaConference::Conference::toCpp(conference)
+	    ->isMe(LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(uri))->getSharedFromThis());
 }
 
 bool_t linphone_conference_is_in(const LinphoneConference *conference) {
@@ -319,24 +326,21 @@ LinphoneStatus linphone_conference_invite_participants(LinphoneConference *confe
                                                        const bctbx_list_t *addresses,
                                                        const LinphoneCallParams *params) {
 	return MediaConference::Conference::toCpp(conference)
-	    ->inviteAddresses(toStd<const LinphoneAddress *>(addresses), params);
+	    ->inviteAddresses(
+	        LinphonePrivate::Utils::bctbxListToCppSharedPtrList<LinphoneAddress, LinphonePrivate::Address>(addresses),
+	        params);
 }
 
 LinphoneStatus linphone_conference_add_participants(LinphoneConference *conference, const bctbx_list_t *calls) {
-	list<shared_ptr<LinphonePrivate::Call>> callList =
-	    L_GET_CPP_LIST_FROM_C_LIST_2(calls, LinphoneCall *, shared_ptr<LinphonePrivate::Call>, [](LinphoneCall *call) {
-		    return LinphonePrivate::Call::toCpp(call)->getSharedFromThis();
-	    });
-	return MediaConference::Conference::toCpp(conference)->addParticipants(callList);
+	return MediaConference::Conference::toCpp(conference)
+	    ->addParticipants(
+	        LinphonePrivate::Utils::bctbxListToCppSharedPtrList<LinphoneCall, LinphonePrivate::Call>(calls));
 }
 
 LinphoneStatus linphone_conference_add_participants_2(LinphoneConference *conference, const bctbx_list_t *addresses) {
-	list<LinphonePrivate::IdentityAddress> addressList = L_GET_CPP_LIST_FROM_C_LIST_2(
-	    addresses, LinphoneAddress *, LinphonePrivate::IdentityAddress, [](LinphoneAddress *address) {
-		    return address ? LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(address))
-		                   : LinphonePrivate::IdentityAddress();
-	    });
-	return MediaConference::Conference::toCpp(conference)->addParticipants(addressList);
+	return MediaConference::Conference::toCpp(conference)
+	    ->addParticipants(
+	        LinphonePrivate::Utils::bctbxListToCppSharedPtrList<LinphoneAddress, LinphonePrivate::Address>(addresses));
 }
 
 LinphoneParticipant *linphone_conference_get_me(const LinphoneConference *conference) {
@@ -469,14 +473,14 @@ bool_t linphone_conference_params_chat_enabled(const LinphoneConferenceParams *p
 }
 
 LinphoneProxyConfig *linphone_conference_params_get_proxy_cfg(const LinphoneConferenceParams *params) {
-	auto account = ConferenceParams::toCpp(params)->getAccount();
+	auto account = ConferenceParams::toCpp(params)->getAccount()->toC();
 	return linphone_core_lookup_proxy_by_identity(
 	    linphone_account_get_core(account),
 	    linphone_account_params_get_identity_address(linphone_account_get_params(account)));
 }
 
 LinphoneAccount *linphone_conference_params_get_account(const LinphoneConferenceParams *params) {
-	return ConferenceParams::toCpp(params)->getAccount();
+	return ConferenceParams::toCpp(params)->getAccount()->toC();
 }
 
 void linphone_conference_params_set_local_participant_enabled(LinphoneConferenceParams *params, bool_t enable) {
@@ -554,16 +558,14 @@ time_t linphone_conference_params_get_end_time(const LinphoneConferenceParams *p
 
 void linphone_conference_params_set_conference_factory_address(LinphoneConferenceParams *params,
                                                                const LinphoneAddress *address) {
-	ConferenceParams::toCpp(params)->setConferenceFactoryAddress(address ? *L_GET_CPP_PTR_FROM_C_OBJECT(address)
-	                                                                     : Address());
+	ConferenceParams::toCpp(params)->setConferenceFactoryAddress(
+	    address ? Address::toCpp(const_cast<LinphoneAddress *>(address))->getSharedFromThis() : nullptr);
 }
 
 const LinphoneAddress *
 linphone_conference_params_get_conference_factory_address(const LinphoneConferenceParams *params) {
 	auto &conferenceAddress = ConferenceParams::toCpp(params)->getConferenceFactoryAddress();
-	if (conferenceAddress.isValid() &&
-	    conferenceAddress != Address()) // isValid() is not enough and empty address should return NULL.
-		return L_GET_C_BACK_PTR(&conferenceAddress);
+	if (conferenceAddress) return conferenceAddress->toC();
 	else return NULL;
 }
 
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index dbf3bac0a4c3e4bcd3ea56341c1a928c178abf39..24de0889221e509d9ff4453f4401ecfbd1df5ff7 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -2726,9 +2726,10 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc,
 		bctbx_free(resourceAddrStr);
 
 		const LinphoneAddress *from = linphone_event_get_from(lev);
-		LinphonePrivate::ConferenceId conferenceId =
-		    LinphonePrivate::ConferenceId(ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)),
-		                                  ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(from)));
+		const auto fromAddr = LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(from))->getSharedFromThis();
+		const auto resourceAddr =
+		    LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(resource))->getSharedFromThis();
+		LinphonePrivate::ConferenceId conferenceId = LinphonePrivate::ConferenceId(resourceAddr, fromAddr);
 		shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(conferenceId);
 		shared_ptr<MediaConference::Conference> audioVideoConference =
 		    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(conferenceId);
@@ -2776,11 +2777,9 @@ _linphone_core_conference_subscribe_received(LinphoneCore *lc, LinphoneEvent *le
 	}
 
 	const LinphoneAddress *resource = linphone_event_get_resource(lev);
-	char *resourceAddressStr = linphone_address_as_string(resource);
-	const ConferenceAddress conferenceAddress = ConferenceAddress(resourceAddressStr);
-	bctbx_free(resourceAddressStr);
-	LinphonePrivate::ConferenceId conferenceId =
-	    LinphonePrivate::ConferenceId(ConferenceAddress(conferenceAddress), ConferenceAddress(conferenceAddress));
+	const std::shared_ptr<Address> conferenceAddress =
+	    Address::toCpp(const_cast<LinphoneAddress *>(resource))->getSharedFromThis();
+	LinphonePrivate::ConferenceId conferenceId = LinphonePrivate::ConferenceId(conferenceAddress, conferenceAddress);
 	shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(conferenceId);
 	shared_ptr<MediaConference::Conference> audioVideoConference =
 	    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(conferenceId);
@@ -2824,12 +2823,9 @@ static void _linphone_core_conference_subscription_state_changed(LinphoneCore *l
 		}
 	} else {
 		/* This has to be done only when running as server */
-		const LinphoneAddress *resource = evSub->getResource();
-		char *resourceAddressStr = linphone_address_as_string(resource);
-		const ConferenceAddress conferenceAddress = ConferenceAddress(resourceAddressStr);
-		bctbx_free(resourceAddressStr);
+		const auto &conferenceAddress = evSub->getResource();
 		LinphonePrivate::ConferenceId conferenceId =
-		    LinphonePrivate::ConferenceId(ConferenceAddress(conferenceAddress), ConferenceAddress(conferenceAddress));
+		    LinphonePrivate::ConferenceId(conferenceAddress, conferenceAddress);
 		shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(conferenceId);
 		shared_ptr<MediaConference::Conference> audioVideoConference =
 		    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(conferenceId);
@@ -4516,8 +4512,10 @@ static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const Lin
 		}
 		proxy_routes_iterator = bctbx_list_next(proxy_routes_iterator);
 	}
+	bctbx_list_free_with_data((bctbx_list_t *)proxy_routes, (bctbx_list_free_func)bctbx_free);
 	if (srv_route) {
-		ret = bctbx_list_append(ret, sal_address_clone(L_GET_CPP_PTR_FROM_C_OBJECT(srv_route)->getInternalAddress()));
+		const auto srv_route_addr = LinphonePrivate::Address::toCpp(srv_route)->getSharedFromThis();
+		ret = bctbx_list_append(ret, sal_address_clone(srv_route_addr->getImpl()));
 	}
 	if (ret == NULL) {
 		/*if the proxy address matches the domain part of the destination, then use the same transport
@@ -4534,10 +4532,8 @@ static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const Lin
 
 static bctbx_list_t *make_routes_for_account(LinphoneAccount *account, const LinphoneAddress *dest) {
 	bctbx_list_t *ret = NULL;
-	const bctbx_list_t *account_routes =
-	    linphone_account_params_get_routes_addresses(linphone_account_get_params(account));
+	bctbx_list_t *account_routes = linphone_account_params_get_routes_addresses(linphone_account_get_params(account));
 	bctbx_list_t *account_routes_iterator = (bctbx_list_t *)account_routes;
-	const LinphoneAddress *srv_route = Account::toCpp(account)->getServiceRouteAddress();
 	while (account_routes_iterator) {
 		LinphoneAddress *local_route = (LinphoneAddress *)bctbx_list_get_data(account_routes_iterator);
 		if (local_route) {
@@ -4547,8 +4543,10 @@ static bctbx_list_t *make_routes_for_account(LinphoneAccount *account, const Lin
 		}
 		account_routes_iterator = bctbx_list_next(account_routes_iterator);
 	}
+	bctbx_list_free(account_routes);
+	const auto srv_route = Account::toCpp(account)->getServiceRouteAddress();
 	if (srv_route) {
-		ret = bctbx_list_append(ret, sal_address_clone(L_GET_CPP_PTR_FROM_C_OBJECT(srv_route)->getInternalAddress()));
+		ret = bctbx_list_append(ret, sal_address_clone(srv_route->getImpl()));
 	}
 	if (ret == NULL && linphone_account_params_get_server_addr(linphone_account_get_params(account))) {
 		/*if the account identity address matches the domain part of the destination, then use the same transport
@@ -4823,7 +4821,7 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc,
 		linphone_transfer_routes_to_op(routes, op);
 	}
 
-	op->setToAddress(L_GET_CPP_PTR_FROM_C_OBJECT(dest)->getInternalAddress());
+	op->setToAddress(Address::toCpp(dest)->getImpl());
 	op->setFrom(identity);
 	op->setSentCustomHeaders(headers);
 	op->setRealm(L_C_TO_STRING(linphone_proxy_config_get_realm(proxy)));
@@ -4831,7 +4829,10 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc,
 	if (with_contact && proxy && Account::toCpp(proxy->account)->getOp()) {
 		const LinphoneAddress *contact = linphone_proxy_config_get_contact(proxy);
 		SalAddress *salAddress = nullptr;
-		if (contact) salAddress = sal_address_clone(L_GET_CPP_PTR_FROM_C_OBJECT(contact)->getInternalAddress());
+		if (contact) {
+			const auto contact_addr = LinphonePrivate::Address::toCpp(contact)->getSharedFromThis();
+			salAddress = sal_address_clone(contact_addr->getImpl());
+		}
 		op->setContactAddress(salAddress);
 		if (salAddress) sal_address_unref(salAddress);
 	}
@@ -4860,7 +4861,7 @@ void linphone_configure_op_with_account(LinphoneCore *lc,
 		linphone_transfer_routes_to_op(routes, op);
 	}
 
-	op->setToAddress(L_GET_CPP_PTR_FROM_C_OBJECT(dest)->getInternalAddress());
+	op->setToAddress(LinphonePrivate::Address::toCpp(dest)->getImpl());
 	op->setFrom(identity);
 	op->setSentCustomHeaders(headers);
 	op->setRealm(
@@ -4869,7 +4870,10 @@ void linphone_configure_op_with_account(LinphoneCore *lc,
 	if (with_contact && account && Account::toCpp(account)->getOp()) {
 		const LinphoneAddress *contact = linphone_account_get_contact_address(account);
 		SalAddress *salAddress = nullptr;
-		if (contact) salAddress = sal_address_clone(L_GET_CPP_PTR_FROM_C_OBJECT(contact)->getInternalAddress());
+		if (contact) {
+			const auto contact_addr = LinphonePrivate::Address::toCpp(contact)->getSharedFromThis();
+			salAddress = sal_address_clone(contact_addr->getImpl());
+		}
 		op->setContactAddress(salAddress);
 		if (salAddress) sal_address_unref(salAddress);
 	}
@@ -5196,8 +5200,8 @@ LinphoneCall *linphone_core_find_call_from_uri(const LinphoneCore *lc, const cha
 }
 
 LinphoneCall *linphone_core_get_call_by_remote_address2(const LinphoneCore *lc, const LinphoneAddress *raddr) {
-	shared_ptr<LinphonePrivate::Call> call =
-	    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getCallByRemoteAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(raddr));
+	const auto remote_addr = LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(raddr))->getSharedFromThis();
+	shared_ptr<LinphonePrivate::Call> call = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getCallByRemoteAddress(remote_addr);
 	return call ? call->toC() : NULL;
 }
 
@@ -7162,7 +7166,6 @@ MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc) {
 
 void net_config_uninit(LinphoneCore *lc) {
 	net_config_t *config = &lc->net_conf;
-
 	if (config->nat_address != NULL) {
 		linphone_config_set_string(lc->config, "net", "nat_address", config->nat_address);
 		ms_free(lc->net_conf.nat_address);
@@ -9127,15 +9130,15 @@ LinphoneConference *linphone_core_create_conference_with_params(LinphoneCore *lc
 			identity = linphone_address_new(linphone_core_get_identity(
 			    lc)); // backward compatibility : use default identity even if set in conference parameters
 		} else {
-			const LinphonePrivate::IdentityAddress &identity_address =
+			const std::shared_ptr<LinphonePrivate::Address> &identity_address =
 			    LinphonePrivate::ConferenceParams::toCpp(params)->getMe();
-			if (identity_address.isValid()) {
+			if (identity_address && identity_address->isValid()) {
 				lInfo() << "Creating remote conference with identity from conference params : " << identity_address;
-				identity = linphone_address_clone(L_GET_C_BACK_PTR(&identity_address.asAddress()));
+				identity = linphone_address_clone(identity_address->toC());
 			} else {
 				identity = linphone_address_new(linphone_core_get_identity(lc));
 				lInfo() << "Creating remote conference with identity from default account "
-				        << L_GET_CPP_PTR_FROM_C_OBJECT(identity)->asString();
+				        << LinphonePrivate::Address::toCpp(identity)->toString();
 			}
 		}
 
@@ -9210,18 +9213,17 @@ LinphoneConference *linphone_core_search_conference(const LinphoneCore *lc,
                                                     const bctbx_list_t *participants) {
 	shared_ptr<LinphonePrivate::ConferenceParams> conferenceParams =
 	    params ? LinphonePrivate::ConferenceParams::toCpp(params)->clone()->toSharedPtr() : nullptr;
-	list<LinphonePrivate::IdentityAddress> participantsList;
+	list<std::shared_ptr<LinphonePrivate::Address>> participantsList;
 	if (participants) {
-		participantsList = L_GET_CPP_LIST_FROM_C_LIST_2(
-		    participants, LinphoneAddress *, LinphonePrivate::IdentityAddress,
-		    [](LinphoneAddress *addr) { return LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)); });
+		participantsList =
+		    LinphonePrivate::Utils::bctbxListToCppSharedPtrList<LinphoneAddress, LinphonePrivate::Address>(
+		        participants);
 	}
-	LinphonePrivate::ConferenceAddress identityAddress =
-	    localAddr ? LinphonePrivate::ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr))
+	shared_ptr<const LinphonePrivate::Address> identityAddress =
+	    localAddr ? LinphonePrivate::Address::toCpp(localAddr)->getSharedFromThis()
 	              : L_GET_PRIVATE_FROM_C_OBJECT(lc)->getDefaultLocalAddress(nullptr, false);
-	LinphonePrivate::ConferenceAddress remoteAddress =
-	    remoteAddr ? LinphonePrivate::ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(remoteAddr))
-	               : LinphonePrivate::ConferenceAddress();
+	shared_ptr<const LinphonePrivate::Address> remoteAddress =
+	    remoteAddr ? LinphonePrivate::Address::toCpp(remoteAddr)->getSharedFromThis() : nullptr;
 	shared_ptr<LinphonePrivate::MediaConference::Conference> conf =
 	    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->searchAudioVideoConference(conferenceParams, identityAddress, remoteAddress,
 	                                                                participantsList);
@@ -9233,9 +9235,10 @@ LinphoneConference *linphone_core_search_conference(const LinphoneCore *lc,
 }
 
 LinphoneConference *linphone_core_search_conference_2(const LinphoneCore *lc, const LinphoneAddress *conferenceAddr) {
-	LinphonePrivate::ConferenceAddress conferenceAddress =
-	    conferenceAddr ? LinphonePrivate::ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(conferenceAddr))
-	                   : LinphonePrivate::ConferenceAddress();
+	const auto conferenceAddress =
+	    conferenceAddr
+	        ? LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(conferenceAddr))->getSharedFromThis()
+	        : nullptr;
 	shared_ptr<LinphonePrivate::MediaConference::Conference> conf =
 	    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->searchAudioVideoConference(conferenceAddress);
 	LinphoneConference *c_conference = NULL;
@@ -9266,8 +9269,7 @@ LinphoneStatus linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *c
 		LinphoneConferenceParams *params = linphone_conference_params_new(lc);
 		if (call) {
 			const LinphoneCallParams *remote_call_params = linphone_call_get_remote_params(call);
-			LinphoneProxyConfig *proxy_cfg = linphone_call_get_dest_proxy(call);
-			auto account = linphone_core_lookup_account_by_identity(lc, linphone_proxy_config_get_contact(proxy_cfg));
+			auto account = Call::toCpp(call)->getDestAccount();
 			LinphonePrivate::ConferenceParams::toCpp(params)->setAccount(account);
 			if (remote_call_params) {
 				linphone_conference_params_set_audio_enabled(params,
@@ -9483,8 +9485,8 @@ int linphone_core_get_unread_chat_message_count(const LinphoneCore *lc) {
 }
 
 int linphone_core_get_unread_chat_message_count_from_local(const LinphoneCore *lc, const LinphoneAddress *address) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getUnreadChatMessageCount(
-	    LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(address)));
+	const auto addr = LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(address))->getSharedFromThis();
+	return L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getUnreadChatMessageCount(addr);
 }
 
 int linphone_core_get_unread_chat_message_count_from_active_locals(const LinphoneCore *lc) {
@@ -9517,7 +9519,8 @@ const char *linphone_core_get_srtp_crypto_suites(LinphoneCore *core) {
 LinphoneConferenceInfo *linphone_core_find_conference_information_from_uri(LinphoneCore *core, LinphoneAddress *uri) {
 #ifdef HAVE_DB_STORAGE
 	auto &mainDb = L_GET_PRIVATE_FROM_C_OBJECT(core)->mainDb;
-	auto confInfo = mainDb->getConferenceInfoFromURI(ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(uri)));
+	const auto uri_addr = LinphonePrivate::Address::toCpp(uri)->getSharedFromThis();
+	auto confInfo = mainDb->getConferenceInfoFromURI(uri_addr);
 
 	if (confInfo != nullptr) {
 		// Clone the conference information so that the application can freely change it without modifying the
diff --git a/coreapi/private.h b/coreapi/private.h
index cc3c17ed13f7ae3610424e727e3f903dea86ae7b..1ffa75c53f8a695ce29e801e5e0dd6a76d87a816 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -59,7 +59,6 @@
 
 #include "linphone/conference.h"
 
-#include "address/address.h"
 #include "c-wrapper/internal/c-sal.h"
 #include "sal/call-op.h"
 #include "sal/event-op.h"
diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h
index 357875b5950942144d3fe427c815378a787756ab..31bf7e836b99a3f85fcd7fa4e291a032fd856935 100644
--- a/coreapi/private_functions.h
+++ b/coreapi/private_functions.h
@@ -81,7 +81,7 @@ LinphonePlayer *linphone_call_build_player(LinphoneCall *call);
 LinphonePrivate::SalCallOp *linphone_call_get_op(const LinphoneCall *call);
 
 // FIXME: Remove this declaration, use LINPHONE_PUBLIC as ugly workaround, already defined in tester_utils.h
-LINPHONE_PUBLIC LinphoneProxyConfig *linphone_call_get_dest_proxy(const LinphoneCall *call);
+LINPHONE_PUBLIC LinphoneAccount *linphone_call_get_dest_account(const LinphoneCall *call);
 
 LINPHONE_PUBLIC MediaStream *linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type);
 LINPHONE_PUBLIC VideoStream *linphone_core_get_preview_stream(LinphoneCore *call);
@@ -220,7 +220,7 @@ void linphone_friend_list_invalidate_friends_maps(LinphoneFriendList *list);
 void linphone_core_clear_bodyless_friend_lists(LinphoneCore *lc);
 void _linphone_friend_list_release(LinphoneFriendList *list);
 /*get rls either from list or core if any*/
-const LinphoneAddress *_linphone_friend_list_get_rls_address(const LinphoneFriendList *list);
+LinphoneAddress *_linphone_friend_list_get_rls_address(const LinphoneFriendList *list);
 
 LINPHONE_PUBLIC void linphone_friend_invalidate_subscription(LinphoneFriend *lf);
 void linphone_friend_close_subscriptions(LinphoneFriend *lf);
@@ -437,7 +437,7 @@ void _linphone_participant_device_notify_stream_capability_changed(LinphoneParti
 void linphone_conference_scheduler_notify_state_changed(LinphoneConferenceScheduler *conference_scheduler,
                                                         LinphoneConferenceSchedulerState state);
 void linphone_conference_scheduler_notify_invitations_sent(LinphoneConferenceScheduler *conference_scheduler,
-                                                           bctbx_list_t *failed_invites);
+                                                           const bctbx_list_t *failed_invites);
 
 LINPHONE_PUBLIC void linphone_participant_device_set_state(LinphoneParticipantDevice *participant_device,
                                                            LinphoneParticipantDeviceState state);
@@ -648,7 +648,7 @@ LINPHONE_PUBLIC LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc,
                                                           LinphoneSubscriptionDir dir,
                                                           const char *name);
 LinphoneEvent *_linphone_core_create_publish(
-    LinphoneCore *lc, LinphoneAccount *account, const LinphoneAddress *resource, const char *event, int expires);
+    LinphoneCore *lc, LinphoneAccount *account, LinphoneAddress *resource, const char *event, int expires);
 void linphone_event_unpublish(LinphoneEvent *lev);
 void linphone_event_set_current_callbacks(LinphoneEvent *ev, LinphoneEventCbs *cbs);
 void linphone_event_set_manual_refresher_mode(LinphoneEvent *lev, bool_t manual);
@@ -981,6 +981,7 @@ typedef struct _SrtpInfo SrtpInfo;
  * @return The srtp info
  */
 LINPHONE_PUBLIC const SrtpInfo *linphone_call_stats_get_srtp_info(const LinphoneCallStats *stats, bool_t is_inner);
+
 /**
  * Create a new #LinphoneNatPolicy by reading the config of a #LinphoneCore according to the passed ref.
  * @param core #LinphoneCore object @notnil
diff --git a/coreapi/proxy.c b/coreapi/proxy.c
index be508b46b85e877d2fe91b36a5174cc56569961e..9a85cad1f4c9ed163b8e761e61806add25c58c1f 100644
--- a/coreapi/proxy.c
+++ b/coreapi/proxy.c
@@ -62,7 +62,11 @@ using namespace LinphonePrivate;
 
 LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_address_equal(const LinphoneAddress *a,
                                                                                const LinphoneAddress *b) {
-	return (LinphoneProxyConfigAddressComparisonResult)Account::compareLinphoneAddresses(a, b);
+	std::shared_ptr<Address> aAddr =
+	    a ? Address::toCpp(const_cast<LinphoneAddress *>(a))->getSharedFromThis() : nullptr;
+	std::shared_ptr<Address> bAddr =
+	    b ? Address::toCpp(const_cast<LinphoneAddress *>(b))->getSharedFromThis() : nullptr;
+	return (LinphoneProxyConfigAddressComparisonResult)Account::compareLinphoneAddresses(aAddr, bAddr);
 }
 
 LinphoneProxyConfigAddressComparisonResult
@@ -136,7 +140,7 @@ LinphoneStatus linphone_proxy_config_set_server_addr(LinphoneProxyConfig *cfg, c
 	return linphone_account_params_set_server_addr(cfg->edit, server_addr);
 }
 
-LinphoneStatus linphone_proxy_config_set_identity_address(LinphoneProxyConfig *cfg, const LinphoneAddress *addr) {
+LinphoneStatus linphone_proxy_config_set_identity_address(LinphoneProxyConfig *cfg, LinphoneAddress *addr) {
 	if (!cfg->edit) {
 		linphone_proxy_config_edit(cfg);
 	}
@@ -543,7 +547,7 @@ const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg) {
 
 const bctbx_list_t *linphone_proxy_config_get_routes(const LinphoneProxyConfig *cfg) {
 	const LinphoneAccountParams *params = cfg->edit ? cfg->edit : linphone_account_get_params(cfg->account);
-	return AccountParams::toCpp(params)->getRoutesString();
+	return L_GET_C_LIST_FROM_CPP_LIST(AccountParams::toCpp(params)->getRoutesString());
 }
 
 const LinphoneAddress *linphone_proxy_config_get_identity_address(const LinphoneProxyConfig *cfg) {
@@ -959,6 +963,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc
 
 	LinphoneProxyConfig *cfg = belle_sip_object_new(LinphoneProxyConfig);
 	cfg->account = linphone_account_new_with_config(lc, params, cfg);
+
 	linphone_account_params_unref(params);
 	cfg->edit = NULL;
 
@@ -1010,7 +1015,8 @@ const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProx
 }
 
 const LinphoneAddress *linphone_proxy_config_get_service_route(const LinphoneProxyConfig *cfg) {
-	return Account::toCpp(cfg->account)->getServiceRouteAddress();
+	const auto route = Account::toCpp(cfg->account)->getServiceRouteAddress();
+	return route ? route->toC() : nullptr;
 }
 
 const char *linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg) {
@@ -1093,7 +1099,7 @@ LinphoneAddress *linphone_proxy_config_get_transport_contact(LinphoneProxyConfig
 }
 
 const LinphoneAddress *_linphone_proxy_config_get_contact_without_params(const LinphoneProxyConfig *cfg) {
-	return Account::toCpp(cfg->account)->getContactAddressWithoutParams();
+	return Account::toCpp(cfg->account)->getContactAddressWithoutParams()->toC();
 }
 
 const struct _LinphoneAuthInfo *linphone_proxy_config_find_auth_info(const LinphoneProxyConfig *cfg) {
diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c
index 4f0e73db8a48a600f85ad1b907c7299d5e7d9887..c22eafa85e2e3bce5cc9dc0cc747bfc714b6e874 100644
--- a/coreapi/quality_reporting.c
+++ b/coreapi/quality_reporting.c
@@ -175,8 +175,10 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t *rm) {
 }
 
 static bool_t quality_reporting_enabled(const LinphoneCall *call) {
-	return (Call::toCpp(call)->getDestProxy() &&
-	        linphone_proxy_config_quality_reporting_enabled(Call::toCpp(call)->getDestProxy()));
+	const auto &account = Call::toCpp(call)->getDestAccount();
+	if (!account) return false;
+	const auto &accountParams = account->getAccountParams();
+	return (accountParams) ? accountParams->getQualityReportingEnabled() : false;
 }
 
 static bool_t media_report_enabled(LinphoneCall *call, int stats_type) {
@@ -315,6 +317,8 @@ static int send_report(LinphoneCall *call, reporting_session_report_t *report, c
 	const char *collector_uri;
 	char *collector_uri_allocated = NULL;
 	const SalAddress *salAddress;
+	const LinphoneAccount *dest_account = NULL;
+	const LinphoneAccountParams *dest_account_params = NULL;
 
 	/*if we are on a low bandwidth network, do not send reports to not overload it*/
 	if (linphone_call_params_low_bandwidth_enabled(linphone_call_get_current_params(call))) {
@@ -397,10 +401,12 @@ static int send_report(LinphoneCall *call, reporting_session_report_t *report, c
 		Call::toCpp(call)->getLog()->getQualityReporting()->on_report_sent(call, type, content);
 	}
 
-	collector_uri = linphone_proxy_config_get_quality_reporting_collector(linphone_call_get_dest_proxy(call));
+	dest_account = linphone_call_get_dest_account(call);
+	dest_account_params = linphone_account_get_params(dest_account);
+	collector_uri = linphone_account_params_get_quality_reporting_collector(dest_account_params);
 	if (!collector_uri) {
 		collector_uri = collector_uri_allocated =
-		    ms_strdup_printf("sip:%s", linphone_proxy_config_get_domain(linphone_call_get_dest_proxy(call)));
+		    ms_strdup_printf("sip:%s", linphone_account_params_get_domain(dest_account_params));
 	}
 	request_uri = linphone_address_new(collector_uri);
 	lev = linphone_core_create_one_shot_publish(linphone_call_get_core(call), request_uri, "vq-rtcpxr");
@@ -408,7 +414,7 @@ static int send_report(LinphoneCall *call, reporting_session_report_t *report, c
 	 * (port, transport, maddr), then it is sent directly.
 	 * Otherwise it is routed as any LinphoneEvent publish, following proxy config policy.
 	 **/
-	salAddress = L_GET_CPP_PTR_FROM_C_OBJECT(request_uri)->getInternalAddress();
+	salAddress = LinphonePrivate::Address::toCpp(request_uri)->getImpl();
 	if (sal_address_has_uri_param(salAddress, "transport") || sal_address_has_uri_param(salAddress, "maddr") ||
 	    linphone_address_get_port(request_uri) != 0) {
 		ms_message("Publishing report with custom route %s", collector_uri);
@@ -567,13 +573,15 @@ void linphone_reporting_update_media_info(LinphoneCall *call, int stats_type) {
 	             ms_strdup_printf("%s-%s-%s", dialogId.c_str(), "remote",
 	                              report->remote_metrics.user_agent ? report->remote_metrics.user_agent : ""));
 
+	char *from = ms_strdup(L_STRING_TO_C(log->getFromAddress()->toString()));
+	char *to = ms_strdup(L_STRING_TO_C(log->getToAddress()->toString()));
 	if (Call::toCpp(call)->getDirection() == LinphoneCallIncoming) {
-		STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(log->getFromAddress()));
-		STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(log->getToAddress()));
+		STR_REASSIGN(report->info.remote_addr.id, from);
+		STR_REASSIGN(report->info.local_addr.id, to);
 		STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_addr.id));
 	} else {
-		STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(log->getToAddress()));
-		STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(log->getFromAddress()));
+		STR_REASSIGN(report->info.remote_addr.id, to);
+		STR_REASSIGN(report->info.local_addr.id, from);
 		STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_addr.id));
 	}
 
@@ -658,7 +666,9 @@ void linphone_reporting_on_rtcp_update(LinphoneCall *call, SalStreamType stats_t
 
 	if (!media_report_enabled(call, stats_type)) return;
 
-	report_interval = linphone_proxy_config_get_quality_reporting_interval(Call::toCpp(call)->getDestProxy());
+	const auto &account = Call::toCpp(call)->getDestAccount();
+	const auto &accountParams = account ? account->getAccountParams() : nullptr;
+	report_interval = (accountParams) ? accountParams->getQualityReportingInterval() : -1;
 
 	if (_linphone_call_stats_get_updated(stats) == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) {
 		metrics = &report->remote_metrics;
diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h
index f6913a3cc02dac7e96fa2fd96f3bad4bff20c22b..a014d8a2c5c12faac0bc2c332f8246a5f8195481 100644
--- a/coreapi/tester_utils.h
+++ b/coreapi/tester_utils.h
@@ -139,7 +139,7 @@ linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddr
 LINPHONE_PUBLIC MediaStream *linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type);
 LINPHONE_PUBLIC VideoStream *linphone_core_get_preview_stream(LinphoneCore *call);
 LINPHONE_PUBLIC bool_t linphone_call_get_all_muted(const LinphoneCall *call);
-LINPHONE_PUBLIC LinphoneProxyConfig *linphone_call_get_dest_proxy(const LinphoneCall *call);
+LINPHONE_PUBLIC LinphoneAccount *linphone_call_get_dest_account(const LinphoneCall *call);
 LINPHONE_PUBLIC unsigned int _linphone_call_get_nb_audio_starts(const LinphoneCall *call);
 LINPHONE_PUBLIC unsigned int _linphone_call_get_nb_audio_stops(const LinphoneCall *call);
 LINPHONE_PUBLIC unsigned int _linphone_call_get_nb_video_starts(const LinphoneCall *call);
@@ -284,6 +284,8 @@ LINPHONE_PUBLIC void linphone_conference_info_set_uri(LinphoneConferenceInfo *co
 LINPHONE_PUBLIC bool_t linphone_participant_preserve_session(const LinphoneParticipant *participant);
 LINPHONE_PUBLIC bool_t linphone_conference_params_is_static(const LinphoneConferenceParams *params);
 
+LINPHONE_PUBLIC char *sal_get_random_token_lowercase(int size);
+
 #ifndef __cplusplus
 LINPHONE_PUBLIC Sal *linphone_core_get_sal(const LinphoneCore *lc);
 LINPHONE_PUBLIC SalOp *linphone_proxy_config_get_sal_op(const LinphoneProxyConfig *cfg);
@@ -294,7 +296,6 @@ LINPHONE_PUBLIC void sal_uninit(Sal *sal);
 
 LINPHONE_PUBLIC int sal_create_uuid(Sal *ctx, char *uuid, size_t len);
 LINPHONE_PUBLIC char *sal_get_random_token(int size);
-LINPHONE_PUBLIC char *sal_get_random_token_lowercase(int size);
 LINPHONE_PUBLIC void sal_set_uuid(Sal *ctx, const char *uuid);
 
 LINPHONE_PUBLIC void sal_default_set_sdp_handling(Sal *h, SalOpSDPHandling handling_method);
diff --git a/coreapi/vcard_stubs.c b/coreapi/vcard_stubs.c
index 27692ce9ab250e66f564ac58e4e777bdf0339a81..109ec0967d595f4019f3fa051dbfa6124bac8a80 100644
--- a/coreapi/vcard_stubs.c
+++ b/coreapi/vcard_stubs.c
@@ -70,15 +70,18 @@ LinphoneVcard *linphone_vcard_ref(BCTBX_UNUSED(LinphoneVcard *vCard)) {
 void linphone_vcard_unref(BCTBX_UNUSED(LinphoneVcard *vCard)) {
 }
 
-bctbx_list_t *linphone_vcard_context_get_vcard_list_from_file(BCTBX_UNUSED(LinphoneVcardContext *context), BCTBX_UNUSED(const char *filename)) {
+bctbx_list_t *linphone_vcard_context_get_vcard_list_from_file(BCTBX_UNUSED(LinphoneVcardContext *context),
+                                                              BCTBX_UNUSED(const char *filename)) {
 	return NULL;
 }
 
-bctbx_list_t *linphone_vcard_context_get_vcard_list_from_buffer(BCTBX_UNUSED(LinphoneVcardContext *context), BCTBX_UNUSED(const char *buffer)) {
+bctbx_list_t *linphone_vcard_context_get_vcard_list_from_buffer(BCTBX_UNUSED(LinphoneVcardContext *context),
+                                                                BCTBX_UNUSED(const char *buffer)) {
 	return NULL;
 }
 
-LinphoneVcard *linphone_vcard_context_get_vcard_from_buffer(BCTBX_UNUSED(LinphoneVcardContext *context), BCTBX_UNUSED(const char *buffer)) {
+LinphoneVcard *linphone_vcard_context_get_vcard_from_buffer(BCTBX_UNUSED(LinphoneVcardContext *context),
+                                                            BCTBX_UNUSED(const char *buffer)) {
 	return NULL;
 }
 
@@ -137,10 +140,12 @@ bctbx_list_t *linphone_vcard_get_phone_numbers(BCTBX_UNUSED(const LinphoneVcard
 	return NULL;
 }
 
-void linphone_vcard_add_phone_number_with_label(BCTBX_UNUSED(LinphoneVcard *vCard), BCTBX_UNUSED(LinphoneFriendPhoneNumber *phoneNumber)) {
+void linphone_vcard_add_phone_number_with_label(BCTBX_UNUSED(LinphoneVcard *vCard),
+                                                BCTBX_UNUSED(LinphoneFriendPhoneNumber *phoneNumber)) {
 }
 
-void linphone_vcard_remove_phone_number_with_label(BCTBX_UNUSED(LinphoneVcard *vCard), BCTBX_UNUSED(const LinphoneFriendPhoneNumber *phoneNumber)) {
+void linphone_vcard_remove_phone_number_with_label(BCTBX_UNUSED(LinphoneVcard *vCard),
+                                                   BCTBX_UNUSED(const LinphoneFriendPhoneNumber *phoneNumber)) {
 }
 
 bctbx_list_t *linphone_vcard_get_phone_numbers_with_label(BCTBX_UNUSED(const LinphoneVcard *vCard)) {
@@ -214,11 +219,16 @@ LinphoneVcard *linphone_vcard_clone(BCTBX_UNUSED(const LinphoneVcard *vCard)) {
 	return NULL;
 }
 
-bctbx_list_t *linphone_vcard_get_extended_properties_values_by_name(BCTBX_UNUSED(const LinphoneVcard *vCard), BCTBX_UNUSED(const char *name)) {
+bctbx_list_t *linphone_vcard_get_extended_properties_values_by_name(BCTBX_UNUSED(const LinphoneVcard *vCard),
+                                                                    BCTBX_UNUSED(const char *name)) {
 	return NULL;
 }
-void linphone_vcard_add_extended_property(BCTBX_UNUSED(LinphoneVcard *vCard), BCTBX_UNUSED(const char *name), BCTBX_UNUSED(const char *value)) {
+
+void linphone_vcard_add_extended_property(BCTBX_UNUSED(LinphoneVcard *vCard),
+                                          BCTBX_UNUSED(const char *name),
+                                          BCTBX_UNUSED(const char *value)) {
 }
 
-void linphone_vcard_remove_extented_properties_by_name(BCTBX_UNUSED(LinphoneVcard *vCard), BCTBX_UNUSED(const char *name)) {
+void linphone_vcard_remove_extented_properties_by_name(BCTBX_UNUSED(LinphoneVcard *vCard),
+                                                       BCTBX_UNUSED(const char *name)) {
 }
diff --git a/daemon/commands/pop-event.cc b/daemon/commands/pop-event.cc
index 907d3ef8774e2216047ca219cc1fa00e3dd343d3..e9ffa7d1826df73b4f864fdbdaeb3f7ef2cae4ae 100644
--- a/daemon/commands/pop-event.cc
+++ b/daemon/commands/pop-event.cc
@@ -29,6 +29,7 @@ PopEventCommand::PopEventCommand()
 	addExample(make_unique<DaemonCommandExample>("pop-event", "Status: Ok\n\n"
 	                                                          "Size: 0"));
 }
+
 void PopEventCommand::exec(Daemon *app, BCTBX_UNUSED(const string &args)) {
 	app->pullEvent();
 }
diff --git a/include/linphone/api/c-account-params.h b/include/linphone/api/c-account-params.h
index 917b710d9f9d131bc15a9bb1de9521b159ed2ac3..af46efc1529ca986d28142915ac635c372c091cf 100644
--- a/include/linphone/api/c-account-params.h
+++ b/include/linphone/api/c-account-params.h
@@ -95,7 +95,7 @@ LINPHONE_PUBLIC void *linphone_account_params_get_user_data(const LinphoneAccoun
  * @return 0 if successful, -1 otherwise.
  **/
 LINPHONE_PUBLIC LinphoneStatus linphone_account_params_set_server_address(LinphoneAccountParams *params,
-                                                                          const LinphoneAddress *server_address);
+                                                                          LinphoneAddress *server_address);
 
 /**
  * Sets the proxy address
@@ -125,7 +125,7 @@ LINPHONE_PUBLIC LinphoneStatus linphone_account_params_set_server_addr(LinphoneA
  * @return 0 if successful, -1 otherwise.
  **/
 LINPHONE_PUBLIC LinphoneStatus linphone_account_params_set_identity_address(LinphoneAccountParams *params,
-                                                                            const LinphoneAddress *identity);
+                                                                            LinphoneAddress *identity);
 
 /**
  * Sets a list of SIP route.
@@ -324,7 +324,7 @@ LINPHONE_PUBLIC void linphone_account_params_set_realm(LinphoneAccountParams *pa
  * @param params The #LinphoneAccountParams object. @notnil
  * @return The list of routes. \bctbx_list{LinphoneAddress} @maybenil
  */
-LINPHONE_PUBLIC const bctbx_list_t *linphone_account_params_get_routes_addresses(const LinphoneAccountParams *params);
+LINPHONE_PUBLIC bctbx_list_t *linphone_account_params_get_routes_addresses(const LinphoneAccountParams *params);
 
 /**
  * Get the identity address of the account params.
@@ -601,7 +601,7 @@ LINPHONE_PUBLIC void linphone_account_params_set_conference_factory_uri(Linphone
  * @param uri The uri of the audio video conference factory. @maybenil
  */
 LINPHONE_PUBLIC void linphone_account_params_set_audio_video_conference_factory_address(LinphoneAccountParams *params,
-                                                                                        const LinphoneAddress *address);
+                                                                                        LinphoneAddress *address);
 
 /**
  * If enabled, the proxy will be used as the only route.
@@ -804,7 +804,7 @@ LINPHONE_PUBLIC const char *linphone_account_params_get_custom_param(const Linph
  * @param contact a #LinphoneAddress the optional alternative contact address. @maybenil
  */
 LINPHONE_PUBLIC void linphone_account_params_set_custom_contact(LinphoneAccountParams *params,
-                                                                const LinphoneAddress *contact);
+                                                                LinphoneAddress *contact);
 
 /**
  * Get the custom contact address previously used when registering to the SIP server.
diff --git a/include/linphone/api/c-account.h b/include/linphone/api/c-account.h
index fb13e32ce1876dec3f2725b40053a5eb5400001e..fba62277e3dcfb45b12ff30dea9bf0becf51b6cc 100644
--- a/include/linphone/api/c-account.h
+++ b/include/linphone/api/c-account.h
@@ -178,7 +178,7 @@ LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_account_get_error_info(Linphon
  * @param account The #LinphoneAccount object. @notnil
  * @return a #LinphoneAddress correspong to the contact address of the account. @maybenil
  **/
-LINPHONE_PUBLIC const LinphoneAddress *linphone_account_get_contact_address(LinphoneAccount *account);
+LINPHONE_PUBLIC LinphoneAddress *linphone_account_get_contact_address(LinphoneAccount *account);
 
 /**
  * Set the contact address for the account.
diff --git a/include/linphone/api/c-call.h b/include/linphone/api/c-call.h
index 60eadc87ca707aa2a5e3b37b31ac31c48b8305f3..c8c6957a33cc6515cbdb75f1a1c859d1f63cffa4 100644
--- a/include/linphone/api/c-call.h
+++ b/include/linphone/api/c-call.h
@@ -438,7 +438,7 @@ LINPHONE_PUBLIC LinphoneStatus linphone_call_terminate_with_error_info(LinphoneC
  * @param redirect_address The #LinphoneAddress to redirect the call to @notnil
  * @return 0 if successful, -1 on error.
  */
-LINPHONE_PUBLIC LinphoneStatus linphone_call_redirect_to(LinphoneCall *call, const LinphoneAddress *redirect_address);
+LINPHONE_PUBLIC LinphoneStatus linphone_call_redirect_to(LinphoneCall *call, LinphoneAddress *redirect_address);
 
 /**
  * Decline a pending incoming call, with a reason.
@@ -575,7 +575,7 @@ LINPHONE_PUBLIC LinphoneStatus linphone_call_accept_update(LinphoneCall *call, c
  * @param refer_to The #LinphoneAddress the call is to be refered to. @notnil
  * @return 0 on success, -1 on failure
  **/
-LINPHONE_PUBLIC LinphoneStatus linphone_call_transfer_to(LinphoneCall *call, const LinphoneAddress *refer_to);
+LINPHONE_PUBLIC LinphoneStatus linphone_call_transfer_to(LinphoneCall *call, LinphoneAddress *refer_to);
 
 /**
  * Transfers a call to destination of another running call. This is used for "attended transfer" scenarios.
diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h
index e695c664ef0569096026f314ea6f40be6f03706d..b740119ab187a7b728868a9c9fdcb693f1024d5b 100644
--- a/include/linphone/api/c-chat-room.h
+++ b/include/linphone/api/c-chat-room.h
@@ -454,7 +454,7 @@ LINPHONE_PUBLIC time_t linphone_chat_room_get_last_update_time(const LinphoneCha
  * @param chat_room A #LinphoneChatRoom object @notnil
  * @param addr The address of the participant to add to the chat room @notnil
  */
-LINPHONE_PUBLIC void linphone_chat_room_add_participant(LinphoneChatRoom *chat_room, const LinphoneAddress *addr);
+LINPHONE_PUBLIC void linphone_chat_room_add_participant(LinphoneChatRoom *chat_room, LinphoneAddress *addr);
 
 /**
  * Add several participants to a chat room at once. This may fail if this type of chat room does not handle
@@ -479,7 +479,7 @@ LINPHONE_PUBLIC bool_t linphone_chat_room_can_handle_participants(const Linphone
  * @return The participant if found, NULL otherwise. @maybenil
  */
 LINPHONE_PUBLIC LinphoneParticipant *linphone_chat_room_find_participant(const LinphoneChatRoom *chat_room,
-                                                                         const LinphoneAddress *address);
+                                                                         LinphoneAddress *address);
 
 /**
  * Get the capabilities of a chat room.
@@ -592,7 +592,7 @@ LINPHONE_PUBLIC const bctbx_list_t *linphone_chat_room_get_composing_addresses(L
  * @param conference_address The conference #LinphoneAddress to be used by the group chat room @maybenil
  */
 LINPHONE_PUBLIC void linphone_chat_room_set_conference_address(LinphoneChatRoom *chat_room,
-                                                               const LinphoneAddress *conference_address);
+                                                               LinphoneAddress *conference_address);
 
 /**
  * Set the list of participant devices in the form of SIP URIs with GRUUs for a given participant.
@@ -603,7 +603,7 @@ LINPHONE_PUBLIC void linphone_chat_room_set_conference_address(LinphoneChatRoom
  * \bctbx_list{LinphoneParticipantDeviceIdentity} @notnil
  */
 LINPHONE_PUBLIC void linphone_chat_room_set_participant_devices(LinphoneChatRoom *chat_room,
-                                                                const LinphoneAddress *participant_address,
+                                                                LinphoneAddress *participant_address,
                                                                 const bctbx_list_t *device_identities);
 
 /**
diff --git a/include/linphone/api/c-conference-info.h b/include/linphone/api/c-conference-info.h
index 0a94da6a809bfde42ef9f3884d95da41e050734f..bdbbc29c81465734cb2b132f93b50dffa4135994 100644
--- a/include/linphone/api/c-conference-info.h
+++ b/include/linphone/api/c-conference-info.h
@@ -79,8 +79,7 @@ LINPHONE_PUBLIC void linphone_conference_info_set_organizer(LinphoneConferenceIn
  * @param conference_info The #LinphoneConferenceInfo object. @notnil
  * @return The list of participants. \bctbx_list{LinphoneAddress} @maybenil
  */
-LINPHONE_PUBLIC const bctbx_list_t *
-linphone_conference_info_get_participants(const LinphoneConferenceInfo *conference_info);
+LINPHONE_PUBLIC bctbx_list_t *linphone_conference_info_get_participants(const LinphoneConferenceInfo *conference_info);
 
 /**
  * Set the list of participants.
@@ -88,7 +87,7 @@ linphone_conference_info_get_participants(const LinphoneConferenceInfo *conferen
  * @param participants The list of participants to set. \bctbx_list{LinphoneAddress} @maybenil
  */
 LINPHONE_PUBLIC void linphone_conference_info_set_participants(LinphoneConferenceInfo *conference_info,
-                                                               const bctbx_list_t *participants);
+                                                               bctbx_list_t *participants);
 
 /**
  * Add a participant to the conference.
diff --git a/include/linphone/core.h b/include/linphone/core.h
index 1f16f32bd38b405b6e7e65fa4eace5fd6d36087e..1bdf44274d7801532528b8874b1c489dd6299248 100644
--- a/include/linphone/core.h
+++ b/include/linphone/core.h
@@ -2185,7 +2185,7 @@ LINPHONE_PUBLIC void linphone_core_set_default_proxy_config(LinphoneCore *core,
  */
 
 /**
- * @addtogroup accounts
+ * @addtogroup account
  * @{
  */
 
@@ -5794,7 +5794,7 @@ LINPHONE_PUBLIC LinphoneContent *linphone_core_create_content(LinphoneCore *core
  * @return a #LinphoneEvent holding the context of the created subcription. @notnil
  **/
 LINPHONE_PUBLIC LinphoneEvent *linphone_core_subscribe(
-    LinphoneCore *core, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body);
+    LinphoneCore *core, LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body);
 
 /**
  * Create an outgoing subscription, specifying the destination resource, the event name, and an optional content body.
@@ -5808,7 +5808,7 @@ LINPHONE_PUBLIC LinphoneEvent *linphone_core_subscribe(
  * @return a #LinphoneEvent holding the context of the created subcription. @notnil
  **/
 LINPHONE_PUBLIC LinphoneEvent *
-linphone_core_create_subscribe(LinphoneCore *core, const LinphoneAddress *resource, const char *event, int expires);
+linphone_core_create_subscribe(LinphoneCore *core, LinphoneAddress *resource, const char *event, int expires);
 
 /**
  * Create an outgoing subscription, specifying the destination resource, the event name, and an optional content body.
@@ -5823,7 +5823,7 @@ linphone_core_create_subscribe(LinphoneCore *core, const LinphoneAddress *resour
  * @return a #LinphoneEvent holding the context of the created subcription. @notnil
  **/
 LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_subscribe_2(
-    LinphoneCore *core, const LinphoneAddress *resource, LinphoneProxyConfig *proxy, const char *event, int expires);
+    LinphoneCore *core, LinphoneAddress *resource, LinphoneProxyConfig *proxy, const char *event, int expires);
 
 /**
  * Create an out-of-dialog notification, specifying the destination resource, the event name.
@@ -5834,7 +5834,7 @@ LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_subscribe_2(
  * @return a #LinphoneEvent holding the context of the notification. @notnil
  **/
 LINPHONE_PUBLIC LinphoneEvent *
-linphone_core_create_notify(LinphoneCore *core, const LinphoneAddress *resource, const char *event);
+linphone_core_create_notify(LinphoneCore *core, LinphoneAddress *resource, const char *event);
 
 /**
  * Publish an event state.
@@ -5849,7 +5849,7 @@ linphone_core_create_notify(LinphoneCore *core, const LinphoneAddress *resource,
  * @return the #LinphoneEvent holding the context of the publish. @maybenil
  **/
 LINPHONE_PUBLIC LinphoneEvent *linphone_core_publish(
-    LinphoneCore *core, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body);
+    LinphoneCore *core, LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body);
 
 /**
  * Create a publish context for an event state.
@@ -5863,7 +5863,7 @@ LINPHONE_PUBLIC LinphoneEvent *linphone_core_publish(
  * @return the #LinphoneEvent holding the context of the publish. @notnil
  **/
 LINPHONE_PUBLIC LinphoneEvent *
-linphone_core_create_publish(LinphoneCore *core, const LinphoneAddress *resource, const char *event, int expires);
+linphone_core_create_publish(LinphoneCore *core, LinphoneAddress *resource, const char *event, int expires);
 
 /**
  * Create a publish context for a one-shot publish.
@@ -5876,7 +5876,7 @@ linphone_core_create_publish(LinphoneCore *core, const LinphoneAddress *resource
  * @return the #LinphoneEvent holding the context of the publish. @notnil
  **/
 LINPHONE_PUBLIC LinphoneEvent *
-linphone_core_create_one_shot_publish(LinphoneCore *core, const LinphoneAddress *resource, const char *event);
+linphone_core_create_one_shot_publish(LinphoneCore *core, LinphoneAddress *resource, const char *event);
 
 /**
  * @}
diff --git a/include/linphone/friendlist.h b/include/linphone/friendlist.h
index 2ef0cc2cb50733db7b21375cd45b80c3cf96e010..8982863e5f7c55f584aa0b1eb71ee83332c8be94 100644
--- a/include/linphone/friendlist.h
+++ b/include/linphone/friendlist.h
@@ -107,7 +107,7 @@ LINPHONE_PUBLIC void linphone_friend_list_set_rls_uri(LinphoneFriendList *friend
  * @param friend_list #LinphoneFriendList object. @notnil
  * @return The RLS URI as #LinphoneAddress associated with the friend list. @maybenil
  **/
-LINPHONE_PUBLIC const LinphoneAddress *linphone_friend_list_get_rls_address(const LinphoneFriendList *friend_list);
+LINPHONE_PUBLIC LinphoneAddress *linphone_friend_list_get_rls_address(const LinphoneFriendList *friend_list);
 
 /**
  * Set the RLS (Resource List Server) URI associated with the friend list to subscribe to these friends presence.
diff --git a/include/linphone/proxy_config.h b/include/linphone/proxy_config.h
index f6ee4d9e51d7a203ad435883a6f18bc0ab8b1dab..87baa3f1bf2033d461fe2f3324d82474fc6d9af0 100644
--- a/include/linphone/proxy_config.h
+++ b/include/linphone/proxy_config.h
@@ -87,7 +87,7 @@ LINPHONE_PUBLIC LinphoneStatus linphone_proxy_config_set_server_addr(LinphonePro
  * @deprecated 06/04/2020 Use #LinphoneAccount object instead
  **/
 LINPHONE_PUBLIC LinphoneStatus linphone_proxy_config_set_identity_address(LinphoneProxyConfig *proxy_config,
-                                                                          const LinphoneAddress *identity);
+                                                                          LinphoneAddress *identity);
 
 /**
  * Sets a list of SIP route.
diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h
index cd9254b2ff6994f9170debacbe39d53fa2d6eb65..38eae9b0c85925ab80fedd288455fe73dba10626 100644
--- a/include/linphone/utils/utils.h
+++ b/include/linphone/utils/utils.h
@@ -39,6 +39,11 @@
 
 LINPHONE_BEGIN_NAMESPACE
 
+class Address;
+class Content;
+class ConferenceInfo;
+class SalCallOp;
+
 namespace Utils {
 template <typename T>
 constexpr T *getPtr(std::shared_ptr<T> &object) {
@@ -129,15 +134,7 @@ inline std::string join(const std::vector<T> &elems, const S &delim) {
 LINPHONE_PUBLIC std::string trim(const std::string &str);
 LINPHONE_PUBLIC std::string normalizeFilename(const std::string &str);
 
-template <typename T, typename std::enable_if<std::is_base_of<Address, T>::value>::type * = nullptr>
-inline const T &getEmptyConstRefObject() {
-	static const T object{};
-	object.removeFromLeakDetector();
-	return object;
-}
-
-template <typename T, typename std::enable_if<!std::is_base_of<Address, T>::value>::type * = nullptr>
-
+template <typename T>
 inline const T &getEmptyConstRefObject() {
 	return bctoolbox::Utils::getEmptyConstRefObject<T>();
 }
@@ -157,6 +154,29 @@ inline std::list<typename Container::value_type> toList(const Container &l) {
 	return v;
 }
 
+template <typename cT,
+          typename cppT,
+          typename std::enable_if<std::is_base_of<bellesip::HybridObject<cT, cppT>, cppT>::value>::type * = nullptr>
+bctbx_list_t *listToCBctbxList(const std::list<std::shared_ptr<cppT>> &l) {
+	bctbx_list_t *bcList = NULL;
+	for (const auto &e : l) {
+		bcList = bctbx_list_append(bcList, e->toC());
+	}
+	return bcList;
+}
+
+template <typename cT,
+          typename cppT,
+          typename std::enable_if<std::is_base_of<bellesip::HybridObject<cT, cppT>, cppT>::value>::type * = nullptr>
+std::list<std::shared_ptr<cppT>> bctbxListToCppSharedPtrList(const bctbx_list_t *l) {
+	std::list<std::shared_ptr<cppT>> cppList;
+	for (const bctbx_list_t *elem = l; elem != NULL; elem = elem->next) {
+		cT *data = static_cast<cT *>(bctbx_list_get_data(elem));
+		cppList.push_back(cppT::toCpp(data)->getSharedFromThis());
+	}
+	return cppList;
+}
+
 template <class T>
 bctbx_list_t *listToBctbxList(const std::list<T> &l) {
 	bctbx_list_t *bcList = NULL;
@@ -175,6 +195,7 @@ std::list<T> bctbxListToList(bctbx_list_t *l) {
 	}
 	return cppList;
 }
+
 LINPHONE_PUBLIC std::tm getTimeTAsTm(time_t t);
 LINPHONE_PUBLIC time_t getTmAsTimeT(const std::tm &t);
 LINPHONE_PUBLIC std::string getTimeAsString(const std::string &format, time_t t);
@@ -239,8 +260,8 @@ private:
  */
 LINPHONE_PUBLIC std::map<std::string, Version> parseCapabilityDescriptor(const std::string &descriptor);
 std::string getSipFragAddress(const Content &content);
-std::string getResourceLists(const std::list<IdentityAddress> &addresses);
-std::list<IdentityAddress> parseResourceLists(const Content &content);
+std::string getResourceLists(const std::list<std::shared_ptr<Address>> &addresses);
+std::list<std::shared_ptr<Address>> parseResourceLists(const Content &content);
 std::shared_ptr<ConferenceInfo> createConferenceInfoFromOp(SalCallOp *op, bool remote);
 } // namespace Utils
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 98a4fcd718a6ebe1f334b110a3355992d1e80ff7..3eab312cbc8f9611a28d10b2dd07fb637c5d913a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -128,8 +128,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
 	account/account.h
 	account/account-params.h
 	address/address.h
-	address/identity-address.h
-	address/identity-address-parser.h
+	address/address-parser.h
 	auth-info/auth-info.h
 	auth-info/auth-stack.h
 	c-wrapper/c-wrapper.h
@@ -349,8 +348,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
 	account_creator/main.cpp
 	account_creator/connector_xmlrpc.cpp
 	address/address.cpp
-	address/identity-address.cpp
-	address/identity-address-parser.cpp
+	address/address-parser.cpp
 	auth-info/auth-info.cpp
 	auth-info/auth-stack.cpp
 	c-wrapper/c-wrapper.cpp
diff --git a/src/account/account-params.cpp b/src/account/account-params.cpp
index e1a594181a43a0d98958ff4a300fd09ba2fdb388..fcea538a0cbb374198b9d7369df0c8f4854a5cbb 100644
--- a/src/account/account-params.cpp
+++ b/src/account/account-params.cpp
@@ -20,6 +20,7 @@
 
 #include "account-params.h"
 #include "c-wrapper/internal/c-tools.h"
+#include "core/core.h"
 #include "linphone/api/c-address.h"
 #include "linphone/types.h"
 #include "nat/nat-policy.h"
@@ -50,12 +51,13 @@ AccountParams::AccountParams(LinphoneCore *lc) {
 	                                                                     LinphonePrivacyDefault)
 	              : (LinphonePrivacyMask)LinphonePrivacyDefault;
 	mIdentity = lc ? linphone_config_get_default_string(lc->config, "proxy", "reg_identity", "") : "";
-	mIdentityAddress = !mIdentity.empty() ? linphone_address_new(mIdentity.c_str()) : nullptr;
+	mIdentityAddress = Address::create(mIdentity);
 	mProxy = lc ? linphone_config_get_default_string(lc->config, "proxy", "reg_proxy", "") : "";
-	mProxyAddress = !mProxy.empty() ? linphone_address_new(mProxy.c_str()) : nullptr;
+	mProxyAddress = Address::create(mProxy);
 	string route = lc ? linphone_config_get_default_string(lc->config, "proxy", "reg_route", "") : "";
-	mRoutes = !route.empty() ? bctbx_list_append(mRoutes, linphone_address_new(route.c_str())) : nullptr;
-	mRoutesString = !route.empty() ? bctbx_list_append(mRoutesString, bctbx_strdup(route.c_str())) : nullptr;
+	if (!route.empty()) {
+		mRoutes.emplace_back(Address::create(route));
+	}
 	mRealm = lc ? linphone_config_get_default_string(lc->config, "proxy", "realm", "") : "";
 	mQualityReportingEnabled =
 	    lc ? !!linphone_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", false) : false;
@@ -129,7 +131,7 @@ AccountParams::AccountParams(LinphoneCore *lc) {
 	    lc ? linphone_config_get_default_string(lc->config, "proxy", "audio_video_conference_factory_uri", "") : "";
 	mAudioVideoConferenceFactoryAddress = nullptr;
 	if (!audioVideoConferenceFactoryUri.empty()) {
-		mAudioVideoConferenceFactoryAddress = linphone_address_new(audioVideoConferenceFactoryUri.c_str());
+		mAudioVideoConferenceFactoryAddress = Address::create(audioVideoConferenceFactoryUri);
 	}
 
 	if (lc && lc->push_config) {
@@ -159,9 +161,8 @@ AccountParams::AccountParams(LinphoneCore *lc, int index) : AccountParams(lc) {
 	sprintf(key, "proxy_%i", index); // TODO: change to account
 
 	mIdentity = linphone_config_get_string(config, key, "reg_identity", mIdentity.c_str());
-	LinphoneAddress *identity_address = linphone_address_new(mIdentity.c_str());
+	std::shared_ptr<Address> identity_address = Address::create(mIdentity);
 	setIdentityAddress(identity_address);
-	if (identity_address) linphone_address_unref(identity_address);
 
 	setServerAddressAsString(linphone_config_get_string(config, key, "reg_proxy", getServerAddressAsString().c_str()));
 
@@ -169,16 +170,6 @@ AccountParams::AccountParams(LinphoneCore *lc, int index) : AccountParams(lc) {
 	if (routes != nullptr) {
 		setRoutesFromStringList(routes);
 		bctbx_list_free_with_data(routes, (bctbx_list_free_func)bctbx_free);
-	} else {
-		// Remove default routes if the existing account doesn't have any
-		if (mRoutes) {
-			bctbx_list_free_with_data(mRoutes, (bctbx_list_free_func)linphone_address_unref);
-			mRoutes = nullptr;
-		}
-		if (mRoutesString) {
-			bctbx_list_free_with_data(mRoutesString, (bctbx_list_free_func)bctbx_free);
-			mRoutesString = nullptr;
-		}
 	}
 
 	mRealm = linphone_config_get_string(config, key, "realm", mRealm.c_str());
@@ -254,7 +245,7 @@ AccountParams::AccountParams(LinphoneCore *lc, int index) : AccountParams(lc) {
 	    linphone_config_get_string(config, key, "audio_video_conference_factory_uri", "");
 	mAudioVideoConferenceFactoryAddress = nullptr;
 	if (!audioVideoConferenceFactoryUri.empty()) {
-		mAudioVideoConferenceFactoryAddress = linphone_address_new(audioVideoConferenceFactoryUri.c_str());
+		mAudioVideoConferenceFactoryAddress = Address::create(audioVideoConferenceFactoryUri);
 	}
 	mRtpBundleEnabled = !!linphone_config_get_bool(config, key, "rtp_bundle", linphone_core_rtp_bundle_enabled(lc));
 	mRtpBundleAssumption = !!linphone_config_get_bool(config, key, "rtp_bundle_assumption", FALSE);
@@ -293,19 +284,27 @@ AccountParams::AccountParams(const AccountParams &other) : HybridObject(other),
 	mDependsOn = other.mDependsOn;
 	mIdKey = other.mIdKey;
 	mConferenceFactoryUri = other.mConferenceFactoryUri;
-	mAudioVideoConferenceFactoryAddress = other.mAudioVideoConferenceFactoryAddress
-	                                          ? linphone_address_clone(other.mAudioVideoConferenceFactoryAddress)
-	                                          : nullptr;
-	mFileTransferServer = other.mFileTransferServer;
-	mIdentity = other.mIdentity;
+	if (other.mAudioVideoConferenceFactoryAddress) {
+		mAudioVideoConferenceFactoryAddress = other.mAudioVideoConferenceFactoryAddress->clone()->toSharedPtr();
+	} else {
+		mAudioVideoConferenceFactoryAddress = nullptr;
+	}
 
-	mRoutes = bctbx_list_copy_with_data(other.mRoutes, (bctbx_list_copy_func)linphone_address_clone);
-	mRoutesString = bctbx_list_copy_with_data(other.mRoutesString, (bctbx_list_copy_func)bctbx_strdup);
+	mFileTransferServer = other.mFileTransferServer;
 
+	mRoutes = other.mRoutes;
 	mPrivacy = other.mPrivacy;
-
-	mIdentityAddress = other.mIdentityAddress ? linphone_address_clone(other.mIdentityAddress) : nullptr;
-	mProxyAddress = other.mProxyAddress ? linphone_address_clone(other.mProxyAddress) : nullptr;
+	mIdentity = other.mIdentity;
+	if (other.mIdentityAddress) {
+		mIdentityAddress = other.mIdentityAddress->clone()->toSharedPtr();
+	} else {
+		mIdentityAddress = nullptr;
+	}
+	if (other.mProxyAddress) {
+		mProxyAddress = other.mProxyAddress->clone()->toSharedPtr();
+	} else {
+		mProxyAddress = nullptr;
+	}
 
 	mAvpfMode = other.mAvpfMode;
 
@@ -314,18 +313,16 @@ AccountParams::AccountParams(const AccountParams &other) : HybridObject(other),
 	mPushNotificationConfig = other.mPushNotificationConfig->clone();
 	mRtpBundleEnabled = other.mRtpBundleEnabled;
 	mRtpBundleAssumption = other.mRtpBundleAssumption;
-	mCustomContact = other.mCustomContact ? linphone_address_clone(other.mCustomContact) : nullptr;
+	if (other.mCustomContact) {
+		mCustomContact = other.mCustomContact->clone()->toSharedPtr();
+	} else {
+		mCustomContact = nullptr;
+	}
 	mLimeServerUrl = other.mLimeServerUrl;
 }
 
 AccountParams::~AccountParams() {
-	if (mIdentityAddress) linphone_address_unref(mIdentityAddress);
-	if (mProxyAddress) linphone_address_unref(mProxyAddress);
-	if (mRoutes) bctbx_list_free_with_data(mRoutes, (bctbx_list_free_func)linphone_address_unref);
-	if (mRoutesString) bctbx_list_free_with_data(mRoutesString, (bctbx_list_free_func)bctbx_free);
 	if (mPushNotificationConfig) mPushNotificationConfig->unref();
-	if (mAudioVideoConferenceFactoryAddress) linphone_address_unref(mAudioVideoConferenceFactoryAddress);
-	if (mCustomContact) linphone_address_unref(mCustomContact);
 }
 
 AccountParams *AccountParams::clone() const {
@@ -371,15 +368,6 @@ void AccountParams::setPublishEnabled(bool enable) {
 void AccountParams::setOutboundProxyEnabled(bool enable) {
 	// If enable we remove all routes to only have the server address as route
 	// If disable since we should only have the server address route, we can remove the list
-	if (mRoutes) {
-		bctbx_list_free_with_data(mRoutes, (bctbx_list_free_func)linphone_address_unref);
-		mRoutes = nullptr;
-	}
-	if (mRoutesString) {
-		bctbx_list_free_with_data(mRoutesString, (bctbx_list_free_func)bctbx_free);
-		mRoutesString = nullptr;
-	}
-
 	// Use only the proxy as route
 	if (enable) {
 		if (!mProxyAddress) {
@@ -387,8 +375,7 @@ void AccountParams::setOutboundProxyEnabled(bool enable) {
 			return;
 		}
 
-		mRoutes = bctbx_list_append(mRoutes, linphone_address_clone(mProxyAddress));
-		mRoutesString = bctbx_list_append(mRoutesString, bctbx_strdup(mProxy.c_str()));
+		mRoutes.emplace_back(mProxyAddress);
 	}
 }
 
@@ -426,7 +413,7 @@ void AccountParams::setRealm(const std::string &realm) {
 
 void AccountParams::setQualityReportingCollector(const std::string &qualityReportingCollector) {
 	if (!qualityReportingCollector.empty()) {
-		LinphoneAddress *addr = linphone_address_new(qualityReportingCollector.c_str());
+		std::shared_ptr<Address> addr = Address::create(qualityReportingCollector);
 
 		if (!addr) {
 			lError() << "Invalid SIP collector URI: " << qualityReportingCollector
@@ -434,10 +421,6 @@ void AccountParams::setQualityReportingCollector(const std::string &qualityRepor
 		} else {
 			mQualityReportingCollector = qualityReportingCollector;
 		}
-
-		if (addr) {
-			linphone_address_unref(addr);
-		}
 	}
 }
 
@@ -469,39 +452,13 @@ void AccountParams::setFileTranferServer(const std::string &fileTransferServer)
 	mFileTransferServer = fileTransferServer;
 }
 
-LinphoneStatus AccountParams::setRoutes(const bctbx_list_t *routes) {
-	if (mRoutes != nullptr) {
-		bctbx_list_free_with_data(mRoutes, (bctbx_list_free_func)linphone_address_unref);
-		mRoutes = nullptr;
-	}
-	if (mRoutesString != nullptr) {
-		bctbx_list_free_with_data(mRoutesString, (bctbx_list_free_func)bctbx_free);
-		mRoutesString = nullptr;
-	}
-
-	bctbx_list_t *iterator = (bctbx_list_t *)routes;
-	while (iterator != nullptr) {
-		LinphoneAddress *routeAddress = (LinphoneAddress *)bctbx_list_get_data(iterator);
-		if (routeAddress != nullptr) {
-			mRoutes = bctbx_list_append(mRoutes, linphone_address_clone(routeAddress));
-			mRoutesString = bctbx_list_append(mRoutesString, linphone_address_as_string_uri_only(routeAddress));
-		}
-		iterator = bctbx_list_next(iterator);
-	}
-
+LinphoneStatus AccountParams::setRoutes(const std::list<std::shared_ptr<Address>> &routes) {
+	mRoutes = routes;
 	return 0;
 }
 
 LinphoneStatus AccountParams::setRoutesFromStringList(const bctbx_list_t *routes) {
-	if (mRoutes != nullptr) {
-		bctbx_list_free_with_data(mRoutes, (bctbx_list_free_func)linphone_address_unref);
-		mRoutes = nullptr;
-	}
-	if (mRoutesString != nullptr) {
-		bctbx_list_free_with_data(mRoutesString, (bctbx_list_free_func)bctbx_free);
-		mRoutesString = nullptr;
-	}
-
+	mRoutes.clear();
 	bctbx_list_t *iterator = (bctbx_list_t *)routes;
 	while (iterator != nullptr) {
 		char *route = (char *)bctbx_list_get_data(iterator);
@@ -516,8 +473,7 @@ LinphoneStatus AccountParams::setRoutesFromStringList(const bctbx_list_t *routes
 			SalAddress *addr = sal_address_new(tmp.c_str());
 			if (addr != NULL) {
 				sal_address_unref(addr);
-				mRoutes = bctbx_list_append(mRoutes, linphone_address_new(tmp.c_str()));
-				mRoutesString = bctbx_list_append(mRoutesString, bctbx_strdup(tmp.c_str()));
+				mRoutes.emplace_back(Address::create(tmp.c_str()));
 			} else {
 				return -1;
 			}
@@ -532,22 +488,14 @@ void AccountParams::setPrivacy(LinphonePrivacyMask privacy) {
 	mPrivacy = privacy;
 }
 
-LinphoneStatus AccountParams::setIdentityAddress(const LinphoneAddress *identityAddress) {
-	if (!identityAddress || linphone_address_get_username(identityAddress) == nullptr) {
-		char *as_string = identityAddress ? linphone_address_as_string(identityAddress) : ms_strdup("NULL");
-		lWarning() << "Invalid sip identity: " << as_string;
-		ms_free(as_string);
+LinphoneStatus AccountParams::setIdentityAddress(const std::shared_ptr<Address> identityAddress) {
+	if (!identityAddress || identityAddress->getUsername().empty()) {
+		lWarning() << "Invalid sip identity: " << identityAddress->toString();
 		return -1;
 	}
 
-	if (mIdentityAddress != nullptr) {
-		linphone_address_unref(mIdentityAddress);
-	}
-	mIdentityAddress = linphone_address_clone(identityAddress);
-
-	char *tmpIdentity = linphone_address_as_string(mIdentityAddress);
-	mIdentity = tmpIdentity;
-	bctbx_free(tmpIdentity);
+	mIdentityAddress = identityAddress->clone()->toSharedPtr();
+	mIdentity = mIdentityAddress->toString();
 
 	return 0;
 }
@@ -567,13 +515,13 @@ void AccountParams::setPushNotificationConfig(PushNotificationConfig *pushNotifi
 	mPushNotificationConfig->ref();
 }
 
-void AccountParams::setAudioVideoConferenceFactoryAddress(const LinphoneAddress *audioVideoConferenceFactoryAddress) {
+void AccountParams::setAudioVideoConferenceFactoryAddress(
+    const std::shared_ptr<Address> audioVideoConferenceFactoryAddress) {
 	if (mAudioVideoConferenceFactoryAddress != nullptr) {
-		linphone_address_unref(mAudioVideoConferenceFactoryAddress);
 		mAudioVideoConferenceFactoryAddress = nullptr;
 	}
 	if (audioVideoConferenceFactoryAddress != nullptr) {
-		mAudioVideoConferenceFactoryAddress = linphone_address_clone(audioVideoConferenceFactoryAddress);
+		mAudioVideoConferenceFactoryAddress = audioVideoConferenceFactoryAddress->clone()->toSharedPtr();
 	}
 }
 
@@ -585,17 +533,15 @@ void AccountParams::enableRtpBundleAssumption(bool value) {
 	mRtpBundleAssumption = value;
 }
 
-void AccountParams::setCustomContact(const LinphoneAddress *contact) {
-	if (mCustomContact) linphone_address_unref(mCustomContact);
-	mCustomContact = contact ? linphone_address_clone(contact) : nullptr;
+void AccountParams::setCustomContact(const std::shared_ptr<Address> contact) {
+	mCustomContact = contact ? contact->clone()->toSharedPtr() : nullptr;
 }
 
 void AccountParams::setCustomContact(const string &contact) {
-	LinphoneAddress *address = !contact.empty() ? linphone_address_new(contact.c_str()) : nullptr;
+	std::shared_ptr<Address> address = !contact.empty() ? Address::create(contact) : nullptr;
 	if (address == nullptr && !contact.empty()) {
 		lError() << "AccountParams: invalid custom contact '" << contact << "'";
 	}
-	if (mCustomContact) linphone_address_unref(mCustomContact);
 	mCustomContact = address;
 }
 
@@ -635,8 +581,8 @@ bool AccountParams::getPublishEnabled() const {
 }
 
 bool AccountParams::getOutboundProxyEnabled() const {
-	LinphoneAddress *address = mRoutes != nullptr ? (LinphoneAddress *)bctbx_list_get_data(mRoutes) : nullptr;
-	return address != nullptr && mProxyAddress != nullptr && linphone_address_weak_equal(mProxyAddress, address);
+	std::shared_ptr<Address> address = !mRoutes.empty() ? mRoutes.front() : nullptr;
+	return address != nullptr && mProxyAddress != nullptr && mProxyAddress->weakEqual(*address);
 }
 
 bool AccountParams::getPushNotificationAllowed() const {
@@ -677,8 +623,12 @@ const std::string &AccountParams::getInternationalPrefix() const {
 	return mInternationalPrefix;
 }
 
-const char *AccountParams::getDomain() const {
-	return mIdentityAddress ? linphone_address_get_domain(mIdentityAddress) : nullptr;
+const char *AccountParams::getDomainCstr() const {
+	return mIdentityAddress ? mIdentityAddress->getDomainCstr() : nullptr;
+}
+
+const std::string AccountParams::getDomain() const {
+	return mIdentityAddress ? mIdentityAddress->getDomain() : std::string();
 }
 
 const std::string &AccountParams::getProxy() const {
@@ -725,19 +675,23 @@ const std::string &AccountParams::getIdentity() const {
 	return mIdentity;
 }
 
-const bctbx_list_t *AccountParams::getRoutes() const {
+const std::list<std::shared_ptr<Address>> &AccountParams::getRoutes() const {
 	return mRoutes;
 }
 
-const bctbx_list_t *AccountParams::getRoutesString() const {
-	return mRoutesString;
+const std::list<std::string> AccountParams::getRoutesString() const {
+	std::list<std::string> routes;
+	for (const auto &r : mRoutes) {
+		routes.push_back(r->toString());
+	}
+	return routes;
 }
 
 LinphonePrivacyMask AccountParams::getPrivacy() const {
 	return mPrivacy;
 }
 
-LinphoneAddress *AccountParams::getIdentityAddress() const {
+const std::shared_ptr<Address> &AccountParams::getIdentityAddress() const {
 	return mIdentityAddress;
 }
 
@@ -753,7 +707,7 @@ PushNotificationConfig *AccountParams::getPushNotificationConfig() const {
 	return mPushNotificationConfig;
 }
 
-const LinphoneAddress *AccountParams::getAudioVideoConferenceFactoryAddress() const {
+const std::shared_ptr<Address> &AccountParams::getAudioVideoConferenceFactoryAddress() const {
 	return mAudioVideoConferenceFactoryAddress;
 }
 
@@ -765,7 +719,7 @@ bool AccountParams::rtpBundleAssumptionEnabled() const {
 	return mRtpBundleAssumption;
 }
 
-const LinphoneAddress *AccountParams::getCustomContact() const {
+const std::shared_ptr<Address> &AccountParams::getCustomContact() const {
 	return mCustomContact;
 }
 
@@ -779,15 +733,12 @@ const std::string &AccountParams::getLimeServerUrl() const {
 
 // -----------------------------------------------------------------------------
 
-LinphoneStatus AccountParams::setServerAddress(const LinphoneAddress *serverAddr) {
+LinphoneStatus AccountParams::setServerAddress(const std::shared_ptr<Address> serverAddr) {
 	bool outboundProxyEnabled = getOutboundProxyEnabled();
 
-	if (mProxyAddress) linphone_address_unref(mProxyAddress);
-	mProxyAddress = linphone_address_clone(serverAddr);
+	mProxyAddress = serverAddr->clone()->toSharedPtr();
 
-	char *tmpProxy = linphone_address_as_string(serverAddr);
-	mProxy = tmpProxy;
-	bctbx_free(tmpProxy);
+	mProxy = mProxyAddress->toString();
 
 	if (outboundProxyEnabled) {
 		// Setting this to true will do the job of setting the routes
@@ -797,37 +748,32 @@ LinphoneStatus AccountParams::setServerAddress(const LinphoneAddress *serverAddr
 	return 0;
 }
 
-const LinphoneAddress *AccountParams::getServerAddress() const {
+const std::shared_ptr<Address> &AccountParams::getServerAddress() const {
 	return mProxyAddress;
 }
 
 LinphoneStatus AccountParams::setServerAddressAsString(const std::string &serverAddr) {
-	LinphoneAddress *addr = nullptr;
+	std::shared_ptr<Address> addr = nullptr;
 
 	if (!serverAddr.empty()) {
 		if (serverAddr.rfind("sip:") == string::npos && serverAddr.rfind("sips:") == string::npos) {
 			string modified("");
 			modified.append("sip:").append(serverAddr);
-			addr = linphone_address_new(modified.c_str());
+			addr = Address::create(modified);
 		}
 
-		if (addr == nullptr) addr = linphone_address_new(serverAddr.c_str());
+		if (addr == nullptr) addr = Address::create(serverAddr);
 		if (addr) {
 			bool outboundProxyEnabled = getOutboundProxyEnabled();
 
-			if (mProxyAddress) linphone_address_unref(mProxyAddress);
-			mProxyAddress = linphone_address_clone(addr);
+			mProxyAddress = addr->clone()->toSharedPtr();
 
-			char *tmpProxy = linphone_address_as_string(addr);
-			mProxy = tmpProxy;
-			bctbx_free(tmpProxy);
+			mProxy = mProxyAddress->toString();
 
 			if (outboundProxyEnabled) {
 				// Setting this to true will do the job of setting the routes
 				setOutboundProxyEnabled(true);
 			}
-
-			linphone_address_unref(addr);
 		} else {
 			lWarning() << "Could not parse " << serverAddr;
 			return -1;
@@ -841,20 +787,18 @@ const std::string &AccountParams::getServerAddressAsString() const {
 	return mProxy;
 }
 
-void AccountParams::setTransport(LinphoneTransportType transport) {
-	linphone_address_set_transport(mProxyAddress, transport);
+void AccountParams::setTransport(LinphonePrivate::Transport transport) {
+	mProxyAddress->setTransport(transport);
 
-	char *tmpProxy = linphone_address_as_string(mProxyAddress);
-	mProxy = tmpProxy;
-	bctbx_free(tmpProxy);
+	mProxy = mProxyAddress->toString();
 
 	if (getOutboundProxyEnabled()) {
 		setOutboundProxyEnabled(true);
 	}
 }
 
-LinphoneTransportType AccountParams::getTransport() const {
-	return linphone_address_get_transport(mProxyAddress);
+LinphonePrivate::Transport AccountParams::getTransport() const {
+	return mProxyAddress->getTransport();
 }
 
 void AccountParams::writeToConfigFile(LinphoneConfig *config, int index) {
@@ -866,8 +810,10 @@ void AccountParams::writeToConfigFile(LinphoneConfig *config, int index) {
 	if (!mProxy.empty()) {
 		linphone_config_set_string(config, key, "reg_proxy", mProxy.c_str());
 	}
-	if (mRoutesString != NULL) {
-		linphone_config_set_string_list(config, key, "reg_route", mRoutesString);
+	if (!mRoutes.empty()) {
+		auto routesString = L_GET_C_LIST_FROM_CPP_LIST(getRoutesString());
+		linphone_config_set_string_list(config, key, "reg_route", routesString);
+		bctbx_list_free_with_data(routesString, (bctbx_list_free_func)bctbx_free);
 	}
 	if (!mIdentity.empty()) {
 		linphone_config_set_string(config, key, "reg_identity", mIdentity.c_str());
@@ -917,7 +863,7 @@ void AccountParams::writeToConfigFile(LinphoneConfig *config, int index) {
 	linphone_config_set_string(config, key, "conference_factory_uri", mConferenceFactoryUri.c_str());
 
 	if (mAudioVideoConferenceFactoryAddress != nullptr) {
-		char *factory_address = linphone_address_as_string_uri_only(mAudioVideoConferenceFactoryAddress);
+		char *factory_address = mAudioVideoConferenceFactoryAddress->asStringUriOnlyCstr();
 		linphone_config_set_string(config, key, "audio_video_conference_factory_uri", factory_address);
 		ms_free(factory_address);
 	}
diff --git a/src/account/account-params.h b/src/account/account-params.h
index 64a02dd0aa89af20ea7f605cc6c0b704fcf52be9..c036a5911eb5e6022634fd8ab9f8f2f6bf054593 100644
--- a/src/account/account-params.h
+++ b/src/account/account-params.h
@@ -45,6 +45,7 @@ public:
 
 	AccountParams *clone() const override;
 
+	// Setters
 	void setExpires(int expires);
 	void setQualityReportingInterval(int qualityReportingInterval);
 	void setPublishExpires(int publishExpires);
@@ -74,15 +75,16 @@ public:
 	void setAvpfMode(LinphoneAVPFMode avpfMode);
 	void setNatPolicy(const std::shared_ptr<NatPolicy> &natPolicy);
 	void setPushNotificationConfig(PushNotificationConfig *pushNotificationConfig);
-	LinphoneStatus setIdentityAddress(const LinphoneAddress *identityAddress);
-	LinphoneStatus setRoutes(const bctbx_list_t *routes);
+	LinphoneStatus setIdentityAddress(const std::shared_ptr<Address> identityAddress);
+	LinphoneStatus setRoutes(const std::list<std::shared_ptr<Address>> &routes);
 	LinphoneStatus setRoutesFromStringList(const bctbx_list_t *routes);
-	void setAudioVideoConferenceFactoryAddress(const LinphoneAddress *audioVideoConferenceFactoryAddress);
+	void setAudioVideoConferenceFactoryAddress(const std::shared_ptr<Address> audioVideoConferenceFactoryAddress);
 	void enableRtpBundle(bool value);
 	void enableRtpBundleAssumption(bool value);
-	void setCustomContact(const LinphoneAddress *contact);
+	void setCustomContact(const std::shared_ptr<Address> contact);
 	void setLimeServerUrl(const std::string &url);
 
+	// Getters
 	int getExpires() const;
 	int getQualityReportingInterval() const;
 	int getPublishExpires() const;
@@ -110,29 +112,30 @@ public:
 	const std::string &getConferenceFactoryUri() const;
 	const std::string &getFileTransferServer() const;
 	const std::string &getIdentity() const;
-	const char *getDomain() const;
-	const bctbx_list_t *getRoutes() const;
-	const bctbx_list_t *getRoutesString() const;
+	const char *getDomainCstr() const;
+	const std::string getDomain() const;
+	const std::list<std::shared_ptr<Address>> &getRoutes() const;
+	const std::list<std::string> getRoutesString() const;
 	LinphonePrivacyMask getPrivacy() const;
-	LinphoneAddress *getIdentityAddress() const;
+	const std::shared_ptr<Address> &getIdentityAddress() const;
 	LinphoneAVPFMode getAvpfMode() const;
 	std::shared_ptr<NatPolicy> getNatPolicy() const;
 	PushNotificationConfig *getPushNotificationConfig() const;
-	const LinphoneAddress *getAudioVideoConferenceFactoryAddress() const;
+	const std::shared_ptr<Address> &getAudioVideoConferenceFactoryAddress() const;
 	bool rtpBundleEnabled() const;
 	bool rtpBundleAssumptionEnabled() const;
-	const LinphoneAddress *getCustomContact() const;
+	const std::shared_ptr<Address> &getCustomContact() const;
 	const std::string &getLimeServerUrl() const;
 
 	// Other
-	LinphoneStatus setServerAddress(const LinphoneAddress *serverAddr);
-	const LinphoneAddress *getServerAddress() const;
+	LinphoneStatus setServerAddress(const std::shared_ptr<Address> serverAddr);
+	const std::shared_ptr<Address> &getServerAddress() const;
 
 	LinphoneStatus setServerAddressAsString(const std::string &serverAddr);
 	const std::string &getServerAddressAsString() const;
 
-	void setTransport(LinphoneTransportType transport);
-	LinphoneTransportType getTransport() const;
+	void setTransport(LinphonePrivate::Transport transport);
+	LinphonePrivate::Transport getTransport() const;
 
 	void writeToConfigFile(LinphoneConfig *config, int index);
 
@@ -168,16 +171,15 @@ private:
 	std::string mIdKey;
 	std::string mConferenceFactoryUri;
 	std::string mFileTransferServer;
-	std::string mIdentity;
 	std::string mLimeServerUrl;
+	std::string mIdentity;
 
-	bctbx_list_t *mRoutes = nullptr;
-	bctbx_list_t *mRoutesString = nullptr;
+	std::list<std::shared_ptr<Address>> mRoutes;
 
 	LinphonePrivacyMask mPrivacy;
 
-	LinphoneAddress *mIdentityAddress = nullptr;
-	LinphoneAddress *mProxyAddress = nullptr;
+	std::shared_ptr<Address> mIdentityAddress = nullptr;
+	std::shared_ptr<Address> mProxyAddress = nullptr;
 
 	LinphoneAVPFMode mAvpfMode;
 
@@ -185,8 +187,8 @@ private:
 
 	PushNotificationConfig *mPushNotificationConfig;
 
-	LinphoneAddress *mAudioVideoConferenceFactoryAddress = nullptr;
-	LinphoneAddress *mCustomContact = nullptr;
+	std::shared_ptr<Address> mAudioVideoConferenceFactoryAddress = nullptr;
+	std::shared_ptr<Address> mCustomContact = nullptr;
 };
 
 LINPHONE_END_NAMESPACE
diff --git a/src/account/account.cpp b/src/account/account.cpp
index ed6f61064421f8d1eaa6d1bcb00ab3511a78c113..7d1e88b402254cf99e137e6060d82a8b5023e584 100644
--- a/src/account/account.cpp
+++ b/src/account/account.cpp
@@ -20,6 +20,7 @@
 
 #include "account.h"
 
+#include "core/core.h"
 #include "linphone/api/c-account-params.h"
 #include "linphone/api/c-account.h"
 #include "push-notification/push-notification-config.h"
@@ -27,7 +28,7 @@
 #ifdef HAVE_ADVANCED_IM
 #ifdef HAVE_LIME_X3DH
 #include "chat/encryption/lime-x3dh-encryption-engine.h"
-#endif // HAVE_ADVANCED_IM
+#endif // HAVE_LIME_X3DH
 #endif // HAVE_ADVANCED_IM
 #include "c-wrapper/c-wrapper.h"
 #include "c-wrapper/internal/c-tools.h"
@@ -61,13 +62,8 @@ Account::Account(const Account &other) : HybridObject(other) {
 Account::~Account() {
 	bctbx_message("LinphoneAccount[%p] destroyed", toC());
 	if (mSentHeaders) sal_custom_header_free(mSentHeaders);
-	if (mPendingContactAddress) linphone_address_unref(mPendingContactAddress);
 	setDependency(nullptr);
 	if (mErrorInfo) linphone_error_info_unref(mErrorInfo);
-
-	if (mServiceRouteAddress) linphone_address_unref(mServiceRouteAddress);
-	if (mContactAddress) linphone_address_unref(mContactAddress);
-	if (mContactAddressWithoutParams) linphone_address_unref(mContactAddressWithoutParams);
 	if (mPresenceModel) linphone_presence_model_unref(mPresenceModel);
 
 	releaseOps();
@@ -79,47 +75,41 @@ Account *Account::clone() const {
 
 // -----------------------------------------------------------------------------
 
-static char *appendLinphoneAddress(LinphoneAddress *addr, char *out) {
-	char *res = out;
+static std::string appendLinphoneAddress(const std::shared_ptr<Address> &addr, const std::string &out) {
+	auto res = out;
 	if (addr) {
-		char *tmp;
-		tmp = linphone_address_as_string(addr);
-		res = ms_strcat_printf(out, "%s", tmp);
-		ms_free(tmp);
+		res.append(addr->toString());
 	}
 	return res;
 }
 
-static char *appendString(const char *string, char *out) {
-	char *res = out;
-	if (string) {
-		res = ms_strcat_printf(out, "%s", string);
+static std::string appendString(const std::string &string, const std::string &out) {
+	auto res = out;
+	if (!string.empty()) {
+		res.append(string);
 	}
 	return res;
 }
 
 bool Account::computePublishParamsHash() {
-	char *source = NULL;
+	std::string source;
 	char hash[33];
 	char saved;
 	unsigned long long previous_hash[2];
-	bctbx_list_t *routes_iterator = mParams->mRoutes;
 	previous_hash[0] = mPreviousPublishParamsHash[0];
 	previous_hash[1] = mPreviousPublishParamsHash[1];
 
-	source = ms_strcat_printf(source, "%i", mParams->mPrivacy);
+	source.append(std::to_string(static_cast<int>(mParams->mPrivacy)));
 	source = appendLinphoneAddress(mParams->mIdentityAddress, source);
-	source = appendString(mParams->mProxy.c_str(), source);
-	while (routes_iterator) {
-		const char *route = (const char *)bctbx_list_get_data(routes_iterator);
-		source = appendString(route, source);
-		routes_iterator = bctbx_list_next(routes_iterator);
-	}
-	source = appendString(mParams->mRealm.c_str(), source);
-	source = ms_strcat_printf(source, "%i", mParams->mPublishExpires);
-	source = ms_strcat_printf(source, "%i", mParams->mPublishEnabled);
-	belle_sip_auth_helper_compute_ha1(source, "dummy", "dummy", hash);
-	ms_free(source);
+	source = appendString(mParams->mProxy, source);
+	const auto &routes = mParams->mRoutes;
+	for (const auto &route : routes) {
+		source = appendLinphoneAddress(route, source);
+	}
+	source = appendString(mParams->mRealm, source);
+	source.append(std::to_string(mParams->mPublishExpires));
+	source.append(std::to_string(mParams->mPublishEnabled ? 1 : 0));
+	belle_sip_auth_helper_compute_ha1(source.c_str(), "dummy", "dummy", hash);
 	saved = hash[16];
 	hash[16] = '\0';
 	mPreviousPublishParamsHash[0] = strtoull(hash, (char **)NULL, 16);
@@ -128,16 +118,15 @@ bool Account::computePublishParamsHash() {
 	return previous_hash[0] != mPreviousPublishParamsHash[0] || previous_hash[1] != mPreviousPublishParamsHash[1];
 }
 
-LinphoneAccountAddressComparisonResult Account::compareLinphoneAddresses(const LinphoneAddress *a,
-                                                                         const LinphoneAddress *b) {
+LinphoneAccountAddressComparisonResult Account::compareLinphoneAddresses(const std::shared_ptr<Address> &a,
+                                                                         const std::shared_ptr<Address> &b) {
 	if (a == NULL && b == NULL) return LinphoneAccountAddressEqual;
 	else if (!a || !b) return LinphoneAccountAddressDifferent;
 
-	if (linphone_address_equal(a, b)) return LinphoneAccountAddressEqual;
-	if (linphone_address_weak_equal(a, b)) {
+	if (*a == *b) return LinphoneAccountAddressEqual;
+	if (a->weakEqual(*b)) {
 		/*also check both transport and uri */
-		if (linphone_address_get_secure(a) == linphone_address_get_secure(b) &&
-		    linphone_address_get_transport(a) == linphone_address_get_transport(b))
+		if (a->getSecure() == b->getSecure() && a->getTransport() == b->getTransport())
 			return LinphoneAccountAddressWeakEqual;
 		else return LinphoneAccountAddressDifferent;
 	}
@@ -146,9 +135,9 @@ LinphoneAccountAddressComparisonResult Account::compareLinphoneAddresses(const L
 
 LinphoneAccountAddressComparisonResult Account::isServerConfigChanged(std::shared_ptr<AccountParams> oldParams,
                                                                       std::shared_ptr<AccountParams> newParams) {
-	LinphoneAddress *oldProxy =
-	    oldParams != nullptr && !oldParams->mProxy.empty() ? linphone_address_new(oldParams->mProxy.c_str()) : NULL;
-	LinphoneAddress *newProxy = !newParams->mProxy.empty() ? linphone_address_new(newParams->mProxy.c_str()) : NULL;
+	std::shared_ptr<Address> oldProxy =
+	    oldParams != nullptr && !oldParams->mProxy.empty() ? Address::create(oldParams->mProxy) : NULL;
+	std::shared_ptr<Address> newProxy = !newParams->mProxy.empty() ? Address::create(newParams->mProxy) : NULL;
 	LinphoneAccountAddressComparisonResult result_identity;
 	LinphoneAccountAddressComparisonResult result;
 
@@ -159,13 +148,10 @@ LinphoneAccountAddressComparisonResult Account::isServerConfigChanged(std::share
 
 	result = compareLinphoneAddresses(oldProxy, newProxy);
 
-	if (mContactAddress != nullptr) {
-		IdentityAddress addr(*L_GET_CPP_PTR_FROM_C_OBJECT(mContactAddress));
-		if (!addr.getGruu().empty() && result != LinphoneAccountAddressEqual) {
-			// Returning weak equal to be sure no unregister will be done
-			result = LinphoneAccountAddressWeakEqual;
-			goto end;
-		}
+	if (mContactAddress && !mContactAddress->getUriParamValue("gr").empty() && result != LinphoneAccountAddressEqual) {
+		// Returning weak equal to be sure no unregister will be done
+		result = LinphoneAccountAddressWeakEqual;
+		goto end;
 	}
 
 	// This is the legacy mode, if there is no gruu and result is different,
@@ -178,8 +164,6 @@ LinphoneAccountAddressComparisonResult Account::isServerConfigChanged(std::share
 	if (result == LinphoneAccountAddressEqual) result = result_identity;
 
 end:
-	if (oldProxy) linphone_address_unref(oldProxy);
-	if (newProxy) linphone_address_unref(newProxy);
 	lInfo() << "linphoneAccountIsServerConfigChanged : " << result;
 
 	return result;
@@ -214,7 +198,7 @@ bool Account::customContactChanged() {
 	if (mParams->mCustomContact == nullptr && mOldParams->mCustomContact == nullptr) return false;
 	if (mParams->mCustomContact != nullptr && mOldParams->mCustomContact == nullptr) return true;
 	if (mParams->mCustomContact == nullptr && mOldParams->mCustomContact != nullptr) return true;
-	return !linphone_address_equal(mOldParams->mCustomContact, mParams->mCustomContact);
+	return !((*mOldParams->mCustomContact) != (*mParams->mCustomContact));
 }
 
 void Account::applyParamsChanges() {
@@ -229,8 +213,7 @@ void Account::applyParamsChanges() {
 	     (mParams->mAudioVideoConferenceFactoryAddress != nullptr)) ||
 	    ((mOldParams->mAudioVideoConferenceFactoryAddress != nullptr) &&
 	     (mParams->mAudioVideoConferenceFactoryAddress != nullptr) &&
-	     linphone_address_equal(mOldParams->mAudioVideoConferenceFactoryAddress,
-	                            mParams->mAudioVideoConferenceFactoryAddress)))
+	     (*mOldParams->mAudioVideoConferenceFactoryAddress == *mParams->mAudioVideoConferenceFactoryAddress)))
 		onAudioVideoConferenceFactoryAddressChanged(mParams->mAudioVideoConferenceFactoryAddress);
 
 	if (mOldParams == nullptr || mOldParams->mNatPolicy != mParams->mNatPolicy)
@@ -285,48 +268,36 @@ void Account::setErrorInfo(LinphoneErrorInfo *errorInfo) {
 	mErrorInfo = errorInfo;
 }
 
-void Account::setContactAddress(const LinphoneAddress *contact) {
-	if (mContactAddress) {
-		linphone_address_unref(mContactAddress);
-		mContactAddress = nullptr;
-	}
-
-	if (contact) mContactAddress = linphone_address_clone(contact);
-
+void Account::setContactAddress(const std::shared_ptr<Address> contact) {
+	mContactAddress = nullptr;
+	if (contact) mContactAddress = contact->clone()->toSharedPtr();
 	setContactAddressWithoutParams(contact);
 }
 
-void Account::setContactAddressWithoutParams(const LinphoneAddress *contact) {
-	if (mContactAddressWithoutParams) {
-		linphone_address_unref(mContactAddressWithoutParams);
-		mContactAddressWithoutParams = nullptr;
-	}
+void Account::setContactAddressWithoutParams(const std::shared_ptr<Address> contact) {
+	mContactAddressWithoutParams = nullptr;
 
 	if (contact) {
-		mContactAddressWithoutParams = linphone_address_clone(contact);
-		linphone_address_clean(mContactAddressWithoutParams);
-		linphone_address_set_port(mContactAddressWithoutParams, -1);
-		linphone_address_set_domain(mContactAddressWithoutParams, nullptr);
-		linphone_address_set_display_name(mContactAddressWithoutParams, nullptr);
+		mContactAddressWithoutParams = contact->clone()->toSharedPtr();
+		mContactAddressWithoutParams->clean();
+		mContactAddressWithoutParams->setPort(-1);
+		mContactAddressWithoutParams->setDomain(nullptr);
+		mContactAddressWithoutParams->setDisplayName(nullptr);
 	}
 }
 
-void Account::setPendingContactAddress(LinphoneAddress *contact) {
+void Account::setPendingContactAddress(std::shared_ptr<Address> contact) {
 	if (mPendingContactAddress) {
-		linphone_address_unref(mPendingContactAddress);
 		mPendingContactAddress = nullptr;
 	}
 
-	if (contact) mPendingContactAddress = linphone_address_clone(contact);
+	if (contact) mPendingContactAddress = contact;
 }
 
-void Account::setServiceRouteAddress(LinphoneAddress *serviceRoute) {
-	if (mServiceRouteAddress) {
-		linphone_address_unref(mServiceRouteAddress);
-		mServiceRouteAddress = nullptr;
-	}
+void Account::setServiceRouteAddress(std::shared_ptr<Address> serviceRoute) {
+	mServiceRouteAddress = nullptr;
 
-	if (serviceRoute) mServiceRouteAddress = linphone_address_clone(serviceRoute);
+	if (serviceRoute) mServiceRouteAddress = serviceRoute->clone()->toSharedPtr();
 }
 
 // Enable register on account dependent on the given one (if any).
@@ -354,13 +325,11 @@ void Account::updateDependentAccount(LinphoneRegistrationState state, const std:
 				copyParams->mRegisterEnabled = true;
 				const SalAddress *salAddr = mOp->getContactAddress();
 
+				if (!mContactAddress) {
+					mContactAddress = Address::create();
+				}
 				if (salAddr) {
-					if (mContactAddress) {
-						linphone_address_unref(mContactAddress);
-					}
-					char *sal_addr = sal_address_as_string(salAddr);
-					mContactAddress = linphone_address_new(sal_addr);
-					bctbx_free(sal_addr);
+					mContactAddress->setImpl(salAddr);
 				}
 			} else if (state == LinphoneRegistrationCleared || state == LinphoneRegistrationFailed) {
 				tmpCpp->pauseRegister();
@@ -375,15 +344,15 @@ void Account::updateDependentAccount(LinphoneRegistrationState state, const std:
 void Account::setState(LinphoneRegistrationState state, const std::string &message) {
 	if (mState != state ||
 	    state == LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/
-		const char *identity = mParams ? mParams->mIdentity.c_str() : "";
+		const auto identity = (mParams) ? mParams->getIdentity().c_str() : std::string();
 		if (!mParams) lWarning() << "AccountParams not set for Account [" << this->toC() << "]";
 		lInfo() << "Account [" << this << "] for identity [" << identity << "] moving from state ["
 		        << linphone_registration_state_to_string(mState) << "] to ["
 		        << linphone_registration_state_to_string(state) << "] on core [" << mCore << "]";
 
 		if (state == LinphoneRegistrationOk) {
-			const auto salAddr = ownership::borrowed(mOp->getContactAddress());
-			if (salAddr) L_GET_CPP_PTR_FROM_C_OBJECT(mContactAddress)->setInternalAddress(salAddr);
+			const auto salAddr = mOp->getContactAddress();
+			if (salAddr) mContactAddress->setImpl(salAddr);
 			mOldParams = nullptr; // We can drop oldParams, since last registration was successful.
 		}
 
@@ -465,31 +434,28 @@ const LinphoneErrorInfo *Account::getErrorInfo() {
 	return mErrorInfo;
 }
 
-const LinphoneAddress *Account::getContactAddress() const {
+const std::shared_ptr<Address> &Account::getContactAddress() const {
 	return mContactAddress;
 }
 
-const LinphoneAddress *Account::getContactAddressWithoutParams() const {
+const std::shared_ptr<Address> &Account::getContactAddressWithoutParams() const {
 	return mContactAddressWithoutParams;
 }
 
-const LinphoneAddress *Account::getPendingContactAddress() const {
+const std::shared_ptr<Address> &Account::getPendingContactAddress() const {
 	return mPendingContactAddress;
 }
 
-const LinphoneAddress *Account::getServiceRouteAddress() {
+const std::shared_ptr<Address> Account::getServiceRouteAddress() const {
 	if (!mOp) return nullptr;
 
-	const auto salAddr = ownership::borrowed(mOp->getServiceRoute());
+	const auto salAddr = mOp->getServiceRoute();
 	if (!salAddr) return nullptr;
 
-	if (mServiceRouteAddress) {
-		L_GET_CPP_PTR_FROM_C_OBJECT(mServiceRouteAddress)->setInternalAddress(salAddr);
-	} else {
-		char *buf = sal_address_as_string(salAddr);
-		mServiceRouteAddress = linphone_address_new(buf);
-		ms_free(buf);
+	if (!mServiceRouteAddress) {
+		mServiceRouteAddress = Address::create();
 	}
+	mServiceRouteAddress->setImpl(salAddr);
 
 	return mServiceRouteAddress;
 }
@@ -518,21 +484,21 @@ std::shared_ptr<Account> Account::getDependency() {
 
 // -----------------------------------------------------------------------------
 
-LinphoneAddress *Account::guessContactForRegister() {
-	LinphoneAddress *result = nullptr;
+std::shared_ptr<Address> Account::guessContactForRegister() {
+	std::shared_ptr<Address> result = nullptr;
 
 	if (mDependency) {
 		// In case of dependent account, force contact of 'master' account, but only after a successful register
-		return linphone_address_clone(mDependency->mContactAddress);
+		return mDependency->mContactAddress;
 	}
-	LinphoneAddress *proxy = linphone_address_new(mParams->mProxy.c_str());
+	std::shared_ptr<Address> proxy = Address::create(mParams->mProxy);
 	if (!proxy) return nullptr;
-	const char *host = linphone_address_get_domain(proxy);
-	if (host) {
-		result = linphone_address_clone(mParams->mIdentityAddress);
+	const auto host = proxy->getDomain();
+	if (!host.empty()) {
+		result = mParams->mIdentityAddress->clone()->toSharedPtr();
 		if (!mParams->mContactParameters.empty()) {
 			// We want to add a list of contacts params to the linphone address
-			linphone_address_set_params(result, mParams->mContactParameters.c_str());
+			result->setParams(mParams->mContactParameters);
 		}
 
 		bool successfullyPreparedPushParameters = false;
@@ -559,12 +525,13 @@ LinphoneAddress *Account::guessContactForRegister() {
 		if (!newParams->mContactUriParameters.empty()) {
 			if (successfullyPreparedPushParameters) {
 				// build an Address to make use of useful param management functions
-				Address contactParamsWrapper(string("sip:dummy;" + newParams->mContactUriParameters));
+				std::shared_ptr<Address> contactParamsWrapper =
+				    Address::create(string("sip:dummy;" + newParams->mContactUriParameters));
 				bool didRemoveParams = false;
 				for (auto pushParam : newParams->mPushNotificationConfig->getPushParamsMap()) {
 					string paramName = pushParam.first;
-					if (!contactParamsWrapper.getUriParamValue(paramName).empty()) {
-						contactParamsWrapper.removeUriParam(paramName);
+					if (!contactParamsWrapper->getUriParamValue(paramName).empty()) {
+						contactParamsWrapper->removeUriParam(paramName);
 						didRemoveParams = true;
 						lError() << "Removing '" << paramName << "' from account [" << this
 						         << "] contact uri parameters because it will be generated automatically since core "
@@ -574,54 +541,37 @@ LinphoneAddress *Account::guessContactForRegister() {
 
 				if (didRemoveParams) {
 					string newContactUriParams;
-					bctbx_map_t *uriParamMap = contactParamsWrapper.getUriParams();
-					bctbx_iterator_t *uriParamMapEnd = bctbx_map_cchar_end(uriParamMap);
-					bctbx_iterator_t *it = bctbx_map_cchar_begin(uriParamMap);
-					for (; !bctbx_iterator_cchar_equals(it, uriParamMapEnd); it = bctbx_iterator_cchar_get_next(it)) {
-						bctbx_pair_t *pair = bctbx_iterator_cchar_get_pair(it);
-						const char *key = bctbx_pair_cchar_get_first(reinterpret_cast<bctbx_pair_cchar_t *>(pair));
-						const char *value = (const char *)bctbx_pair_cchar_get_second(pair);
-						if (value) {
-							newContactUriParams = newContactUriParams + key + "=" + value + ";";
+					const auto &uriParamMap = contactParamsWrapper->getUriParams();
+					for (const auto &param : uriParamMap) {
+						if (!param.second.empty()) {
+							newContactUriParams = newContactUriParams + param.first + "=" + param.second + ";";
 						}
 					}
-					bctbx_iterator_cchar_delete(it);
-					bctbx_iterator_cchar_delete(uriParamMapEnd);
-					bctbx_mmap_cchar_delete_with_data(uriParamMap, bctbx_free);
 
 					lWarning() << "Account [" << this << "] contact uri parameters changed from '"
 					           << newParams->mContactUriParameters << "' to '" << newContactUriParams << "'";
 					newParams->mContactUriParameters = newContactUriParams;
 				}
 			}
-			linphone_address_set_uri_params(result, newParams->mContactUriParameters.c_str());
+			result->setUriParams(newParams->mContactUriParameters);
 		}
 
 		if (successfullyPreparedPushParameters) {
-			linphone_address_set_uri_param(result, PushConfigPridKey.c_str(),
-			                               newParams->getPushNotificationConfig()->getPrid().c_str());
-			linphone_address_set_uri_param(result, PushConfigProviderKey.c_str(),
-			                               newParams->getPushNotificationConfig()->getProvider().c_str());
-			linphone_address_set_uri_param(result, PushConfigParamKey.c_str(),
-			                               newParams->getPushNotificationConfig()->getParam().c_str());
+			result->setUriParam(PushConfigPridKey, newParams->getPushNotificationConfig()->getPrid());
+			result->setUriParam(PushConfigProviderKey, newParams->getPushNotificationConfig()->getProvider());
+			result->setUriParam(PushConfigParamKey, newParams->getPushNotificationConfig()->getParam());
 
 			auto &pushParams = newParams->getPushNotificationConfig()->getPushParamsMap();
-			linphone_address_set_uri_param(result, PushConfigSilentKey.c_str(),
-			                               pushParams.at(PushConfigSilentKey).c_str());
-			linphone_address_set_uri_param(result, PushConfigTimeoutKey.c_str(),
-			                               pushParams.at(PushConfigTimeoutKey).c_str());
+			result->setUriParam(PushConfigSilentKey, pushParams.at(PushConfigSilentKey));
+			result->setUriParam(PushConfigTimeoutKey, pushParams.at(PushConfigTimeoutKey));
 
 			if (mParams->mRemotePushNotificationAllowed) {
-				linphone_address_set_uri_param(result, PushConfigMsgStrKey.c_str(),
-				                               newParams->getPushNotificationConfig()->getMsgStr().c_str());
-				linphone_address_set_uri_param(result, PushConfigCallStrKey.c_str(),
-				                               newParams->getPushNotificationConfig()->getCallStr().c_str());
-				linphone_address_set_uri_param(result, PushConfigGroupChatStrKey.c_str(),
-				                               newParams->getPushNotificationConfig()->getGroupChatStr().c_str());
-				linphone_address_set_uri_param(result, PushConfigCallSoundKey.c_str(),
-				                               newParams->getPushNotificationConfig()->getCallSnd().c_str());
-				linphone_address_set_uri_param(result, PushConfigMsgSoundKey.c_str(),
-				                               newParams->getPushNotificationConfig()->getMsgSnd().c_str());
+				result->setUriParam(PushConfigMsgStrKey, newParams->getPushNotificationConfig()->getMsgStr());
+				result->setUriParam(PushConfigCallStrKey, newParams->getPushNotificationConfig()->getCallStr());
+				result->setUriParam(PushConfigGroupChatStrKey,
+				                    newParams->getPushNotificationConfig()->getGroupChatStr());
+				result->setUriParam(PushConfigCallSoundKey, newParams->getPushNotificationConfig()->getCallSnd());
+				result->setUriParam(PushConfigMsgSoundKey, newParams->getPushNotificationConfig()->getMsgSnd());
 			}
 			lInfo() << "Added push notification informations '"
 			        << newParams->getPushNotificationConfig()->asString(mParams->mRemotePushNotificationAllowed)
@@ -629,28 +579,24 @@ LinphoneAddress *Account::guessContactForRegister() {
 			setAccountParams(newParams);
 		}
 	}
-	linphone_address_unref(proxy);
 	return result;
 }
 
 std::list<SalAddress *> Account::getOtherContacts() {
 	std::list<SalAddress *> ret;
 	if (mPendingContactAddress) {
-		SalAddress *toRemove =
-		    sal_address_clone(L_GET_CPP_PTR_FROM_C_OBJECT(mPendingContactAddress)->getInternalAddress());
+		SalAddress *toRemove = sal_address_clone(mPendingContactAddress->getImpl());
 		sal_address_set_params(toRemove, "expires=0");
 		ret.push_back(toRemove);
 	}
 	if (mParams->mCustomContact) {
-		SalAddress *toAdd =
-		    sal_address_clone(L_GET_CPP_PTR_FROM_C_OBJECT(mParams->mCustomContact)->getInternalAddress());
+		SalAddress *toAdd = sal_address_clone(mParams->mCustomContact->getImpl());
 		ret.push_back(toAdd);
 	}
 	if (mOldParams && mOldParams->mCustomContact) {
-		if (!mParams->mCustomContact || !linphone_address_equal(mOldParams->mCustomContact, mParams->mCustomContact)) {
+		if (!mParams->mCustomContact || (*mOldParams->mCustomContact != *mParams->mCustomContact)) {
 			/* need to remove previously used custom contact */
-			SalAddress *toRemove =
-			    sal_address_clone(L_GET_CPP_PTR_FROM_C_OBJECT(mOldParams->mCustomContact)->getInternalAddress());
+			SalAddress *toRemove = sal_address_clone(mOldParams->mCustomContact->getImpl());
 			sal_address_set_params(toRemove, "expires=0");
 			ret.push_back(toRemove);
 		}
@@ -661,7 +607,7 @@ std::list<SalAddress *> Account::getOtherContacts() {
 void Account::registerAccount() {
 	if (mParams->mRegisterEnabled) {
 
-		LinphoneAddress *proxy = linphone_address_new(mParams->mProxy.c_str());
+		std::shared_ptr<Address> proxy = Address::create(mParams->mProxy);
 		if (proxy == nullptr) {
 			lError() << "Can't register LinphoneAccount [" << this << "] without a proxy";
 			return;
@@ -669,35 +615,32 @@ void Account::registerAccount() {
 
 		lInfo() << "LinphoneAccount [" << this
 		        << "] about to register (LinphoneCore version: " << linphone_core_get_version() << ")";
-		char *proxy_string = linphone_address_as_string_uri_only(proxy);
-		linphone_address_unref(proxy);
+		auto proxy_string = proxy->asStringUriOnly();
 
 		if (mOp) mOp->release();
 		mOp = new SalRegisterOp(mCore->sal.get());
 
-		linphone_configure_op(mCore, mOp, mParams->mIdentityAddress, mSentHeaders, FALSE);
+		linphone_configure_op(mCore, mOp, mParams->mIdentityAddress->toC(), mSentHeaders, FALSE);
 
-		LinphoneAddress *contactAddress = guessContactForRegister();
+		std::shared_ptr<Address> contactAddress = guessContactForRegister();
 		if (contactAddress) {
-			mOp->setContactAddress(L_GET_CPP_PTR_FROM_C_OBJECT(contactAddress)->getInternalAddress());
+			mOp->setContactAddress(contactAddress->getImpl());
 			if (!mContactAddress) {
-				mContactAddress = linphone_address_clone(contactAddress);
+				mContactAddress = contactAddress->clone()->toSharedPtr();
 			}
-			linphone_address_unref(contactAddress);
 		}
 		mOp->setUserPointer(this->toC());
 
 		auto otherContacts = getOtherContacts();
-		if (mOp->sendRegister(proxy_string, mParams->mIdentity, mParams->mExpires, otherContacts) == 0) {
+		const auto identity = (mParams) ? mParams->getIdentity() : std::string();
+		if (mOp->sendRegister(proxy_string.c_str(), identity, mParams->mExpires, otherContacts) == 0) {
 			if (mPendingContactAddress) {
-				linphone_address_unref(mPendingContactAddress);
 				mPendingContactAddress = nullptr;
 			}
 			setState(LinphoneRegistrationProgress, "Registration in progress");
 		} else {
 			setState(LinphoneRegistrationFailed, "Registration failed");
 		}
-		if (proxy_string != nullptr) ms_free(proxy_string);
 		for (auto ct : otherContacts)
 			sal_address_unref(ct);
 	} else {
@@ -770,22 +713,19 @@ void Account::notifyPublishStateChanged(LinphonePublishState state) {
 }
 
 void Account::stopRefreshing() {
-	LinphoneAddress *contact_addr = nullptr;
+	std::shared_ptr<Address> contact_addr = nullptr;
 	const SalAddress *sal_addr = mOp && mState == LinphoneRegistrationOk ? mOp->getContactAddress() : nullptr;
 	if (sal_addr) {
 		char *buf = sal_address_as_string(sal_addr);
-		contact_addr = buf ? linphone_address_new(buf) : nullptr;
+		contact_addr = buf ? Address::create(buf) : nullptr;
 		ms_free(buf);
 	}
 
 	/*with udp, there is a risk of port reuse, so I prefer to not do anything for now*/
 	if (contact_addr) {
-		if (linphone_address_get_transport(contact_addr) != LinphoneTransportUdp &&
+		if (contact_addr->getTransport() != LinphonePrivate::Transport::Udp &&
 		    linphone_config_get_int(mCore->config, "sip", "unregister_previous_contact", 0)) {
-			if (mPendingContactAddress) linphone_address_unref(mPendingContactAddress);
 			mPendingContactAddress = contact_addr;
-		} else {
-			linphone_address_unref(contact_addr);
 		}
 	}
 
@@ -827,31 +767,19 @@ LinphoneTransportType Account::getTransport() {
 	std::string addr;
 	LinphoneTransportType ret = LinphoneTransportUdp; /*default value*/
 	const SalAddress *route_addr = nullptr;
-	bool destroy_route_addr = false;
-
 	if (getServiceRouteAddress()) {
-		route_addr = L_GET_CPP_PTR_FROM_C_OBJECT(getServiceRouteAddress())->getInternalAddress();
-	} else if (mParams && mParams->getRoutes()) {
+		route_addr = getServiceRouteAddress()->getImpl();
+	} else if (mParams && !mParams->getRoutes().empty()) {
 		// get first route
-		char *tmp = linphone_address_as_string((LinphoneAddress *)bctbx_list_get_data(mParams->getRoutes()));
-		addr = tmp;
-		bctbx_free(tmp);
+		route_addr = mParams->getRoutes().front()->getImpl();
 	} else if (mParams && !mParams->getServerAddressAsString().empty()) {
-		addr = mParams->getServerAddressAsString();
+		route_addr = mParams->getServerAddress()->getImpl();
 	} else {
 		lError() << "Cannot guess transport for account with identity [" << this->toC() << "]";
 		return ret;
 	}
-
-	if (!route_addr) {
-		if (!((*(SalAddress **)&route_addr) = sal_address_new(addr.c_str()))) return ret;
-		destroy_route_addr = true;
-	}
-
 	ret = salTransportToLinphoneTransport(sal_address_get_transport(route_addr));
 
-	if (destroy_route_addr) sal_address_unref((SalAddress *)route_addr);
-
 	return ret;
 }
 
@@ -874,9 +802,9 @@ const LinphoneAuthInfo *Account::findAuthInfo() const {
 		return nullptr;
 	}
 
-	const char *username = mParams->mIdentityAddress ? linphone_address_get_username(mParams->mIdentityAddress) : NULL;
-	const char *domain = mParams->mIdentityAddress ? linphone_address_get_domain(mParams->mIdentityAddress) : NULL;
-	return linphone_core_find_auth_info(mCore, mParams->mRealm.c_str(), username, domain);
+	const std::string username = mParams->mIdentityAddress ? mParams->mIdentityAddress->getUsername() : std::string();
+	const std::string domain = mParams->mIdentityAddress ? mParams->mIdentityAddress->getDomain() : std::string();
+	return linphone_core_find_auth_info(mCore, mParams->mRealm.c_str(), username.c_str(), domain.c_str());
 }
 
 int Account::getUnreadChatMessageCount() const {
@@ -885,8 +813,7 @@ int Account::getUnreadChatMessageCount() const {
 		return -1;
 	}
 
-	return L_GET_CPP_PTR_FROM_C_OBJECT(mCore)->getUnreadChatMessageCount(
-	    LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(mParams->mIdentityAddress)));
+	return L_GET_CPP_PTR_FROM_C_OBJECT(mCore)->getUnreadChatMessageCount(mParams->mIdentityAddress);
 }
 
 void Account::writeToConfigFile(int index) {
@@ -1002,13 +929,14 @@ void Account::apply(LinphoneCore *lc) {
 	done();
 }
 
-shared_ptr<EventPublish> Account::createPublish(const char *event, int expires) {
+shared_ptr<EventPublish> Account::createPublish(const std::string event, int expires) {
 	if (!mCore) {
 		lError() << "Cannot create publish from account [" << this->toC() << "] not attached to any core";
 		return nullptr;
 	}
 	return dynamic_pointer_cast<EventPublish>(
-	    Event::toCpp(_linphone_core_create_publish(mCore, this->toC(), NULL, event, expires))->getSharedFromThis());
+	    (new EventPublish(L_GET_CPP_PTR_FROM_C_OBJECT(mCore), getSharedFromThis(), NULL, event, expires))
+	        ->getSharedFromThis());
 }
 
 void Account::setPresenceModel(LinphonePresenceModel *presence) {
@@ -1049,7 +977,8 @@ int Account::sendPublish() {
 			// when PUBLISH is about to expire, so we can update the presence model timestamp
 			mPresencePublishEvent->setManualRefresherMode(true);
 		}
-		mPresencePublishEvent->setUserData(mParams->getIdentityAddress());
+		const auto &identityAddress = mParams->getIdentityAddress();
+		mPresencePublishEvent->setUserData(identityAddress->toC());
 
 		LinphoneConfig *config = linphone_core_get_config(mCore);
 		if (linphone_config_get_bool(config, "sip", "update_presence_model_timestamp_before_publish_expires_refresh",
@@ -1064,22 +993,21 @@ int Account::sendPublish() {
 
 		if (linphone_presence_model_get_presentity(mPresenceModel) == NULL) {
 			lInfo() << "No presentity set for model [" << mPresenceModel << "], using identity from account ["
-			        << this->toC() << "]";
-			linphone_presence_model_set_presentity(mPresenceModel, mParams->getIdentityAddress());
+			        << this->toC() << "]: " << *identityAddress;
+			linphone_presence_model_set_presentity(mPresenceModel, identityAddress->toC());
 		}
 
-		LinphoneAddress *presentity_address = NULL;
+		const auto currentPresentity = linphone_presence_model_get_presentity(mPresenceModel);
+		std::shared_ptr<const Address> presentityAddress = nullptr;
 		char *contact = NULL;
-		if (!linphone_address_equal(linphone_presence_model_get_presentity(mPresenceModel),
-		                            mParams->getIdentityAddress())) {
-			lInfo() << "Presentity for model [" << mPresenceModel << "] differ account [" << this->toC()
-			        << "], using account";
-			presentity_address =
-			    linphone_address_clone(linphone_presence_model_get_presentity(mPresenceModel)); /*saved, just in case*/
+		if (!linphone_address_equal(currentPresentity, identityAddress->toC())) {
+			lInfo() << "Presentity for model [" << mPresenceModel << "] differs account [" << this->toC()
+			        << "], using account " << *identityAddress;
+			presentityAddress = Address::toCpp(currentPresentity)->getSharedFromThis(); /*saved, just in case*/
 			if (linphone_presence_model_get_contact(mPresenceModel)) {
 				contact = bctbx_strdup(linphone_presence_model_get_contact(mPresenceModel));
 			}
-			linphone_presence_model_set_presentity(mPresenceModel, mParams->getIdentityAddress());
+			linphone_presence_model_set_presentity(mPresenceModel, identityAddress->toC());
 			linphone_presence_model_set_contact(mPresenceModel, NULL); /*it will be automatically computed*/
 		}
 
@@ -1104,9 +1032,11 @@ int Account::sendPublish() {
 		linphone_content_unref(content);
 		ms_free(presence_body);
 
-		if (presentity_address) {
-			linphone_presence_model_set_presentity(mPresenceModel, presentity_address);
-			linphone_address_unref(presentity_address);
+		if (presentityAddress) {
+			lInfo() << "Restoring previous presentity address " << *presentityAddress << " for model ["
+			        << mPresenceModel << "]";
+
+			linphone_presence_model_set_presentity(mPresenceModel, presentityAddress->toC());
 		}
 		if (contact) {
 			linphone_presence_model_set_contact(mPresenceModel, contact);
@@ -1237,7 +1167,8 @@ void Account::onConferenceFactoryUriChanged(const std::string &conferenceFactory
 	}
 }
 
-void Account::onAudioVideoConferenceFactoryAddressChanged(const LinphoneAddress *audioVideoConferenceFactoryAddress) {
+void Account::onAudioVideoConferenceFactoryAddressChanged(
+    const std::shared_ptr<Address> &audioVideoConferenceFactoryAddress) {
 	std::string conferenceSpec("conference/");
 	conferenceSpec.append(Core::conferenceVersionAsString());
 
diff --git a/src/account/account.h b/src/account/account.h
index b70ac211487a81267c11a97fa5c5702694dc22b3..e43d381fad6ab465c679a1ea1dc093e16f75f416 100644
--- a/src/account/account.h
+++ b/src/account/account.h
@@ -66,10 +66,10 @@ public:
 	void setSipEtag(const std::string &sipEtag);
 	void setCore(LinphoneCore *lc);
 	void setErrorInfo(LinphoneErrorInfo *errorInfo);
-	void setContactAddress(const LinphoneAddress *contact);
-	void setContactAddressWithoutParams(const LinphoneAddress *contact);
-	void setPendingContactAddress(LinphoneAddress *contact);
-	void setServiceRouteAddress(LinphoneAddress *serviceRoute);
+	void setContactAddress(const std::shared_ptr<Address> contact);
+	void setContactAddressWithoutParams(const std::shared_ptr<Address> contact);
+	void setPendingContactAddress(std::shared_ptr<Address> contact);
+	void setServiceRouteAddress(std::shared_ptr<Address> serviceRoute);
 	void setState(LinphoneRegistrationState state, const std::string &message);
 	void setOp(SalRegisterOp *op);
 	void setCustomheader(const std::string &headerName, const std::string &headerValue);
@@ -83,10 +83,10 @@ public:
 	const std::string &getSipEtag() const;
 	LinphoneCore *getCore() const;
 	const LinphoneErrorInfo *getErrorInfo();
-	const LinphoneAddress *getContactAddress() const;
-	const LinphoneAddress *getContactAddressWithoutParams() const;
-	const LinphoneAddress *getPendingContactAddress() const;
-	const LinphoneAddress *getServiceRouteAddress();
+	const std::shared_ptr<Address> &getContactAddress() const;
+	const std::shared_ptr<Address> &getContactAddressWithoutParams() const;
+	const std::shared_ptr<Address> &getPendingContactAddress() const;
+	const std::shared_ptr<Address> getServiceRouteAddress() const;
 	LinphoneRegistrationState getState() const;
 	SalRegisterOp *getOp() const;
 	const char *getCustomHeader(const std::string &headerName) const;
@@ -113,15 +113,15 @@ public:
 	const std::string &getCustomParam(const std::string &key) const;
 	void writeToConfigFile(int index);
 	const LinphoneAuthInfo *findAuthInfo() const;
-	std::shared_ptr<EventPublish> createPublish(const char *event, int expires);
+	std::shared_ptr<EventPublish> createPublish(const std::string event, int expires);
 	LinphoneReason getError();
 	LinphoneTransportType getTransport();
 
 	// Callbacks
 
 	// Utils
-	static LinphoneAccountAddressComparisonResult compareLinphoneAddresses(const LinphoneAddress *a,
-	                                                                       const LinphoneAddress *b);
+	static LinphoneAccountAddressComparisonResult compareLinphoneAddresses(const std::shared_ptr<Address> &a,
+	                                                                       const std::shared_ptr<Address> &b);
 
 	// To be removed when not using proxy config anymore
 	LinphoneProxyConfig *getConfig() const;
@@ -137,11 +137,12 @@ private:
 	void updateDependentAccount(LinphoneRegistrationState state, const std::string &message);
 	LinphoneAccountAddressComparisonResult isServerConfigChanged(std::shared_ptr<AccountParams> oldParams,
 	                                                             std::shared_ptr<AccountParams> newParams);
-	LinphoneAddress *guessContactForRegister();
+	std::shared_ptr<Address> guessContactForRegister();
 
 	void onInternationalPrefixChanged();
 	void onConferenceFactoryUriChanged(const std::string &conferenceFactoryUri);
-	void onAudioVideoConferenceFactoryAddressChanged(const LinphoneAddress *audioVideoConferenceFactoryAddress);
+	void
+	onAudioVideoConferenceFactoryAddressChanged(const std::shared_ptr<Address> &audioVideoConferenceFactoryAddress);
 	void onNatPolicyChanged(const std::shared_ptr<NatPolicy> &policy);
 	void onLimeServerUrlChanged(const std::string &limeServerUrl);
 	bool customContactChanged();
@@ -163,10 +164,10 @@ private:
 
 	LinphoneErrorInfo *mErrorInfo = nullptr;
 
-	LinphoneAddress *mContactAddress = nullptr;
-	LinphoneAddress *mContactAddressWithoutParams = nullptr;
-	LinphoneAddress *mPendingContactAddress = nullptr;
-	LinphoneAddress *mServiceRouteAddress = nullptr;
+	std::shared_ptr<Address> mContactAddress = nullptr;
+	std::shared_ptr<Address> mContactAddressWithoutParams = nullptr;
+	std::shared_ptr<Address> mPendingContactAddress = nullptr;
+	mutable std::shared_ptr<Address> mServiceRouteAddress = nullptr;
 
 	LinphoneRegistrationState mState = LinphoneRegistrationNone;
 
@@ -198,4 +199,4 @@ private:
 
 LINPHONE_END_NAMESPACE
 
-#endif // ifndef _L_ACCOUNT_H_
\ No newline at end of file
+#endif // ifndef _L_ACCOUNT_H_
diff --git a/src/address/address-parser.cpp b/src/address/address-parser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2fc36fabdbe30d470ae78a677caf2a8e11c67344
--- /dev/null
+++ b/src/address/address-parser.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010-2022 Belledonne Communications SARL.
+ *
+ * This file is part of Liblinphone
+ * (see https://gitlab.linphone.org/BC/public/liblinphone).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "linphone/utils/utils.h"
+
+#include "logger/logger.h"
+
+#include "address-parser.h"
+
+// =============================================================================
+
+using namespace std;
+
+LINPHONE_BEGIN_NAMESPACE
+
+static void sal_address_ext_set_scheme(SalAddress *addr, const std::string &scheme) {
+	if (scheme == "sips") sal_address_set_secure(addr, TRUE);
+}
+
+static void sal_address_ext_set_gr(SalAddress *addr, const char *value) {
+	sal_address_set_uri_param(addr, "gr", value);
+}
+
+static void sal_address_ext_set_username_escaped(SalAddress *addr, const char *value) {
+	/* In the SalAddress (aka belle_sip_header_address_t), the user name is stored "unescaped".
+	 * Our fast Address parser gives us escaped strings, so we have to convert*/
+	char *tmp = belle_sip_to_unescaped_string(value);
+	sal_address_set_username(addr, tmp);
+	belle_sip_free(tmp);
+}
+
+unique_ptr<AddressParser> AddressParser::sInstance;
+
+AddressParser &AddressParser::get() {
+	if (!sInstance) sInstance.reset(new AddressParser());
+	return *sInstance.get();
+}
+
+AddressParser::AddressParser() {
+
+	shared_ptr<belr::Grammar> grammar = belr::GrammarLoader::get().load(IdentityGrammar);
+	if (!grammar) lFatal() << "Unable to load Identity Address grammar.";
+	mParser = make_shared<belr::Parser<void *>>(grammar);
+
+	mParser->setHandler("address", belr::make_fn(&sal_address_new_empty))
+	    ->setCollector("scheme", belr::make_fn(&sal_address_ext_set_scheme))
+	    ->setCollector("user", belr::make_fn(&sal_address_ext_set_username_escaped))
+	    ->setCollector("host", belr::make_fn(&sal_address_set_domain))
+	    ->setCollector("gruu-value", belr::make_fn(&sal_address_ext_set_gr));
+}
+
+// -----------------------------------------------------------------------------
+
+SalAddress *AddressParser::parseAddress(const string &input) {
+	size_t parsedSize;
+	SalAddress *identityAddress = (SalAddress *)mParser->parseInput("address", input, &parsedSize);
+	if (!identityAddress) {
+		lDebug() << "Unable to parse identity address from " << input;
+		return nullptr;
+	}
+	return identityAddress;
+}
+
+LINPHONE_END_NAMESPACE
diff --git a/src/address/identity-address-parser.h b/src/address/address-parser.h
similarity index 67%
rename from src/address/identity-address-parser.h
rename to src/address/address-parser.h
index dab1a7ead97bf31001c81a210426e27bf8a8ab97..0aea7a013987326f3feb3b64258cdaaf853bcb23 100644
--- a/src/address/identity-address-parser.h
+++ b/src/address/address-parser.h
@@ -21,26 +21,31 @@
 #ifndef _L_IDENTITY_ADDRESS_PARSER_H_
 #define _L_IDENTITY_ADDRESS_PARSER_H_
 
-#include "identity-address.h"
-#include "object/singleton.h"
+#include "belr/abnf.h"
+#include "belr/belr.h"
+#include "belr/grammarbuilder.h"
+
+#include "c-wrapper/internal/c-sal.h"
 
 // =============================================================================
 
 LINPHONE_BEGIN_NAMESPACE
 
-class IdentityAddressParserPrivate;
-
-class IdentityAddressParser : public Singleton<IdentityAddressParser> {
-	friend class Singleton<IdentityAddressParser>;
+/**
+ * The AddressParser is designed to efficiently parse
+ * simple SIP uris whith only scheme, user, host, and gr parameter.
+ */
+class AddressParser {
 
 public:
-	std::shared_ptr<IdentityAddress> parseAddress(const std::string &input);
+	SalAddress *parseAddress(const std::string &input);
+	static AddressParser &get();
 
 private:
-	IdentityAddressParser();
-
-	L_DECLARE_PRIVATE(IdentityAddressParser);
-	L_DISABLE_COPY(IdentityAddressParser);
+	AddressParser();
+	std::shared_ptr<belr::Parser<void *>> mParser;
+	static std::unique_ptr<AddressParser> sInstance;
+	static constexpr const char *IdentityGrammar = "identity_grammar";
 };
 
 LINPHONE_END_NAMESPACE
diff --git a/src/address/address.cpp b/src/address/address.cpp
index c8676ad15e930461e8c009232c35cac4356c4d03..49c12f0c132478e9f87b15e629d0768fbb63bf58 100644
--- a/src/address/address.cpp
+++ b/src/address/address.cpp
@@ -18,97 +18,82 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <belle-sip/sip-uri.h>
+#include <bctoolbox/defs.h>
+
+#include "belle-sip/sip-uri.h"
 
 #include "address.h"
 #include "c-wrapper/c-wrapper.h"
-#include "containers/lru-cache.h"
 #include "logger/logger.h"
 
-// TODO: delete after Addres is not derived anymore from ClonableObject
-#include "object/clonable-object-p.h"
-
 // =============================================================================
 
 using namespace std;
-using namespace ownership;
 
 LINPHONE_BEGIN_NAMESPACE
 
-namespace {
-class SalAddressWrap {
-public:
-	explicit SalAddressWrap(SalAddress *salAddress = nullptr) : mSalAddress(salAddress) {
-	}
+std::unordered_map<std::string, std::unique_ptr<SalAddress, Address::SalAddressDeleter>> Address::sAddressCache;
 
-	SalAddressWrap(const SalAddressWrap &other) : mSalAddress(other.mSalAddress) {
-		if (mSalAddress) sal_address_ref(mSalAddress);
-	}
+SalAddress *Address::getSalAddressFromCache(const string &uri,
+                                            std::function<SalAddress *(const std::string &)> alternateParserFunction) {
+	auto &ptr = sAddressCache[uri];
+	if (ptr) return sal_address_clone(ptr.get());
 
-	SalAddressWrap(SalAddressWrap &&other) : mSalAddress(other.mSalAddress) {
-		other.mSalAddress = nullptr;
-	}
-
-	~SalAddressWrap() {
-		if (mSalAddress) sal_address_unref(mSalAddress);
-	}
-
-	const SalAddress *get() {
-		return mSalAddress;
-	}
-
-private:
-	SalAddress *mSalAddress;
-};
-LruCache<string, SalAddressWrap> addressesCache;
-} // namespace
-
-static Owned<SalAddress> getSalAddressFromCache(const string &uri) {
-	SalAddressWrap *wrap = addressesCache[uri];
-	if (wrap) return owned(sal_address_clone(wrap->get()));
-
-	SalAddress *address = sal_address_new(L_STRING_TO_C(uri));
+	// lInfo() << "Creating SalAddress for " << uri;
+	SalAddress *address = nullptr;
+	if (alternateParserFunction) {
+		address = alternateParserFunction(uri);
+	} else address = sal_address_new(L_STRING_TO_C(uri));
 	if (address) {
-		addressesCache.insert(uri, SalAddressWrap(address));
-		return owned(sal_address_clone(address));
+		removeFromLeakDetector(address);
+		ptr = (unique_ptr<SalAddress, SalAddressDeleter>(address, SalAddressDeleter()));
+		return sal_address_clone(address);
 	}
-
 	return nullptr;
 }
 
 // -----------------------------------------------------------------------------
 
-Address::Address(const string &address) : ClonableObject(*new ClonableObjectPrivate) {
-	if (!(internalAddress = getSalAddressFromCache(address))) {
+Address::Address(const string &address) {
+	if (address.empty()) {
+		mImpl = sal_address_new_empty();
+	} else if (!(mImpl = getSalAddressFromCache(address, nullptr))) {
 		lWarning() << "Cannot create Address, bad uri [" << address << "]";
 	}
 }
 
-Address::Address(const Address &other)
-    : ClonableObject(*new ClonableObjectPrivate),
-      internalAddress(other.internalAddress ? owned(sal_address_clone(other.internalAddress)) : nullptr) {
+Address::Address(const Address &other) : HybridObject(other) {
+	SalAddress *salAddress = other.mImpl;
+	if (salAddress) mImpl = sal_address_clone(salAddress);
+	else mImpl = sal_address_new_empty();
 }
 
-Address::Address(BorrowedMut<SalAddress> source)
-    : ClonableObject(*new ClonableObjectPrivate), internalAddress(source ? owned(sal_address_ref(source)) : nullptr) {
+Address::Address(SalAddress *addr) {
+	mImpl = addr;
 }
 
-Address::~Address() {
-	if (internalAddress) sal_address_unref(internalAddress.take());
+Address::Address() {
+	mImpl = sal_address_new_empty();
 }
 
-Address &Address::operator=(const Address &other) {
-	if (this != &other) {
-		setInternalAddress(other.internalAddress);
-	}
+Address::Address(Address &&other) {
+	mImpl = other.mImpl;
+	other.mImpl = nullptr;
+}
 
-	return *this;
+Address::~Address() {
+	if (mImpl) sal_address_unref(mImpl);
+}
+
+Address *Address::clone() const {
+	return new Address(*this);
 }
 
-Address &Address::operator=(Address &&other) {
+Address &Address::operator=(const Address &other) {
 	if (this != &other) {
-		if (internalAddress) sal_address_unref(internalAddress.take());
-		internalAddress = std::move(other.internalAddress);
+		if (mImpl) sal_address_unref(mImpl);
+		SalAddress *salAddress = other.mImpl;
+		mImpl = salAddress ? sal_address_clone(salAddress) : nullptr;
 	}
 
 	return *this;
@@ -116,8 +101,8 @@ Address &Address::operator=(Address &&other) {
 
 bool Address::operator==(const Address &other) const {
 	// If either internal addresses is NULL, then the two addresses are not the same
-	if (!internalAddress || !other.internalAddress) return false;
-	return (sal_address_equals(internalAddress, other.internalAddress) == 0);
+	if (!mImpl || !other.mImpl) return false;
+	return (sal_address_equals(mImpl, other.mImpl) == 0);
 }
 
 bool Address::operator!=(const Address &other) const {
@@ -130,162 +115,220 @@ bool Address::operator<(const Address &other) const {
 
 // -----------------------------------------------------------------------------
 
-void Address::setInternalAddress(const Borrowed<SalAddress> addr) {
-	if (internalAddress) sal_address_unref(internalAddress.take());
-	internalAddress = addr ? owned(sal_address_clone(addr)) : nullptr;
+Address Address::getUri() const {
+	if (mImpl) {
+		return Address(sal_address_new_uri_only(mImpl));
+	}
+	return Address();
+}
+
+Address Address::getUriWithoutGruu() const {
+	auto uri = getUri();
+	uri.removeUriParam("gr");
+	return uri;
+}
+
+void Address::setImpl(const SalAddress *addr) {
+	setImpl(sal_address_clone(addr));
+}
+
+void Address::setImpl(SalAddress *addr) {
+	if (mImpl) sal_address_unref(mImpl);
+	mImpl = addr;
 }
 
 void Address::clearSipAddressesCache() {
-	addressesCache.clear();
+	sAddressCache.clear();
 }
 
 bool Address::isValid() const {
-	return !!internalAddress;
+	return mImpl && sal_address_get_domain(mImpl);
 }
 
-const string &Address::getScheme() const {
-	if (!internalAddress) return Utils::getEmptyConstRefObject<string>();
+bool Address::setScheme(const std::string &scheme) {
+	if (!mImpl) return false;
+	if (scheme == "sip") setSecure(false);
+	else if (scheme == "sips") setSecure(true);
+	else {
+		lError() << "Address::setScheme() can't be set to " << scheme;
+		return false;
+	}
+	return true;
+}
 
-	string scheme(L_C_TO_STRING(sal_address_get_scheme(internalAddress)));
-	if (scheme != cache.scheme) cache.scheme = scheme;
-	return cache.scheme;
+const char *Address::getSchemeCstr() const {
+	return mImpl ? sal_address_get_scheme(mImpl) : nullptr;
 }
 
-const string &Address::getDisplayName() const {
-	if (!internalAddress) return Utils::getEmptyConstRefObject<string>();
+std::string Address::getScheme() const {
+	return L_C_TO_STRING(getSchemeCstr());
+}
+
+const char *Address::getDisplayNameCstr() const {
+	return mImpl ? sal_address_get_display_name(mImpl) : nullptr;
+}
 
-	string displayName(L_C_TO_STRING(sal_address_get_display_name(internalAddress)));
-	if (displayName != cache.displayName) cache.displayName = displayName;
-	return cache.displayName;
+std::string Address::getDisplayName() const {
+	return L_C_TO_STRING(getDisplayNameCstr());
 }
 
 bool Address::setDisplayName(const string &displayName) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_display_name(internalAddress.borrow(), L_STRING_TO_C(displayName));
+	sal_address_set_display_name(mImpl, L_STRING_TO_C(displayName));
 	return true;
 }
 
-const string &Address::getUsername() const {
-	if (!internalAddress) return Utils::getEmptyConstRefObject<string>();
+const char *Address::getUsernameCstr() const {
+	return mImpl ? sal_address_get_username(mImpl) : nullptr;
+}
 
-	string username(L_C_TO_STRING(sal_address_get_username(internalAddress)));
-	if (username != cache.username) cache.username = username;
-	return cache.username;
+const std::string Address::getUsername() const {
+	return L_C_TO_STRING(getUsernameCstr());
 }
 
 bool Address::setUsername(const string &username) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_username(internalAddress.borrow(), L_STRING_TO_C(username));
+	sal_address_set_username(mImpl, L_STRING_TO_C(username));
 	return true;
 }
 
-const string &Address::getDomain() const {
-	if (!internalAddress) return Utils::getEmptyConstRefObject<string>();
+const char *Address::getDomainCstr() const {
+	return mImpl ? sal_address_get_domain(mImpl) : nullptr;
+}
 
-	string domain(L_C_TO_STRING(sal_address_get_domain(internalAddress)));
-	if (domain != cache.domain) cache.domain = domain;
-	return cache.domain;
+std::string Address::getDomain() const {
+	return L_C_TO_STRING(getDomainCstr());
 }
 
 bool Address::setDomain(const string &domain) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_domain(internalAddress.borrow(), L_STRING_TO_C(domain));
+	sal_address_set_domain(mImpl, L_STRING_TO_C(domain));
 	return true;
 }
 
 int Address::getPort() const {
-	return internalAddress ? sal_address_get_port(internalAddress) : 0;
+	return mImpl ? sal_address_get_port(mImpl) : 0;
 }
 
 bool Address::setPort(int port) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_port(internalAddress.borrow(), port);
+	sal_address_set_port(mImpl, port);
 	return true;
 }
 
 Transport Address::getTransport() const {
-	return internalAddress ? static_cast<Transport>(sal_address_get_transport(internalAddress)) : Transport::Udp;
+	return mImpl ? static_cast<Transport>(sal_address_get_transport(mImpl)) : Transport::Udp;
 }
 
 bool Address::setTransport(Transport transport) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_transport(internalAddress.borrow(), static_cast<SalTransport>(transport));
+	sal_address_set_transport(mImpl, static_cast<SalTransport>(transport));
 	return true;
 }
 
 bool Address::getSecure() const {
-	return internalAddress && sal_address_is_secure(internalAddress);
+	return mImpl && sal_address_is_secure(mImpl);
 }
 
 bool Address::setSecure(bool enabled) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_secure(internalAddress.borrow(), enabled);
+	sal_address_set_secure(mImpl, enabled);
 	return true;
 }
 
 bool Address::isSip() const {
-	return internalAddress && sal_address_is_sip(internalAddress);
+	return mImpl && sal_address_is_sip(mImpl);
 }
 
-const string &Address::getMethodParam() const {
-	if (!internalAddress) return Utils::getEmptyConstRefObject<string>();
-
-	string methodParam(L_C_TO_STRING(sal_address_get_method_param(internalAddress)));
-	if (methodParam != cache.methodParam) cache.methodParam = methodParam;
-	return cache.methodParam;
+bool Address::setMethodParam(const std::string &value) {
+	if (!mImpl) return false;
+	sal_address_set_method_param(mImpl, value.c_str());
+	return true;
 }
 
-bool Address::setMethodParam(const string &methodParam) {
-	if (!internalAddress) return false;
+const char *Address::getMethodParamCstr() const {
+	return mImpl ? sal_address_get_method_param(mImpl) : nullptr;
+}
 
-	sal_address_set_method_param(internalAddress.borrow(), L_STRING_TO_C(methodParam));
-	return true;
+std::string Address::getMethodParam() const {
+	return L_C_TO_STRING(getMethodParamCstr());
 }
 
-const string &Address::getPassword() const {
-	if (!internalAddress) return Utils::getEmptyConstRefObject<string>();
+const char *Address::getPasswordCstr() const {
+	return mImpl ? sal_address_get_password(mImpl) : nullptr;
+}
 
-	string password(L_C_TO_STRING(sal_address_get_password(internalAddress)));
-	if (password != cache.password) cache.password = password;
-	return cache.password;
+std::string Address::getPassword() const {
+	return L_C_TO_STRING(getPasswordCstr());
 }
 
 bool Address::setPassword(const string &password) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_password(internalAddress.borrow(), L_STRING_TO_C(password));
+	sal_address_set_password(mImpl, L_STRING_TO_C(password));
 	return true;
 }
 
 bool Address::clean() {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_clean(internalAddress.borrow());
+	sal_address_clean(mImpl);
 	return true;
 }
 
-string Address::asString() const {
-	if (!internalAddress) return "";
+char *Address::toStringCstr() const {
+	return isValid() ? sal_address_as_string(mImpl) : nullptr;
+}
+
+std::string Address::toString() const {
+	char *tmp = toStringCstr();
+	std::string ret(L_C_TO_STRING(tmp));
+	bctbx_free(tmp);
+	return ret;
+}
+
+string Address::toStringUriOnlyOrdered() const {
+	ostringstream res;
+	res << getScheme() << ":";
+	if (!getUsername().empty()) {
+		char *tmp = belle_sip_uri_to_escaped_username(getUsername().c_str());
+		res << tmp << "@";
+		ms_free(tmp);
+	}
+
+	if (getDomain().find(":") != string::npos) {
+		res << "[" << getDomain() << "]";
+	} else {
+		res << getDomain();
+	}
 
-	char *buf = sal_address_as_string(internalAddress);
-	string out = buf;
-	ms_free(buf);
-	return out;
+	const auto uriParams = getUriParams();
+	for (const auto &param : uriParams) {
+		const auto &name = param.first;
+		res << ";" << name;
+		const auto &value = param.second;
+		if (!value.empty()) {
+			res << "=" << value;
+		}
+	}
+	return res.str();
 }
 
-string Address::asStringUriOnly() const {
-	if (!internalAddress) return "";
+char *Address::asStringUriOnlyCstr() const {
+	return isValid() ? sal_address_as_string_uri_only(mImpl) : nullptr;
+}
 
-	char *buf = sal_address_as_string_uri_only(internalAddress);
-	string out = buf;
-	ms_free(buf);
-	return out;
+std::string Address::asStringUriOnly() const {
+	char *buf = asStringUriOnlyCstr();
+	std::string tmp(L_C_TO_STRING(buf));
+	bctbx_free(buf);
+	return tmp;
 }
 
 bool Address::weakEqual(const Address &address) const {
@@ -293,113 +336,95 @@ bool Address::weakEqual(const Address &address) const {
 	       getPort() == address.getPort();
 }
 
-const string &Address::getHeaderValue(const string &headerName) const {
-	if (internalAddress) {
-		const char *value = sal_address_get_header(internalAddress, L_STRING_TO_C(headerName));
-		if (value) {
-			cache.headers[headerName] = value;
-			return cache.headers[headerName];
-		}
-	}
+const char *Address::getHeaderValueCstr(const string &headerName) const {
+	return mImpl ? sal_address_get_header(mImpl, headerName.c_str()) : nullptr;
+}
 
-	return Utils::getEmptyConstRefObject<string>();
+std::string Address::getHeaderValue(const std::string &headerName) const {
+	return L_C_TO_STRING(getHeaderValueCstr(headerName));
 }
 
 bool Address::setHeader(const string &headerName, const string &headerValue) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_header(internalAddress.borrow(), L_STRING_TO_C(headerName), L_STRING_TO_C(headerValue));
+	sal_address_set_header(mImpl, L_STRING_TO_C(headerName), L_STRING_TO_C(headerValue));
 	return true;
 }
 
 bool Address::hasParam(const string &paramName) const {
-	return internalAddress && !!sal_address_has_param(internalAddress, L_STRING_TO_C(paramName));
+	return mImpl && !!sal_address_has_param(mImpl, L_STRING_TO_C(paramName));
 }
 
-const string &Address::getParamValue(const string &paramName) const {
-	if (internalAddress) {
-		const char *value = sal_address_get_param(internalAddress, L_STRING_TO_C(paramName));
-		if (value) {
-			cache.params[paramName] = value;
-			return cache.params[paramName];
-		}
-	}
+const char *Address::getParamValueCstr(const string &paramName) const {
+	return mImpl ? sal_address_get_param(mImpl, paramName.c_str()) : nullptr;
+}
 
-	return Utils::getEmptyConstRefObject<string>();
+const std::string Address::getParamValue(const std::string &paramName) const {
+	return L_C_TO_STRING(getParamValueCstr(paramName));
 }
 
 bool Address::setParam(const string &paramName, const string &paramValue) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_param(internalAddress.borrow(), L_STRING_TO_C(paramName), L_STRING_TO_C(paramValue));
+	sal_address_set_param(mImpl, L_STRING_TO_C(paramName), L_STRING_TO_C(paramValue));
 	return true;
 }
 
 bool Address::setParams(const string &params) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_params(internalAddress.borrow(), L_STRING_TO_C(params));
+	sal_address_set_params(mImpl, L_STRING_TO_C(params));
 	return true;
 }
 
 bool Address::removeParam(const string &uriParamName) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_remove_param(internalAddress, L_STRING_TO_C(uriParamName));
+	sal_address_remove_param(mImpl, L_STRING_TO_C(uriParamName));
 	return true;
 }
 
 bool Address::hasUriParam(const string &uriParamName) const {
-	return internalAddress && !!sal_address_has_uri_param(internalAddress, L_STRING_TO_C(uriParamName));
+	return mImpl && !!sal_address_has_uri_param(mImpl, L_STRING_TO_C(uriParamName));
 }
 
-const string &Address::getUriParamValue(const string &uriParamName) const {
-	if (internalAddress) {
-		const char *value = sal_address_get_uri_param(internalAddress, L_STRING_TO_C(uriParamName));
-		if (value) {
-			cache.uriParams[uriParamName] = value;
-			return cache.uriParams[uriParamName];
-		}
-	}
-
-	return Utils::getEmptyConstRefObject<string>();
+const char *Address::getUriParamValueCstr(const string &uriParamName) const {
+	return mImpl ? sal_address_get_uri_param(mImpl, uriParamName.c_str()) : nullptr;
 }
 
-bctbx_map_t *Address::getUriParams() const {
-	if (internalAddress) {
-		return sal_address_get_uri_params(internalAddress);
-	}
-	return nullptr;
+std::string Address::getUriParamValue(const std::string &uriParamName) const {
+	return L_C_TO_STRING(getUriParamValueCstr(uriParamName));
 }
 
 bool Address::setUriParam(const string &uriParamName, const string &uriParamValue) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_uri_param(internalAddress.borrow(), L_STRING_TO_C(uriParamName), L_STRING_TO_C(uriParamValue));
+	sal_address_set_uri_param(mImpl, L_STRING_TO_C(uriParamName), L_STRING_TO_C(uriParamValue));
 	return true;
 }
 
 bool Address::setUriParams(const string &uriParams) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_set_uri_params(internalAddress.borrow(), L_STRING_TO_C(uriParams));
+	sal_address_set_uri_params(mImpl, L_STRING_TO_C(uriParams));
 	return true;
 }
 
 bool Address::removeUriParam(const string &uriParamName) {
-	if (!internalAddress) return false;
+	if (!mImpl) return false;
 
-	sal_address_remove_uri_param(internalAddress, L_STRING_TO_C(uriParamName));
+	sal_address_remove_uri_param(mImpl, L_STRING_TO_C(uriParamName));
 	return true;
 }
 
-void Address::removeFromLeakDetector() const {
-	belle_sip_header_address_t *header_addr =
-	    BELLE_SIP_HEADER_ADDRESS(static_cast<const SalAddress *>(internalAddress));
+void Address::removeFromLeakDetector(SalAddress *addr) {
+	belle_sip_header_address_t *header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
 	belle_sip_uri_t *sip_uri = belle_sip_header_address_get_uri(header_addr);
-	belle_sip_object_remove_from_leak_detector(
-	    BELLE_SIP_OBJECT(const_cast<belle_sip_parameters_t *>(belle_sip_uri_get_headers(sip_uri))));
-	belle_sip_object_remove_from_leak_detector(BELLE_SIP_OBJECT(sip_uri));
+	if (sip_uri) {
+		belle_sip_object_remove_from_leak_detector(
+		    BELLE_SIP_OBJECT(const_cast<belle_sip_parameters_t *>(belle_sip_uri_get_headers(sip_uri))));
+		belle_sip_object_remove_from_leak_detector(BELLE_SIP_OBJECT(sip_uri));
+	}
 	belle_sip_object_remove_from_leak_detector(BELLE_SIP_OBJECT(header_addr));
 }
 
diff --git a/src/address/address.h b/src/address/address.h
index babe50808b42f7c58ca6c5cdfa4f60806d56ca3a..e996bc7761fc8bbc994883dca11d8924a455f265 100644
--- a/src/address/address.h
+++ b/src/address/address.h
@@ -21,45 +21,39 @@
 #ifndef _L_ADDRESS_H_
 #define _L_ADDRESS_H_
 
-#include <bctoolbox/map.h>
-#include <bctoolbox/ownership.hh>
 #include <ostream>
 #include <unordered_map>
 
+#include "belle-sip/object++.hh"
 #include "c-wrapper/internal/c-sal.h"
+
 #include "enums.h"
-#include "object/clonable-object.h"
 
 // =============================================================================
 
-using namespace ownership;
-
 LINPHONE_BEGIN_NAMESPACE
 
-class IdentityAddress;
-class ConferenceAddress;
-
-class LINPHONE_PUBLIC Address : public ClonableObject {
-	// TODO: Remove me later.
-	friend class CallSession;
-	friend class ClientGroupChatRoom;
-	friend class ClientGroupChatRoomPrivate;
-	friend class ServerGroupChatRoom;
-	friend class ServerGroupChatRoomPrivate;
-	friend class IdentityAddress;
-
+/**
+ * Base class for SIP addresses (not just URIs).
+ * It simply wraps a SalAddress structure (actually a belle_sip_header_address_t).
+ */
+class LINPHONE_PUBLIC Address : public bellesip::HybridObject<LinphoneAddress, Address> {
 public:
-	explicit Address(const std::string &address = "");
+	explicit Address(const std::string &address);
+	Address();
+	Address(Address &&other);
 	Address(const Address &other);
-	Address(BorrowedMut<SalAddress> source);
+	Address(SalAddress *addr);
 	virtual ~Address();
+	virtual Address *clone() const override;
+	virtual std::string toString() const override;
 
-	Address *clone() const override {
-		return new Address(*this);
-	}
+	Address getUri() const;
+	Address getUriWithoutGruu() const;
 
+	virtual char *toStringCstr() const; // This one can be overriden.
+	char *asStringUriOnlyCstr() const;
 	Address &operator=(const Address &other);
-	Address &operator=(Address &&other);
 
 	bool operator==(const Address &other) const;
 	bool operator!=(const Address &other) const;
@@ -68,17 +62,26 @@ public:
 
 	bool isValid() const;
 
-	const std::string &getScheme() const;
+	std::string getScheme() const;
+	const char *getSchemeCstr() const;
+	bool setScheme(const std::string &scheme);
 
-	const std::string &getDisplayName() const;
+	std::string getDisplayName() const;
+	const char *getDisplayNameCstr() const;
 	bool setDisplayName(const std::string &displayName);
 
-	const std::string &getUsername() const;
+	const std::string getUsername() const;
+	const char *getUsernameCstr() const;
 	bool setUsername(const std::string &username);
 
-	const std::string &getDomain() const;
+	std::string getDomain() const;
+	const char *getDomainCstr() const;
 	bool setDomain(const std::string &domain);
 
+	const char *getPasswordCstr() const;
+	std::string getPassword() const;
+	bool setPassword(const std::string &password);
+
 	int getPort() const;
 	bool setPort(int port);
 
@@ -90,64 +93,64 @@ public:
 
 	bool isSip() const;
 
-	const std::string &getMethodParam() const;
-	bool setMethodParam(const std::string &methodParam);
-
-	const std::string &getPassword() const;
-	bool setPassword(const std::string &password);
-
-	bool clean();
+	bool setMethodParam(const std::string &value);
+	std::string getMethodParam() const;
+	const char *getMethodParamCstr() const;
 
-	std::string asString() const;
-	std::string asStringUriOnly() const;
-
-	bool weakEqual(const Address &address) const;
-
-	const std::string &getHeaderValue(const std::string &headerName) const;
+	std::string getHeaderValue(const std::string &headerName) const;
+	const char *getHeaderValueCstr(const std::string &headerName) const;
 	bool setHeader(const std::string &headerName, const std::string &headerValue);
 
 	bool hasParam(const std::string &paramName) const;
-	const std::string &getParamValue(const std::string &paramName) const;
+	const std::string getParamValue(const std::string &paramName) const;
+	const char *getParamValueCstr(const std::string &paramName) const;
 	bool setParam(const std::string &paramName, const std::string &paramValue = "");
 	bool setParams(const std::string &params);
 	bool removeParam(const std::string &paramName);
 
 	bool hasUriParam(const std::string &uriParamName) const;
-	const std::string &getUriParamValue(const std::string &uriParamName) const;
-	bctbx_map_t *getUriParams() const;
+	std::string getUriParamValue(const std::string &uriParamName) const;
+	const char *getUriParamValueCstr(const std::string &uriParamName) const;
+	inline const std::map<std::string, std::string> getUriParams() const {
+		std::map<std::string, std::string> params;
+		if (mImpl) sal_address_get_uri_params(mImpl, params);
+		return params;
+	}
 	bool setUriParam(const std::string &uriParamName, const std::string &uriParamValue = "");
 	bool setUriParams(const std::string &uriParams);
 	bool removeUriParam(const std::string &uriParamName);
 
-	inline const Borrowed<SalAddress> getInternalAddress() const {
-		return internalAddress;
+	inline std::string asString() const {
+		return toString();
 	}
-	/* Set the `internalAddress` with a clone of `value` */
-	void setInternalAddress(const Borrowed<SalAddress> value);
+	std::string toStringUriOnlyOrdered() const;
+
+	std::string asStringUriOnly() const;
 
-	// This method is necessary when creating static variables of type address as they canot be freed before the leak
-	// detector runs
-	void removeFromLeakDetector() const;
+	bool clean();
+	bool weakEqual(const Address &other) const;
+
+	inline const SalAddress *getImpl() const {
+		return mImpl;
+	}
+	void setImpl(SalAddress *value);
+	void setImpl(const SalAddress *value);
 	static void clearSipAddressesCache();
 
+protected:
+	static SalAddress *getSalAddressFromCache(const std::string &uri,
+	                                          std::function<SalAddress *(const std::string &)> alternateParserFunction);
+
 private:
-	struct AddressCache {
-		std::string scheme;
-		std::string displayName;
-		std::string username;
-		std::string domain;
-		std::string methodParam;
-		std::string password;
-
-		std::unordered_map<std::string, std::string> headers;
-		std::unordered_map<std::string, std::string> params;
-		std::unordered_map<std::string, std::string> uriParams;
+	SalAddress *mImpl = nullptr;
+	struct SalAddressDeleter {
+		void operator()(SalAddress *addr) {
+			sal_address_unref(addr);
+		}
 	};
+	static void removeFromLeakDetector(SalAddress *addr);
 
-	// Cqche is required so that getters can return const refs
-	mutable AddressCache cache;
-
-	Owned<SalAddress> internalAddress = nullptr;
+	static std::unordered_map<std::string, std::unique_ptr<SalAddress, SalAddressDeleter>> sAddressCache;
 };
 
 inline std::ostream &operator<<(std::ostream &os, const Address &address) {
diff --git a/src/address/identity-address-parser.cpp b/src/address/identity-address-parser.cpp
deleted file mode 100644
index 04fac941db8c7a6ace686af309561b44613c2abd..0000000000000000000000000000000000000000
--- a/src/address/identity-address-parser.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2010-2022 Belledonne Communications SARL.
- *
- * This file is part of Liblinphone
- * (see https://gitlab.linphone.org/BC/public/liblinphone).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <set>
-#include <unordered_map>
-
-#include <belr/abnf.h>
-#include <belr/grammarbuilder.h>
-
-#include "linphone/utils/utils.h"
-
-#include "logger/logger.h"
-#include "object/object-p.h"
-
-#include "identity-address-parser.h"
-
-// =============================================================================
-
-using namespace std;
-
-LINPHONE_BEGIN_NAMESPACE
-
-namespace {
-string IdentityGrammar("identity_grammar");
-}
-
-// -----------------------------------------------------------------------------
-
-class IdentityAddressParserPrivate : public ObjectPrivate {
-public:
-	shared_ptr<belr::Parser<shared_ptr<IdentityAddress>>> parser;
-	unordered_map<string, shared_ptr<IdentityAddress>> cache;
-};
-
-IdentityAddressParser::IdentityAddressParser() : Singleton(*new IdentityAddressParserPrivate) {
-	L_D();
-
-	shared_ptr<belr::Grammar> grammar = belr::GrammarLoader::get().load(IdentityGrammar);
-	if (!grammar) lFatal() << "Unable to load Identity Address grammar.";
-	d->parser = make_shared<belr::Parser<shared_ptr<IdentityAddress>>>(grammar);
-
-	d->parser->setHandler("address", belr::make_fn(make_shared<IdentityAddress>))
-	    ->setCollector("scheme", belr::make_sfn(&IdentityAddress::setScheme))
-	    ->setCollector("user", belr::make_sfn(&IdentityAddress::setUsername))
-	    ->setCollector("host", belr::make_sfn(&IdentityAddress::setDomain))
-	    ->setCollector("gruu-value", belr::make_sfn(&IdentityAddress::setGruu));
-}
-
-// -----------------------------------------------------------------------------
-
-shared_ptr<IdentityAddress> IdentityAddressParser::parseAddress(const string &input) {
-	L_D();
-
-	auto it = d->cache.find(input);
-	if (it == d->cache.end()) {
-		size_t parsedSize;
-		shared_ptr<IdentityAddress> identityAddress = d->parser->parseInput("Address", input, &parsedSize);
-		if (!identityAddress) {
-			lDebug() << "Unable to parse identity address from " << input;
-			return nullptr;
-		}
-		// Remove identity address from leak detector as the IdentityAddressParser is a used as static variable
-		identityAddress->removeFromLeakDetector();
-		d->cache[input] = identityAddress;
-		return identityAddress;
-	} else {
-		return it->second;
-	}
-}
-
-LINPHONE_END_NAMESPACE
diff --git a/src/address/identity-address.cpp b/src/address/identity-address.cpp
deleted file mode 100644
index 41c0a094b823a22c36d1222459808bec7d14d749..0000000000000000000000000000000000000000
--- a/src/address/identity-address.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (c) 2010-2022 Belledonne Communications SARL.
- *
- * This file is part of Liblinphone
- * (see https://gitlab.linphone.org/BC/public/liblinphone).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "linphone/utils/utils.h"
-#include <belle-sip/utils.h>
-
-#include "identity-address-parser.h"
-
-#include "c-wrapper/c-wrapper.h"
-#include "identity-address.h"
-#include "logger/logger.h"
-
-// =============================================================================
-
-using namespace std;
-
-LINPHONE_BEGIN_NAMESPACE
-
-// -----------------------------------------------------------------------------
-
-IdentityAddress::IdentityAddress(const string &address) {
-	if (!address.empty()) {
-		shared_ptr<IdentityAddress> parsedAddress = IdentityAddressParser::getInstance()->parseAddress(address);
-		if (parsedAddress != nullptr) {
-			char *tmp;
-			setScheme(parsedAddress->getScheme());
-			tmp = belle_sip_to_unescaped_string(parsedAddress->getUsername().c_str());
-			setUsername(tmp);
-			ms_free(tmp);
-			setDomain(parsedAddress->getDomain());
-			setGruu(parsedAddress->getGruu());
-		} else {
-			// lInfo() << "Fallback parsing used for " <<address;
-			Address tmpAddress(address);
-			fillFromAddress(tmpAddress);
-		}
-	}
-}
-
-IdentityAddress::IdentityAddress(const Address &address) {
-	fillFromAddress(address);
-}
-
-void IdentityAddress::fillFromAddress(const Address &address) {
-	if (address.isValid() && ((address.getScheme() == "sip") || (address.getScheme() == "sips"))) {
-		setScheme(address.getScheme());
-		setUsername(address.getUsername());
-		setDomain(address.getDomain());
-		if (address.hasUriParam("gr")) {
-			setGruu(address.getUriParamValue("gr"));
-		}
-	}
-}
-
-IdentityAddress::IdentityAddress(const IdentityAddress &other) : Address(other) {
-}
-
-IdentityAddress::IdentityAddress() {
-}
-
-IdentityAddress &IdentityAddress::operator=(const IdentityAddress &other) {
-	if (this != &other) {
-		Address::operator=(other);
-	}
-	return *this;
-}
-
-bool IdentityAddress::operator==(const IdentityAddress &other) const {
-	/* Scheme is not used for comparison. sip:toto@sip.linphone.org and sips:toto@sip.linphone.org refer to the same
-	 * person. */
-	return getUsername() == other.getUsername() && getDomain() == other.getDomain() && getGruu() == other.getGruu();
-}
-
-bool IdentityAddress::operator!=(const IdentityAddress &other) const {
-	return !(*this == other);
-}
-
-bool IdentityAddress::operator<(const IdentityAddress &other) const {
-	int diff = getUsername().compare(other.getUsername());
-	if (diff == 0) {
-		diff = getDomain().compare(other.getDomain());
-		if (diff == 0) {
-			diff = getGruu().compare(other.getGruu());
-		}
-	}
-	return diff < 0;
-}
-
-bool IdentityAddress::isValid() const {
-	return !getScheme().empty() && !getDomain().empty();
-}
-
-const string &IdentityAddress::getScheme() const {
-	return Address::getScheme();
-}
-
-void IdentityAddress::setScheme(const string &scheme) {
-	Address::setSecure(scheme.compare("sips") == 0);
-}
-
-const string &IdentityAddress::getUsername() const {
-	return Address::getUsername();
-}
-
-void IdentityAddress::setUsername(const string &username) {
-	Address::setUsername(username);
-}
-
-const string &IdentityAddress::getDomain() const {
-	return Address::getDomain();
-}
-
-void IdentityAddress::setDomain(const string &domain) {
-	Address::setDomain(domain);
-}
-
-bool IdentityAddress::hasGruu() const {
-	return hasUriParam("gr");
-}
-
-const string &IdentityAddress::getGruu() const {
-	return getUriParamValue("gr");
-}
-
-void IdentityAddress::setGruu(const string &gruu) {
-	if (gruu.empty() == true) {
-		removeUriParam("gr");
-	} else {
-		setUriParam("gr", gruu);
-	}
-}
-
-IdentityAddress IdentityAddress::getAddressWithoutGruu() const {
-	IdentityAddress address(*this);
-	address.removeUriParam("gr");
-	return address;
-}
-
-string IdentityAddress::asString() const {
-	ostringstream res;
-	res << getScheme() << ":";
-	if (!getUsername().empty()) {
-		char *tmp = belle_sip_uri_to_escaped_username(getUsername().c_str());
-		res << tmp << "@";
-		ms_free(tmp);
-	}
-
-	if (getDomain().find(":") != string::npos) {
-		res << "[" << getDomain() << "]";
-	} else {
-		res << getDomain();
-	}
-
-	if (!getGruu().empty()) {
-		res << ";gr=" << getGruu();
-	}
-	return res.str();
-}
-
-const Address &IdentityAddress::asAddress() const {
-	return *this;
-}
-
-void IdentityAddress::removeFromLeakDetector() const {
-	Address::removeFromLeakDetector();
-}
-
-ConferenceAddress::ConferenceAddress(const Address &address) : IdentityAddress(address) {
-	fillUriParams(address);
-};
-ConferenceAddress::ConferenceAddress(const std::string &address) : ConferenceAddress(Address(address)) {
-}
-ConferenceAddress::ConferenceAddress(const ConferenceAddress &other) : IdentityAddress(other) {
-	fillUriParams(other);
-}
-
-ConferenceAddress::ConferenceAddress(const IdentityAddress &other) : IdentityAddress(other) {
-}
-ConferenceAddress &ConferenceAddress::operator=(const ConferenceAddress &other) {
-	if (this != &other) {
-		IdentityAddress::operator=(other);
-		fillUriParams(other);
-	}
-	return *this;
-}
-
-bool ConferenceAddress::operator==(const ConferenceAddress &other) const {
-	return Address::operator==(other);
-}
-
-bool ConferenceAddress::operator!=(const ConferenceAddress &other) const {
-	return !(*this == other);
-}
-
-bool ConferenceAddress::operator<(const ConferenceAddress &other) const {
-	return Address::operator<(other);
-}
-
-string ConferenceAddress::asString() const {
-	std::string addressStr = IdentityAddress::asString();
-	bctbx_map_t *uriParamMap = getUriParams();
-	bctbx_iterator_t *uriParamMapEnd = bctbx_map_cchar_end(uriParamMap);
-	bctbx_iterator_t *it = bctbx_map_cchar_begin(uriParamMap);
-	for (; !bctbx_iterator_cchar_equals(it, uriParamMapEnd); it = bctbx_iterator_cchar_get_next(it)) {
-		bctbx_pair_t *pair = bctbx_iterator_cchar_get_pair(it);
-		const char *key = bctbx_pair_cchar_get_first(reinterpret_cast<bctbx_pair_cchar_t *>(pair));
-		// GRUU is already added by Identity address asString() function
-		if (strcmp(key, "gr") != 0) {
-			const char *value = (const char *)bctbx_pair_cchar_get_second(pair);
-			addressStr = addressStr + ";" + key;
-			if (value) {
-				addressStr = addressStr + "=" + value;
-			}
-		}
-	}
-	bctbx_iterator_cchar_delete(it);
-	bctbx_iterator_cchar_delete(uriParamMapEnd);
-	bctbx_mmap_cchar_delete_with_data(uriParamMap, bctbx_free);
-	return addressStr;
-}
-
-const string &ConferenceAddress::getConfId() const {
-	return getUriParamValue("conf-id");
-}
-
-void ConferenceAddress::setConfId(const string &confId) {
-	setUriParam("conf-id", confId);
-}
-
-bool ConferenceAddress::hasConfId() const {
-	return hasUriParam("conf-id");
-}
-
-void ConferenceAddress::fillUriParams(const Address &address) {
-	bctbx_map_t *uriParamMap = address.getUriParams();
-	if (uriParamMap) {
-		bctbx_iterator_t *uriParamMapEnd = bctbx_map_cchar_end(uriParamMap);
-		bctbx_iterator_t *it = bctbx_map_cchar_begin(uriParamMap);
-		for (; !bctbx_iterator_cchar_equals(it, uriParamMapEnd); it = bctbx_iterator_cchar_get_next(it)) {
-			bctbx_pair_t *pair = bctbx_iterator_cchar_get_pair(it);
-			const char *key = bctbx_pair_cchar_get_first(reinterpret_cast<bctbx_pair_cchar_t *>(pair));
-			const char *value = (const char *)bctbx_pair_cchar_get_second(pair);
-			setUriParam(L_C_TO_STRING(key), L_C_TO_STRING(value));
-		}
-		bctbx_iterator_cchar_delete(it);
-		bctbx_iterator_cchar_delete(uriParamMapEnd);
-		bctbx_mmap_cchar_delete_with_data(uriParamMap, bctbx_free);
-	}
-}
-
-int ConferenceAddress::compareUriParams(const bctbx_map_t *otherUriParamMap) const {
-	bctbx_map_t *thisUriParamMap = getUriParams();
-	// Check that this and other uri parameter maps have the same number of elements
-	size_t thisMapSize = bctbx_map_cchar_size(thisUriParamMap);
-	size_t otherMapSize = bctbx_map_cchar_size(otherUriParamMap);
-	int diff = (int)(thisMapSize - otherMapSize);
-
-	bctbx_iterator_t *thisUriParamMapEnd = bctbx_map_cchar_end(thisUriParamMap);
-	bctbx_iterator_t *otherUriParamMapEnd = bctbx_map_cchar_end(otherUriParamMap);
-
-	bctbx_iterator_t *thisIt = bctbx_map_cchar_begin(thisUriParamMap);
-
-	// Loop through URI parameter map until:
-	// - diff is 0
-	// - end of map has not been reached
-	while ((diff == 0) && (!bctbx_iterator_cchar_equals(thisIt, thisUriParamMapEnd))) {
-		bctbx_pair_t *thisPair = bctbx_iterator_cchar_get_pair(thisIt);
-		const char *thisKey = bctbx_pair_cchar_get_first(reinterpret_cast<bctbx_pair_cchar_t *>(thisPair));
-		const char *thisValue = (const char *)bctbx_pair_cchar_get_second(thisPair);
-
-		bctbx_iterator_t *otherIt = bctbx_map_cchar_find_key(otherUriParamMap, thisKey);
-		// Test that key exists
-		if (!bctbx_iterator_cchar_equals(otherIt, otherUriParamMapEnd)) {
-			bctbx_pair_t *otherPair = bctbx_iterator_cchar_get_pair(otherIt);
-			const char *otherValue = (const char *)bctbx_pair_cchar_get_second(otherPair);
-			if ((otherValue == NULL) || (thisValue == NULL)) {
-				// keep diff at 0 if both other and this value are NULL
-				diff = ((otherValue == NULL) && (thisValue == NULL)) ? 0 : -1;
-			} else {
-				diff = strcmp(thisValue, otherValue);
-			}
-		} else {
-			diff = -1;
-		}
-
-		bctbx_iterator_cchar_delete(otherIt);
-		thisIt = bctbx_iterator_cchar_get_next(thisIt);
-	}
-
-	bctbx_mmap_cchar_delete_with_data(thisUriParamMap, bctbx_free);
-	bctbx_iterator_cchar_delete(thisIt);
-	bctbx_iterator_cchar_delete(thisUriParamMapEnd);
-	bctbx_iterator_cchar_delete(otherUriParamMapEnd);
-
-	return diff;
-}
-
-ConferenceAddress ConferenceAddress::getAddressWithoutGruu() const {
-	Address address(asString());
-	address.removeUriParam("gr");
-	return address;
-}
-
-LINPHONE_END_NAMESPACE
diff --git a/src/address/identity-address.h b/src/address/identity-address.h
deleted file mode 100644
index cb9e34ee9a5f5e9ff5a9d20cffb5e4ab48d599dc..0000000000000000000000000000000000000000
--- a/src/address/identity-address.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2010-2022 Belledonne Communications SARL.
- *
- * This file is part of Liblinphone
- * (see https://gitlab.linphone.org/BC/public/liblinphone).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _L_IDENTITY_ADDRESS_H_
-#define _L_IDENTITY_ADDRESS_H_
-
-#include <ostream>
-#include <string>
-
-#include "address.h"
-#include "linphone/utils/general.h"
-
-// =============================================================================
-
-LINPHONE_BEGIN_NAMESPACE
-
-class LINPHONE_PUBLIC IdentityAddress : protected Address {
-public:
-	explicit IdentityAddress(const std::string &address);
-	IdentityAddress(const Address &address);
-	IdentityAddress(const IdentityAddress &other);
-	IdentityAddress();
-	virtual ~IdentityAddress() = default;
-
-	virtual IdentityAddress *clone() const override {
-		return new IdentityAddress(*this);
-	}
-
-	IdentityAddress &operator=(const IdentityAddress &other);
-
-	bool operator==(const IdentityAddress &other) const;
-	bool operator!=(const IdentityAddress &other) const;
-
-	bool operator<(const IdentityAddress &other) const;
-
-	bool isValid() const;
-
-	const std::string &getScheme() const;
-	void setScheme(const std::string &scheme);
-
-	const std::string &getUsername() const;
-	void setUsername(const std::string &username);
-
-	const std::string &getDomain() const;
-	void setDomain(const std::string &domain);
-
-	bool hasGruu() const;
-	const std::string &getGruu() const;
-	void setGruu(const std::string &gruu);
-
-	IdentityAddress getAddressWithoutGruu() const;
-
-	virtual std::string asString() const;
-
-	const Address &asAddress() const;
-
-	// This method is necessary when creating static variables of type address as they canot be freed before the leak
-	// detector runs
-	void removeFromLeakDetector() const;
-
-private:
-	void fillFromAddress(const Address &address);
-};
-
-inline std::ostream &operator<<(std::ostream &os, const IdentityAddress &identityAddress) {
-	os << "IdentityAddress(" << identityAddress.asString() << ")";
-	return os;
-}
-
-class LINPHONE_PUBLIC ConferenceAddress : public IdentityAddress {
-public:
-	ConferenceAddress(const std::string &address);
-	ConferenceAddress(const Address &address);
-	ConferenceAddress(const IdentityAddress &other);
-	ConferenceAddress(const ConferenceAddress &other);
-	ConferenceAddress() : IdentityAddress(){};
-	virtual ~ConferenceAddress() = default;
-
-	ConferenceAddress *clone() const override {
-		return new ConferenceAddress(*this);
-	}
-
-	ConferenceAddress &operator=(const ConferenceAddress &other);
-	ConferenceAddress &operator=(const IdentityAddress &other) {
-		if (this != &other) {
-			IdentityAddress::operator=(other);
-		}
-		return *this;
-	};
-
-	bool operator==(const ConferenceAddress &other) const;
-	bool operator!=(const ConferenceAddress &other) const;
-
-	bool operator<(const ConferenceAddress &other) const;
-
-	ConferenceAddress getAddressWithoutGruu() const;
-	virtual std::string asString() const override;
-
-	bool hasConfId() const;
-	const std::string &getConfId() const;
-	void setConfId(const std::string &confId);
-
-private:
-	void fillUriParams(const Address &address);
-	int compareUriParams(const bctbx_map_t *otherUriParamMap) const;
-};
-
-LINPHONE_END_NAMESPACE
-
-// Add map key support.
-namespace std {
-template <>
-struct hash<LinphonePrivate::IdentityAddress> {
-	std::size_t operator()(const LinphonePrivate::IdentityAddress &identityAddress) const {
-		if (!identityAddress.isValid()) return std::size_t(-1);
-		return hash<string>()(identityAddress.asString());
-	}
-};
-} // namespace std
-
-#endif // ifndef _L_IDENTITY_ADDRESS_H_
diff --git a/src/auth-info/auth-stack.cpp b/src/auth-info/auth-stack.cpp
index c5fa70963d57ba232ed5bb25d39005566e5bdb29..09d48434c60985b0cdf2ca024d4fd002b158e259 100644
--- a/src/auth-info/auth-stack.cpp
+++ b/src/auth-info/auth-stack.cpp
@@ -29,6 +29,8 @@
 
 #include "private_functions.h"
 
+#include <algorithm>
+
 using namespace ::std;
 
 LINPHONE_BEGIN_NAMESPACE
diff --git a/src/c-wrapper/api/c-account-params.cpp b/src/c-wrapper/api/c-account-params.cpp
index 24f6e342294267509833f3285bf91c90e0b1270a..4460f8d7f2dd7425b730af9c11dc34c3f11671d1 100644
--- a/src/c-wrapper/api/c-account-params.cpp
+++ b/src/c-wrapper/api/c-account-params.cpp
@@ -20,7 +20,6 @@
 
 #include "linphone/api/c-account-params.h"
 #include "account/account-params.h"
-
 #include "c-wrapper/c-wrapper.h"
 #include "c-wrapper/internal/c-tools.h"
 #include "linphone/api/c-address.h"
@@ -70,21 +69,22 @@ void *linphone_account_params_get_user_data(const LinphoneAccountParams *params)
 }
 
 LinphoneStatus linphone_account_params_set_server_address(LinphoneAccountParams *params,
-                                                          const LinphoneAddress *server_address) {
-	return AccountParams::toCpp(params)->setServerAddress(server_address);
+                                                          LinphoneAddress *server_address) {
+	return AccountParams::toCpp(params)->setServerAddress(Address::toCpp(server_address)->getSharedFromThis());
 }
 
 LinphoneStatus linphone_account_params_set_server_addr(LinphoneAccountParams *params, const char *server_address) {
-	return AccountParams::toCpp(params)->setServerAddressAsString(server_address);
+	return AccountParams::toCpp(params)->setServerAddressAsString(L_C_TO_STRING(server_address));
 }
 
-LinphoneStatus linphone_account_params_set_identity_address(LinphoneAccountParams *params,
-                                                            const LinphoneAddress *identity) {
-	return AccountParams::toCpp(params)->setIdentityAddress(identity);
+LinphoneStatus linphone_account_params_set_identity_address(LinphoneAccountParams *params, LinphoneAddress *identity) {
+	return AccountParams::toCpp(params)->setIdentityAddress(Address::toCpp(identity)->getSharedFromThis());
 }
 
 LinphoneStatus linphone_account_params_set_routes_addresses(LinphoneAccountParams *params, const bctbx_list_t *routes) {
-	return AccountParams::toCpp(params)->setRoutes(routes);
+	const std::list<std::shared_ptr<LinphonePrivate::Address>> routeList =
+	    LinphonePrivate::Utils::bctbxListToCppSharedPtrList<LinphoneAddress, LinphonePrivate::Address>(routes);
+	return AccountParams::toCpp(params)->setRoutes(routeList);
 }
 
 void linphone_account_params_set_expires(LinphoneAccountParams *params, int expires) {
@@ -165,7 +165,7 @@ int linphone_account_params_get_quality_reporting_interval(const LinphoneAccount
 }
 
 const char *linphone_account_params_get_domain(const LinphoneAccountParams *params) {
-	return AccountParams::toCpp(params)->getDomain();
+	return AccountParams::toCpp(params)->getDomainCstr();
 }
 
 const char *linphone_account_params_get_realm(const LinphoneAccountParams *params) {
@@ -176,12 +176,16 @@ void linphone_account_params_set_realm(LinphoneAccountParams *params, const char
 	AccountParams::toCpp(params)->setRealm(L_C_TO_STRING(realm));
 }
 
-const bctbx_list_t *linphone_account_params_get_routes_addresses(const LinphoneAccountParams *params) {
-	return AccountParams::toCpp(params)->getRoutes();
+bctbx_list_t *linphone_account_params_get_routes_addresses(const LinphoneAccountParams *params) {
+	bctbx_list_t *route_list = NULL;
+	for (const auto &route : AccountParams::toCpp(params)->getRoutes()) {
+		route_list = bctbx_list_append(route_list, route->toC());
+	}
+	return route_list;
 }
 
 const LinphoneAddress *linphone_account_params_get_identity_address(const LinphoneAccountParams *params) {
-	return AccountParams::toCpp(params)->getIdentityAddress();
+	return AccountParams::toCpp(params)->getIdentityAddress()->toC();
 }
 
 const char *linphone_account_params_get_identity(const LinphoneAccountParams *params) {
@@ -197,7 +201,7 @@ bool_t linphone_account_params_publish_enabled(const LinphoneAccountParams *para
 }
 
 const LinphoneAddress *linphone_account_params_get_server_address(const LinphoneAccountParams *params) {
-	return AccountParams::toCpp(params)->getServerAddress();
+	return AccountParams::toCpp(params)->getServerAddress()->toC();
 }
 
 const char *linphone_account_params_get_server_addr(const LinphoneAccountParams *params) {
@@ -314,14 +318,14 @@ const char *linphone_account_params_get_conference_factory_uri(const LinphoneAcc
 }
 
 void linphone_account_params_set_audio_video_conference_factory_address(LinphoneAccountParams *params,
-                                                                        const LinphoneAddress *address) {
-	AccountParams::toCpp(params)->setAudioVideoConferenceFactoryAddress(address);
+                                                                        LinphoneAddress *address) {
+	AccountParams::toCpp(params)->setAudioVideoConferenceFactoryAddress(Address::toCpp(address)->getSharedFromThis());
 }
 
 const LinphoneAddress *
 linphone_account_params_get_audio_video_conference_factory_address(const LinphoneAccountParams *params) {
-	const LinphoneAddress *address = AccountParams::toCpp(params)->getAudioVideoConferenceFactoryAddress();
-	return address != nullptr ? address : nullptr;
+	const auto &address = AccountParams::toCpp(params)->getAudioVideoConferenceFactoryAddress();
+	return address != nullptr ? address->toC() : nullptr;
 }
 
 void linphone_account_params_set_push_notification_allowed(LinphoneAccountParams *params, bool_t allow) {
@@ -371,11 +375,11 @@ bool_t linphone_account_params_outbound_proxy_enabled(const LinphoneAccountParam
 }
 
 void linphone_account_params_set_transport(LinphoneAccountParams *params, LinphoneTransportType transport) {
-	AccountParams::toCpp(params)->setTransport(transport);
+	AccountParams::toCpp(params)->setTransport(static_cast<LinphonePrivate::Transport>(transport));
 }
 
 LinphoneTransportType linphone_account_params_get_transport(const LinphoneAccountParams *params) {
-	return AccountParams::toCpp(params)->getTransport();
+	return static_cast<LinphoneTransportType>(AccountParams::toCpp(params)->getTransport());
 }
 
 void linphone_account_params_enable_rtp_bundle(LinphoneAccountParams *params, bool_t value) {
@@ -410,12 +414,12 @@ const char *linphone_account_params_get_custom_param(const LinphoneAccountParams
 	return L_STRING_TO_C(AccountParams::toCpp(params)->getCustomParam(L_C_TO_STRING(key)));
 }
 
-void linphone_account_params_set_custom_contact(LinphoneAccountParams *params, const LinphoneAddress *contact) {
-	AccountParams::toCpp(params)->setCustomContact(contact);
+void linphone_account_params_set_custom_contact(LinphoneAccountParams *params, LinphoneAddress *contact) {
+	AccountParams::toCpp(params)->setCustomContact(Address::toCpp(contact)->getSharedFromThis());
 }
 
 const LinphoneAddress *linphone_account_params_get_custom_contact(const LinphoneAccountParams *params) {
-	return AccountParams::toCpp(params)->getCustomContact();
+	return AccountParams::toCpp(params)->getCustomContact()->toC();
 }
 
 void linphone_account_params_set_lime_server_url(LinphoneAccountParams *params, const char *url) {
diff --git a/src/c-wrapper/api/c-account.cpp b/src/c-wrapper/api/c-account.cpp
index c0898d18518c10a5dd6eea6de0044f4fd2a52f74..8f5d12e463da84f73aba65f2dc4c13b97c3d01f9 100644
--- a/src/c-wrapper/api/c-account.cpp
+++ b/src/c-wrapper/api/c-account.cpp
@@ -110,12 +110,13 @@ const LinphoneErrorInfo *linphone_account_get_error_info(LinphoneAccount *accoun
 	return Account::toCpp(account)->getErrorInfo();
 }
 
-const LinphoneAddress *linphone_account_get_contact_address(LinphoneAccount *account) {
-	return Account::toCpp(account)->getContactAddress();
+LinphoneAddress *linphone_account_get_contact_address(LinphoneAccount *account) {
+	return (Account::toCpp(account)->getContactAddress()) ? Account::toCpp(account)->getContactAddress()->toC() : NULL;
 }
 
 void linphone_account_set_contact_address(LinphoneAccount *account, const LinphoneAddress *addr) {
-	return Account::toCpp(account)->setContactAddress(addr);
+	return Account::toCpp(account)->setContactAddress(
+	    Address::toCpp(const_cast<LinphoneAddress *>(addr))->getSharedFromThis());
 }
 
 LinphoneRegistrationState linphone_account_get_state(LinphoneAccount *account) {
diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp
index b64048ab036683b702efcd54a9e2f711e7f01f00..f10ecfa1707a7608bf7d623e40d8f65fff0a85cb 100644
--- a/src/c-wrapper/api/c-address.cpp
+++ b/src/c-wrapper/api/c-address.cpp
@@ -18,32 +18,26 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "linphone/api/c-address.h"
 #include "address/address.h"
 #include "c-wrapper/c-wrapper.h"
 
-// =============================================================================
-
-L_DECLARE_C_CLONABLE_OBJECT_IMPL(Address);
-
+using namespace LinphonePrivate;
 using namespace std;
 
 // =============================================================================
 
 LinphoneAddress *linphone_address_new(const char *address) {
-	LinphonePrivate::Address *cppPtr = new LinphonePrivate::Address(L_C_TO_STRING(address));
-	if (!cppPtr->isValid()) {
-		delete cppPtr;
-		return nullptr;
+	LinphoneAddress *addr = Address::createCObject(L_C_TO_STRING(address));
+	if (address && address[0] != '\0' && !Address::toCpp(addr)->isValid()) {
+		linphone_address_unref(addr);
+		addr = NULL;
 	}
-
-	LinphoneAddress *object = L_INIT(Address);
-	L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr);
-
-	return object;
+	return addr;
 }
 
 LinphoneAddress *linphone_address_clone(const LinphoneAddress *address) {
-	return reinterpret_cast<LinphoneAddress *>(belle_sip_object_clone(BELLE_SIP_OBJECT(address)));
+	return Address::toCpp(address)->clone()->toC();
 }
 
 LinphoneAddress *linphone_address_ref(LinphoneAddress *address) {
@@ -56,143 +50,143 @@ void linphone_address_unref(LinphoneAddress *address) {
 }
 
 bool_t linphone_address_is_valid(const LinphoneAddress *address) {
-	return address && L_GET_CPP_PTR_FROM_C_OBJECT(address)->isValid();
+	return address && Address::toCpp(address)->isValid();
 }
 
 const char *linphone_address_get_scheme(const LinphoneAddress *address) {
-	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getScheme());
+	return Address::toCpp(address)->getSchemeCstr();
 }
 
 const char *linphone_address_get_display_name(const LinphoneAddress *address) {
-	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getDisplayName());
+	return Address::toCpp(address)->getDisplayNameCstr();
 }
 
 LinphoneStatus linphone_address_set_display_name(LinphoneAddress *address, const char *display_name) {
-	return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setDisplayName(L_C_TO_STRING(display_name));
+	return Address::toCpp(address)->setDisplayName(L_C_TO_STRING(display_name)) ? 0 : -1;
 }
 
 const char *linphone_address_get_username(const LinphoneAddress *address) {
-	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getUsername());
+	return Address::toCpp(address)->getUsernameCstr();
 }
 
 LinphoneStatus linphone_address_set_username(LinphoneAddress *address, const char *username) {
-	return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setUsername(L_C_TO_STRING(username));
+	return Address::toCpp(address)->setUsername(L_C_TO_STRING(username)) ? 0 : -1;
 }
 
 const char *linphone_address_get_domain(const LinphoneAddress *address) {
-	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getDomain());
+	return Address::toCpp(address)->getDomainCstr();
 }
 
 LinphoneStatus linphone_address_set_domain(LinphoneAddress *address, const char *domain) {
-	return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setDomain(L_C_TO_STRING(domain));
+	return Address::toCpp(address)->setDomain(L_C_TO_STRING(domain)) ? 0 : -1;
 }
 
 int linphone_address_get_port(const LinphoneAddress *address) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(address)->getPort();
+	return Address::toCpp(address)->getPort();
 }
 
 LinphoneStatus linphone_address_set_port(LinphoneAddress *address, int port) {
-	return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setPort(port);
+	return Address::toCpp(address)->setPort(port) ? 0 : -1;
 }
 
 LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *address) {
-	return static_cast<LinphoneTransportType>(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getTransport());
+	return static_cast<LinphoneTransportType>(Address::toCpp(address)->getTransport());
 }
 
 LinphoneStatus linphone_address_set_transport(LinphoneAddress *address, LinphoneTransportType transport) {
-	return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setTransport(static_cast<LinphonePrivate::Transport>(transport));
+	return Address::toCpp(address)->setTransport(static_cast<LinphonePrivate::Transport>(transport)) ? 0 : -1;
 }
 
 bool_t linphone_address_get_secure(const LinphoneAddress *address) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(address)->getSecure();
+	return Address::toCpp(address)->getSecure();
 }
 
 void linphone_address_set_secure(LinphoneAddress *address, bool_t enabled) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->setSecure(!!enabled);
+	Address::toCpp(address)->setSecure(!!enabled);
 }
 
 bool_t linphone_address_is_sip(const LinphoneAddress *address) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(address)->isSip();
+	return Address::toCpp(address)->isSip() ? TRUE : FALSE;
 }
 
 const char *linphone_address_get_method_param(const LinphoneAddress *address) {
-	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getMethodParam());
+	return Address::toCpp(address)->getMethodParamCstr();
 }
 
 void linphone_address_set_method_param(LinphoneAddress *address, const char *method_param) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->setMethodParam(L_C_TO_STRING(method_param));
+	Address::toCpp(address)->setMethodParam(L_C_TO_STRING(method_param));
 }
 
 const char *linphone_address_get_password(const LinphoneAddress *address) {
-	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getPassword());
+	return Address::toCpp(address)->getPasswordCstr();
 }
 
 void linphone_address_set_password(LinphoneAddress *address, const char *password) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->setPassword(L_C_TO_STRING(password));
+	Address::toCpp(address)->setPassword(L_C_TO_STRING(password));
 }
 
 void linphone_address_clean(LinphoneAddress *address) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->clean();
+	Address::toCpp(address)->clean();
 }
 
 char *linphone_address_as_string(const LinphoneAddress *address) {
-	return bctbx_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(address)->asString().c_str());
+	return Address::toCpp(address)->toStringCstr();
 }
 
 char *linphone_address_as_string_uri_only(const LinphoneAddress *address) {
-	return bctbx_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(address)->asStringUriOnly().c_str());
+	return Address::toCpp(address)->asStringUriOnlyCstr();
 }
 
 bool_t linphone_address_weak_equal(const LinphoneAddress *address1, const LinphoneAddress *address2) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(address1)->weakEqual(*L_GET_CPP_PTR_FROM_C_OBJECT(address2));
+	return Address::toCpp(address1)->weakEqual(*Address::toCpp(address2)) ? TRUE : FALSE;
 }
 
 bool_t linphone_address_equal(const LinphoneAddress *address1, const LinphoneAddress *address2) {
-	return *L_GET_CPP_PTR_FROM_C_OBJECT(address1) == *L_GET_CPP_PTR_FROM_C_OBJECT(address2);
+	return *Address::toCpp(address1) == *Address::toCpp(address2);
 }
 
 const char *linphone_address_get_header(const LinphoneAddress *address, const char *header_name) {
-	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getHeaderValue(L_C_TO_STRING(header_name)));
+	return Address::toCpp(address)->getHeaderValueCstr(header_name);
 }
 
 void linphone_address_set_header(LinphoneAddress *address, const char *header_name, const char *header_value) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->setHeader(L_C_TO_STRING(header_name), L_C_TO_STRING(header_value));
+	Address::toCpp(address)->setHeader(header_name, L_C_TO_STRING(header_value));
 }
 
 bool_t linphone_address_has_param(const LinphoneAddress *address, const char *param_name) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(address)->hasParam(L_C_TO_STRING(param_name));
+	return Address::toCpp(address)->hasParam(param_name) ? TRUE : FALSE;
 }
 
 const char *linphone_address_get_param(const LinphoneAddress *address, const char *param_name) {
-	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getParamValue(L_C_TO_STRING(param_name)));
+	return Address::toCpp(address)->getParamValueCstr(param_name);
 }
 
 void linphone_address_set_param(LinphoneAddress *address, const char *param_name, const char *param_value) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->setParam(L_C_TO_STRING(param_name), L_C_TO_STRING(param_value));
+	Address::toCpp(address)->setParam(param_name, L_C_TO_STRING(param_value));
 }
 
 void linphone_address_set_params(LinphoneAddress *address, const char *params) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->setParams(L_C_TO_STRING(params));
+	Address::toCpp(address)->setParams(L_C_TO_STRING(params));
 }
 
 bool_t linphone_address_has_uri_param(const LinphoneAddress *address, const char *uri_param_name) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(address)->hasUriParam(L_C_TO_STRING(uri_param_name));
+	return Address::toCpp(address)->hasUriParam(uri_param_name) ? TRUE : FALSE;
 }
 
 const char *linphone_address_get_uri_param(const LinphoneAddress *address, const char *uri_param_name) {
-	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getUriParamValue(L_C_TO_STRING(uri_param_name)));
+	return Address::toCpp(address)->getUriParamValueCstr(uri_param_name);
 }
 
 void linphone_address_set_uri_param(LinphoneAddress *address, const char *uri_param_name, const char *uri_param_value) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->setUriParam(L_C_TO_STRING(uri_param_name), L_C_TO_STRING(uri_param_value));
+	Address::toCpp(address)->setUriParam(uri_param_name, L_C_TO_STRING(uri_param_value));
 }
 
 void linphone_address_set_uri_params(LinphoneAddress *address, const char *params) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->setUriParams(L_C_TO_STRING(params));
+	Address::toCpp(address)->setUriParams(L_C_TO_STRING(params));
 }
 
 void linphone_address_remove_uri_param(LinphoneAddress *address, const char *uri_param_name) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(address)->removeUriParam(L_C_TO_STRING(uri_param_name));
+	Address::toCpp(address)->removeUriParam(L_C_TO_STRING(uri_param_name));
 }
 
 void linphone_address_destroy(LinphoneAddress *address) {
@@ -200,5 +194,5 @@ void linphone_address_destroy(LinphoneAddress *address) {
 }
 
 bool_t linphone_address_is_secure(const LinphoneAddress *address) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(address)->getSecure();
+	return Address::toCpp(address)->getSecure() ? TRUE : FALSE;
 }
diff --git a/src/c-wrapper/api/c-call-log.cpp b/src/c-wrapper/api/c-call-log.cpp
index 47f536da6eb8fbb7c8550e7a8de8f3fdfeb69876..ded5a6f6ff8d6e1045bfead5c05a44a1946f4d3a 100644
--- a/src/c-wrapper/api/c-call-log.cpp
+++ b/src/c-wrapper/api/c-call-log.cpp
@@ -33,7 +33,9 @@ using namespace LinphonePrivate;
 
 LinphoneCallLog *
 linphone_call_log_new(LinphoneCore *core, LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress *to) {
-	return CallLog::createCObject(L_GET_CPP_PTR_FROM_C_OBJECT(core)->getSharedFromThis(), dir, from, to);
+	const auto cppFrom = Address::toCpp(from)->getSharedFromThis();
+	const auto cppTo = Address::toCpp(to)->getSharedFromThis();
+	return CallLog::createCObject(L_GET_CPP_PTR_FROM_C_OBJECT(core)->getSharedFromThis(), dir, cppFrom, cppTo);
 }
 
 LinphoneCallLog *linphone_call_log_ref(LinphoneCallLog *call_log) {
@@ -62,7 +64,7 @@ int linphone_call_log_get_duration(const LinphoneCallLog *call_log) {
 }
 
 const LinphoneAddress *linphone_call_log_get_from_address(const LinphoneCallLog *call_log) {
-	return CallLog::toCpp(call_log)->getFromAddress();
+	return CallLog::toCpp(call_log)->getFromAddress()->toC();
 }
 
 float linphone_call_log_get_quality(const LinphoneCallLog *call_log) {
@@ -74,15 +76,16 @@ const char *linphone_call_log_get_ref_key(const LinphoneCallLog *call_log) {
 }
 
 const LinphoneAddress *linphone_call_log_get_local_address(const LinphoneCallLog *call_log) {
-	return CallLog::toCpp(call_log)->getLocalAddress();
+	return CallLog::toCpp(call_log)->getLocalAddress()->toC();
 }
 
 const LinphoneAddress *linphone_call_log_get_remote_address(const LinphoneCallLog *call_log) {
-	return CallLog::toCpp(call_log)->getRemoteAddress();
+	return CallLog::toCpp(call_log)->getRemoteAddress()->toC();
 }
 
 void linphone_call_log_set_remote_address(LinphoneCallLog *call_log, LinphoneAddress *address) {
-	CallLog::toCpp(call_log)->setRemoteAddress(address);
+	const auto cppAddress = Address::toCpp(address)->getSharedFromThis();
+	CallLog::toCpp(call_log)->setRemoteAddress(cppAddress);
 }
 
 time_t linphone_call_log_get_start_date(const LinphoneCallLog *call_log) {
@@ -94,7 +97,7 @@ LinphoneCallStatus linphone_call_log_get_status(const LinphoneCallLog *call_log)
 }
 
 const LinphoneAddress *linphone_call_log_get_to_address(const LinphoneCallLog *call_log) {
-	return CallLog::toCpp(call_log)->getToAddress();
+	return CallLog::toCpp(call_log)->getToAddress()->toC();
 }
 
 void linphone_call_log_set_ref_key(LinphoneCallLog *call_log, const char *refkey) {
@@ -147,8 +150,10 @@ LinphoneCallLog *linphone_core_create_call_log(LinphoneCore *core,
                                                LinphoneCallStatus status,
                                                bool_t video_enabled,
                                                float quality) {
-	auto log =
-	    CallLog::create(L_GET_CPP_PTR_FROM_C_OBJECT(core), dir, linphone_address_ref(from), linphone_address_ref(to));
+
+	const auto cppFrom = Address::toCpp(from)->getSharedFromThis();
+	const auto cppTo = Address::toCpp(to)->getSharedFromThis();
+	auto log = CallLog::create(L_GET_CPP_PTR_FROM_C_OBJECT(core), dir, cppFrom, cppTo);
 
 	log->setDuration(duration);
 	log->setStartTime(start_time);
@@ -183,10 +188,11 @@ void call_logs_write_to_config_file(LinphoneCore *lc) {
 		linphone_config_clean_section(cfg, logsection);
 		linphone_config_set_int(cfg, logsection, "dir", log->getDirection());
 		linphone_config_set_int(cfg, logsection, "status", log->getStatus());
-		tmp = linphone_address_as_string(log->getFromAddress());
+
+		tmp = ms_strdup(L_STRING_TO_C(log->getFromAddress()->toString()));
 		linphone_config_set_string(cfg, logsection, "from", tmp);
 		ms_free(tmp);
-		tmp = linphone_address_as_string(log->getToAddress());
+		tmp = ms_strdup(L_STRING_TO_C(log->getToAddress()->toString()));
 		linphone_config_set_string(cfg, logsection, "to", tmp);
 		ms_free(tmp);
 		if (log->getStartTime())
@@ -216,13 +222,13 @@ bctbx_list_t *linphone_core_read_call_logs_from_config_file(LinphoneCore *lc) {
 	for (i = 0;; ++i) {
 		snprintf(logsection, sizeof(logsection), "call_log_%i", i);
 		if (linphone_config_has_section(cfg, logsection)) {
-			LinphoneAddress *from = NULL, *to = NULL;
 			tmp = linphone_config_get_string(cfg, logsection, "from", NULL);
-			if (tmp) from = linphone_address_new(tmp);
+			const auto from = (tmp) ? Address::create(tmp) : nullptr;
 			tmp = linphone_config_get_string(cfg, logsection, "to", NULL);
-			if (tmp) to = linphone_address_new(tmp);
-			if (!from || !to) continue;
-
+			const auto to = (tmp) ? Address::create(tmp) : nullptr;
+			if (!from || !from->isValid() || !to || !to->isValid()) {
+				continue;
+			}
 			auto cl = CallLog::create(L_GET_CPP_PTR_FROM_C_OBJECT(lc),
 			                          static_cast<LinphoneCallDir>(linphone_config_get_int(cfg, logsection, "dir", 0)),
 			                          from, to);
@@ -357,7 +363,8 @@ bctbx_list_t *linphone_core_get_call_history_for_address(LinphoneCore *lc, const
 	std::unique_ptr<MainDb> &mainDb = L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb;
 	if (!mainDb) return NULL;
 
-	auto list = mainDb->getCallHistory(ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)));
+	const auto cppAddr = Address::toCpp(const_cast<LinphoneAddress *>(addr))->getSharedFromThis();
+	auto list = mainDb->getCallHistory(cppAddr);
 
 	bctbx_list_t *results = NULL;
 	if (!list.empty()) {
@@ -382,8 +389,9 @@ bctbx_list_t *linphone_core_get_call_history_2(LinphoneCore *lc,
 	std::unique_ptr<MainDb> &mainDb = L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb;
 	if (!mainDb) return NULL;
 
-	auto list = mainDb->getCallHistory(ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(peer_addr)),
-	                                   ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(local_addr)));
+	const auto peerAddr = Address::toCpp(const_cast<LinphoneAddress *>(peer_addr))->getSharedFromThis();
+	const auto localAddr = Address::toCpp(const_cast<LinphoneAddress *>(local_addr))->getSharedFromThis();
+	auto list = mainDb->getCallHistory(peerAddr, localAddr);
 
 	bctbx_list_t *results = NULL;
 	if (!list.empty()) {
diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp
index 15a32e3e61d9e0a8ad63100492249de842026899..620f74fb47ed63feb6ca388349084c463d53fefb 100644
--- a/src/c-wrapper/api/c-call.cpp
+++ b/src/c-wrapper/api/c-call.cpp
@@ -64,8 +64,8 @@ LinphonePrivate::SalCallOp *linphone_call_get_op(const LinphoneCall *call) {
 	return Call::toCpp(call)->getOp();
 }
 
-LinphoneProxyConfig *linphone_call_get_dest_proxy(const LinphoneCall *call) {
-	return Call::toCpp(call)->getDestProxy();
+LinphoneAccount *linphone_call_get_dest_account(const LinphoneCall *call) {
+	return Call::toCpp(call)->getDestAccount()->toC();
 }
 
 IceSession *linphone_call_get_ice_session(const LinphoneCall *call) {
@@ -177,15 +177,15 @@ bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call) {
 }
 
 const LinphoneAddress *linphone_call_get_remote_address(const LinphoneCall *call) {
-	return L_GET_C_BACK_PTR(Call::toCpp(call)->getRemoteAddress());
+	return Call::toCpp(call)->getRemoteAddress()->toC();
 }
 
 const LinphoneAddress *linphone_call_get_to_address(const LinphoneCall *call) {
-	return L_GET_C_BACK_PTR(&Call::toCpp(call)->getToAddress());
+	return Call::toCpp(call)->getToAddress()->toC();
 }
 
 const LinphoneAddress *linphone_call_get_request_address(const LinphoneCall *call) {
-	return L_GET_C_BACK_PTR(&Call::toCpp(call)->getActiveSession()->getRequestAddress());
+	return Call::toCpp(call)->getActiveSession()->getRequestAddress()->toC();
 }
 
 const char *linphone_call_get_to_header(const LinphoneCall *call, const char *name) {
@@ -198,8 +198,8 @@ char *linphone_call_get_remote_address_as_string(const LinphoneCall *call) {
 }
 
 const LinphoneAddress *linphone_call_get_diversion_address(const LinphoneCall *call) {
-	const LinphonePrivate::Address &diversionAddress = Call::toCpp(call)->getDiversionAddress();
-	return diversionAddress.isValid() ? L_GET_C_BACK_PTR(&diversionAddress) : nullptr;
+	const auto &diversionAddress = Call::toCpp(call)->getDiversionAddress();
+	return diversionAddress && diversionAddress->isValid() ? diversionAddress->toC() : nullptr;
 }
 
 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call) {
@@ -215,8 +215,8 @@ const char *linphone_call_get_refer_to(const LinphoneCall *call) {
 }
 
 LinphoneAddress *linphone_call_get_refer_to_address(const LinphoneCall *call) {
-	const LinphonePrivate::Address &referToAddress = Call::toCpp(call)->getReferToAddress();
-	return referToAddress.isValid() ? L_GET_C_BACK_PTR(&referToAddress) : nullptr;
+	const auto &referToAddress = Call::toCpp(call)->getReferToAddress();
+	return referToAddress && referToAddress->isValid() ? referToAddress->toC() : nullptr;
 }
 
 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call) {
@@ -387,8 +387,8 @@ LinphoneStatus linphone_call_redirect(LinphoneCall *call, const char *redirect_u
 	return Call::toCpp(call)->redirect(redirect_uri);
 }
 
-LinphoneStatus linphone_call_redirect_to(LinphoneCall *call, const LinphoneAddress *redirect_address) {
-	return Call::toCpp(call)->redirect(*L_GET_CPP_PTR_FROM_C_OBJECT(redirect_address));
+LinphoneStatus linphone_call_redirect_to(LinphoneCall *call, LinphoneAddress *redirect_address) {
+	return Call::toCpp(call)->redirect(Address::toCpp(redirect_address)->getSharedFromThis());
 }
 
 LinphoneStatus linphone_call_decline(LinphoneCall *call, LinphoneReason reason) {
@@ -431,8 +431,8 @@ LinphoneStatus linphone_call_transfer(LinphoneCall *call, const char *referTo) {
 	return Call::toCpp(call)->transfer(referTo);
 }
 
-LinphoneStatus linphone_call_transfer_to(LinphoneCall *call, const LinphoneAddress *referTo) {
-	return Call::toCpp(call)->transfer(*L_GET_CPP_PTR_FROM_C_OBJECT(referTo));
+LinphoneStatus linphone_call_transfer_to(LinphoneCall *call, LinphoneAddress *referTo) {
+	return Call::toCpp(call)->transfer(Address::toCpp(referTo)->getSharedFromThis());
 }
 
 LinphoneStatus linphone_call_transfer_to_another(LinphoneCall *call, LinphoneCall *dest) {
@@ -621,9 +621,10 @@ LinphoneCall *linphone_call_new_outgoing(LinphoneCore *lc,
                                          const LinphoneAddress *to,
                                          const LinphoneCallParams *params,
                                          LinphoneProxyConfig *cfg) {
-	LinphoneCall *lcall =
-	    Call::createCObject(L_GET_CPP_PTR_FROM_C_OBJECT(lc), LinphoneCallOutgoing, *L_GET_CPP_PTR_FROM_C_OBJECT(from),
-	                        *L_GET_CPP_PTR_FROM_C_OBJECT(to), cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params));
+	LinphoneCall *lcall = Call::createCObject(L_GET_CPP_PTR_FROM_C_OBJECT(lc), LinphoneCallOutgoing,
+	                                          Address::toCpp(const_cast<LinphoneAddress *>(from))->getSharedFromThis(),
+	                                          Address::toCpp(const_cast<LinphoneAddress *>(to))->getSharedFromThis(),
+	                                          cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params));
 
 	return lcall;
 }
@@ -632,9 +633,10 @@ LinphoneCall *linphone_call_new_incoming(LinphoneCore *lc,
                                          const LinphoneAddress *from,
                                          const LinphoneAddress *to,
                                          LinphonePrivate::SalCallOp *op) {
-	LinphoneCall *lcall =
-	    Call::createCObject(L_GET_CPP_PTR_FROM_C_OBJECT(lc), LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_OBJECT(from),
-	                        *L_GET_CPP_PTR_FROM_C_OBJECT(to), nullptr, op, nullptr);
+	LinphoneCall *lcall = Call::createCObject(L_GET_CPP_PTR_FROM_C_OBJECT(lc), LinphoneCallIncoming,
+	                                          Address::toCpp(const_cast<LinphoneAddress *>(from))->getSharedFromThis(),
+	                                          Address::toCpp(const_cast<LinphoneAddress *>(to))->getSharedFromThis(),
+	                                          nullptr, op, nullptr);
 	Call::toCpp(lcall)->initiateIncoming();
 	return lcall;
 }
diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp
index 7d2f3bc275e8bfd18241ca56fee451edf3de96c7..fda749c27b183e5142beb77cccf844ce974fb1f0 100644
--- a/src/c-wrapper/api/c-chat-message.cpp
+++ b/src/c-wrapper/api/c-chat-message.cpp
@@ -238,13 +238,13 @@ void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *dat
 }
 
 const LinphoneAddress *linphone_chat_message_get_from_address(const LinphoneChatMessage *msg) {
-	const LinphonePrivate::Address &addr = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFromAddress().asAddress();
-	return L_GET_C_BACK_PTR(&addr);
+	const auto &addr = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFromAddress();
+	return addr->toC();
 }
 
 const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMessage *msg) {
-	const LinphonePrivate::Address &addr = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getToAddress().asAddress();
-	return L_GET_C_BACK_PTR(&addr);
+	const auto addr = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getToAddress();
+	return addr->toC();
 }
 
 const char *linphone_chat_message_get_file_transfer_filepath(const LinphoneChatMessage *msg) {
@@ -273,9 +273,9 @@ const char *linphone_chat_message_get_reply_message_id(LinphoneChatMessage *msg)
 
 const LinphoneAddress *linphone_chat_message_get_reply_message_sender_address(LinphoneChatMessage *msg) {
 	if (L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isReply()) {
-		const LinphonePrivate::IdentityAddress &address = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getReplyToSenderAddress();
-		if (address.isValid()) {
-			return L_GET_C_BACK_PTR(&(address.asAddress()));
+		const auto &address = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getReplyToSenderAddress();
+		if (address && address->isValid()) {
+			return address->toC();
 		}
 	}
 	return NULL;
@@ -539,8 +539,8 @@ const LinphoneAddress *linphone_chat_message_get_peer_address(const LinphoneChat
 }
 
 const LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage *msg) {
-	const LinphonePrivate::Address &addr = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getLocalAddress().asAddress();
-	return L_GET_C_BACK_PTR(&addr);
+	const auto &addr = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getLocalAddress();
+	return addr->toC();
 }
 
 LinphoneReason linphone_chat_message_get_reason(const LinphoneChatMessage *msg) {
diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp
index 27d46b8b48d11499a21818dc78d741fc26b51ecd..707feb4e3c9bd23d8da17cc1fae6382281b8e63e 100644
--- a/src/c-wrapper/api/c-chat-room.cpp
+++ b/src/c-wrapper/api/c-chat-room.cpp
@@ -29,7 +29,7 @@
 #include "linphone/api/c-chat-room.h"
 #include "linphone/wrapper_utils.h"
 
-#include "address/identity-address.h"
+#include "address/address.h"
 #include "c-wrapper/c-wrapper.h"
 #include "call/call.h"
 #include "chat/chat-message/chat-message-p.h"
@@ -41,6 +41,7 @@
 #include "conference/participant.h"
 #include "core/core-p.h"
 #include "event-log/event-log.h"
+#include "linphone/utils/utils.h"
 
 // =============================================================================
 
@@ -61,22 +62,9 @@ static void _linphone_chat_room_constructor(BCTBX_UNUSED(LinphoneChatRoom *cr))
 }
 
 static void _linphone_chat_room_destructor(LinphoneChatRoom *cr) {
-	if (cr->composingAddresses)
-		bctbx_list_free_with_data(cr->composingAddresses, (bctbx_list_free_func)linphone_address_unref);
 	_linphone_chat_room_clear_callbacks(cr);
 }
 
-/*
-
-static list<LinphonePrivate::IdentityAddress>
-_get_identity_address_list_from_address_list(list<LinphonePrivate::Address> addressList) {
-    list<LinphonePrivate::IdentityAddress> lIdent;
-    for (const auto &addr : addressList)
-        lIdent.push_back(LinphonePrivate::IdentityAddress(addr));
-    return lIdent;
-}
-*/
-
 void linphone_chat_room_allow_multipart(LinphoneChatRoom *room) {
 	L_GET_CPP_PTR_FROM_C_OBJECT(room)->allowMultipart(true);
 }
@@ -111,18 +99,18 @@ LinphoneCore *linphone_chat_room_get_core(const LinphoneChatRoom *cr) {
 }
 
 const LinphoneAddress *linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) {
-	const LinphonePrivate::IdentityAddress &address = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress();
-	if (address.isValid()) {
-		return L_GET_C_BACK_PTR(&(address.asAddress()));
+	const auto &address = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress();
+	if (address && address->isValid()) {
+		return address->toC();
 	} else {
 		return NULL;
 	}
 }
 
 const LinphoneAddress *linphone_chat_room_get_local_address(LinphoneChatRoom *cr) {
-	const LinphonePrivate::IdentityAddress &address = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLocalAddress();
-	if (address.isValid()) {
-		return L_GET_C_BACK_PTR(&(address.asAddress()));
+	const auto &address = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLocalAddress();
+	if (address && address->isValid()) {
+		return address->toC();
 	} else {
 		return NULL;
 	}
@@ -363,22 +351,18 @@ time_t linphone_chat_room_get_last_update_time(const LinphoneChatRoom *cr) {
 	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastUpdateTime();
 }
 
-void linphone_chat_room_add_participant(LinphoneChatRoom *cr, const LinphoneAddress *addr) {
-	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant(
-	    LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)));
+void linphone_chat_room_add_participant(LinphoneChatRoom *cr, LinphoneAddress *addr) {
+	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant(LinphonePrivate::Address::toCpp(addr)->getSharedFromThis());
 }
 
 bool_t linphone_chat_room_add_participants(LinphoneChatRoom *cr, const bctbx_list_t *addresses) {
-	list<LinphonePrivate::Address> lAddr = L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(addresses, Address);
-	list<LinphonePrivate::IdentityAddress> lIdentAddr;
-	for (const auto &addr : lAddr)
-		lIdentAddr.push_back(LinphonePrivate::IdentityAddress(addr));
-	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipants(lIdentAddr);
+	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipants(
+	    LinphonePrivate::Utils::bctbxListToCppSharedPtrList<LinphoneAddress, LinphonePrivate::Address>(addresses));
 }
 
-LinphoneParticipant *linphone_chat_room_find_participant(const LinphoneChatRoom *cr, const LinphoneAddress *addr) {
-	std::shared_ptr<LinphonePrivate::Participant> participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(
-	    LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)));
+LinphoneParticipant *linphone_chat_room_find_participant(const LinphoneChatRoom *cr, LinphoneAddress *addr) {
+	std::shared_ptr<LinphonePrivate::Participant> participant =
+	    L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(LinphonePrivate::Address::toCpp(addr)->getSharedFromThis());
 	if (participant) {
 		return participant->toC();
 	}
@@ -398,10 +382,9 @@ bool_t linphone_chat_room_has_capability(const LinphoneChatRoom *cr, int mask) {
 }
 
 const LinphoneAddress *linphone_chat_room_get_conference_address(const LinphoneChatRoom *cr) {
-	const LinphonePrivate::ConferenceAddress &confAddress = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress();
-	if (confAddress.isValid()) {
-		const LinphonePrivate::Address &address = confAddress.asAddress();
-		return L_GET_C_BACK_PTR(&address);
+	const auto &confAddress = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress();
+	if (confAddress && confAddress->isValid()) {
+		return confAddress->toC();
 	} else {
 		return NULL;
 	}
@@ -457,15 +440,9 @@ void linphone_chat_room_set_subject(LinphoneChatRoom *cr, const char *subject) {
 }
 
 const bctbx_list_t *linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr) {
-	bctbx_list_free_with_data(cr->composingAddresses, (bctbx_list_free_func)linphone_address_unref);
-	list<LinphonePrivate::Address> composingAddresses;
-	// TODO: Improve perf or algorithm?
-	{
-		list<LinphonePrivate::IdentityAddress> addresses = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getComposingAddresses();
-		transform(addresses.cbegin(), addresses.cend(), back_inserter(composingAddresses),
-		          [](const LinphonePrivate::IdentityAddress &address) { return address.asAddress(); });
-	}
-	cr->composingAddresses = L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(composingAddresses);
+	list<shared_ptr<LinphonePrivate::Address>> addresses = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getComposingAddresses();
+	cr->composingAddresses =
+	    LinphonePrivate::Utils::listToCBctbxList<LinphoneAddress, LinphonePrivate::Address>(addresses);
 	return cr->composingAddresses;
 }
 
@@ -473,16 +450,15 @@ const bctbx_list_t *linphone_chat_room_get_composing_addresses(LinphoneChatRoom
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
-void linphone_chat_room_set_conference_address(LinphoneChatRoom *cr, const LinphoneAddress *confAddr) {
+void linphone_chat_room_set_conference_address(LinphoneChatRoom *cr, LinphoneAddress *confAddr) {
 #ifdef HAVE_ADVANCED_IM
-	char *addrStr = confAddr ? linphone_address_as_string(confAddr) : nullptr;
 	LinphonePrivate::ServerGroupChatRoomPrivate *sgcr =
 	    dynamic_cast<LinphonePrivate::ServerGroupChatRoomPrivate *>(L_GET_PRIVATE_FROM_C_OBJECT(cr));
 	if (sgcr) {
-		LinphonePrivate::Address idAddr = addrStr ? LinphonePrivate::Address(addrStr) : LinphonePrivate::Address("");
+		std::shared_ptr<LinphonePrivate::Address> idAddr =
+		    LinphonePrivate::Address::toCpp(confAddr)->getSharedFromThis();
 		sgcr->setConferenceAddress(idAddr);
 	}
-	if (addrStr) bctbx_free(addrStr);
 #else
 	lWarning() << "Advanced IM such as group chat is disabled!";
 #endif
@@ -496,16 +472,15 @@ void linphone_chat_room_set_conference_address(LinphoneChatRoom *cr, const Linph
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
 void linphone_chat_room_set_participant_devices(LinphoneChatRoom *cr,
-                                                const LinphoneAddress *partAddr,
+                                                LinphoneAddress *partAddr,
                                                 const bctbx_list_t *deviceIdentities) {
 #ifdef HAVE_ADVANCED_IM
-	char *addrStr = linphone_address_as_string(partAddr);
 	list<shared_ptr<LinphonePrivate::ParticipantDeviceIdentity>> lDevicesIdentities =
 	    LinphonePrivate::ParticipantDeviceIdentity::getCppListFromCList(deviceIdentities);
 	LinphonePrivate::ServerGroupChatRoomPrivate *sgcr =
 	    dynamic_cast<LinphonePrivate::ServerGroupChatRoomPrivate *>(L_GET_PRIVATE_FROM_C_OBJECT(cr));
-	if (sgcr) sgcr->setParticipantDevices(LinphonePrivate::IdentityAddress(addrStr), lDevicesIdentities);
-	bctbx_free(addrStr);
+	if (sgcr)
+		sgcr->setParticipantDevices(LinphonePrivate::Address::toCpp(partAddr)->getSharedFromThis(), lDevicesIdentities);
 #else
 	lWarning() << "Advanced IM such as group chat is disabled!";
 #endif
@@ -521,11 +496,11 @@ void linphone_chat_room_set_participant_devices(LinphoneChatRoom *cr,
 void linphone_chat_room_notify_participant_device_registration(LinphoneChatRoom *cr,
                                                                const LinphoneAddress *participant_device) {
 #ifdef HAVE_ADVANCED_IM
-	char *addrStr = linphone_address_as_string(participant_device);
 	LinphonePrivate::ServerGroupChatRoomPrivate *sgcr =
 	    dynamic_cast<LinphonePrivate::ServerGroupChatRoomPrivate *>(L_GET_PRIVATE_FROM_C_OBJECT(cr));
-	if (sgcr) sgcr->notifyParticipantDeviceRegistration(LinphonePrivate::IdentityAddress(addrStr));
-	bctbx_free(addrStr);
+	if (sgcr)
+		sgcr->notifyParticipantDeviceRegistration(
+		    LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(participant_device))->getSharedFromThis());
 #else
 	lWarning() << "Advanced IM such as group chat is disabled!";
 #endif
diff --git a/src/c-wrapper/api/c-conference-info.cpp b/src/c-wrapper/api/c-conference-info.cpp
index 15b38812367ff69b7ae695c42a70a3f9a69ac6a8..d57e70911bb8b5ff7ddd4c72106830b7e32f6f11 100644
--- a/src/c-wrapper/api/c-conference-info.cpp
+++ b/src/c-wrapper/api/c-conference-info.cpp
@@ -46,26 +46,27 @@ void linphone_conference_info_unref(LinphoneConferenceInfo *conference_info) {
 }
 
 const LinphoneAddress *linphone_conference_info_get_organizer(const LinphoneConferenceInfo *conference_info) {
-	const LinphonePrivate::Address &address = ConferenceInfo::toCpp(conference_info)->getOrganizerAddress().asAddress();
-	return address.isValid() ? L_GET_C_BACK_PTR(&address) : nullptr;
+	const auto &address = ConferenceInfo::toCpp(conference_info)->getOrganizerAddress();
+	return address && address->isValid() ? address->toC() : nullptr;
 }
 
 void linphone_conference_info_set_organizer(LinphoneConferenceInfo *conference_info, LinphoneAddress *organizer) {
-	ConferenceInfo::toCpp(conference_info)->setOrganizer(*L_GET_CPP_PTR_FROM_C_OBJECT(organizer));
+	ConferenceInfo::toCpp(conference_info)->setOrganizer(Address::toCpp(organizer)->getSharedFromThis());
 }
 
-const bctbx_list_t *linphone_conference_info_get_participants(const LinphoneConferenceInfo *conference_info) {
-	return ConferenceInfo::toCpp(conference_info)->getParticipantsCList();
+bctbx_list_t *linphone_conference_info_get_participants(const LinphoneConferenceInfo *conference_info) {
+	const auto &participants = ConferenceInfo::toCpp(conference_info)->getParticipants();
+	bctbx_list_t *participant_addresses = NULL;
+	for (const auto &participant : participants) {
+		const auto &address = participant.first;
+		participant_addresses = bctbx_list_append(participant_addresses, address->toC());
+	}
+	return participant_addresses;
 }
 
-void linphone_conference_info_set_participants(LinphoneConferenceInfo *conference_info,
-                                               const bctbx_list_t *participants) {
-	const std::list<LinphonePrivate::IdentityAddress> participantsList = L_GET_CPP_LIST_FROM_C_LIST_2(
-	    participants, LinphoneAddress *, LinphonePrivate::IdentityAddress, [](LinphoneAddress *addr) {
-		    return addr ? LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))
-		                : LinphonePrivate::IdentityAddress();
-	    });
-
+void linphone_conference_info_set_participants(LinphoneConferenceInfo *conference_info, bctbx_list_t *participants) {
+	const std::list<std::shared_ptr<LinphonePrivate::Address>> participantsList =
+	    LinphonePrivate::Utils::bctbxListToCppSharedPtrList<LinphoneAddress, LinphonePrivate::Address>(participants);
 	ConferenceInfo::participant_list_t participantsMap;
 	ConferenceInfo::participant_params_t participantsParams;
 	for (const auto &p : participantsList) {
@@ -75,21 +76,21 @@ void linphone_conference_info_set_participants(LinphoneConferenceInfo *conferenc
 }
 
 void linphone_conference_info_add_participant(LinphoneConferenceInfo *conference_info, LinphoneAddress *participant) {
-	ConferenceInfo::toCpp(conference_info)->addParticipant(*L_GET_CPP_PTR_FROM_C_OBJECT(participant));
+	ConferenceInfo::toCpp(conference_info)->addParticipant(Address::toCpp(participant)->getSharedFromThis());
 }
 
 void linphone_conference_info_remove_participant(LinphoneConferenceInfo *conference_info,
                                                  LinphoneAddress *participant) {
-	ConferenceInfo::toCpp(conference_info)->removeParticipant(*L_GET_CPP_PTR_FROM_C_OBJECT(participant));
+	ConferenceInfo::toCpp(conference_info)->removeParticipant(Address::toCpp(participant)->getSharedFromThis());
 }
 
 const LinphoneAddress *linphone_conference_info_get_uri(const LinphoneConferenceInfo *conference_info) {
-	const LinphonePrivate::Address &address = ConferenceInfo::toCpp(conference_info)->getUri().asAddress();
-	return address.isValid() ? L_GET_C_BACK_PTR(&address) : nullptr;
+	const auto &address = ConferenceInfo::toCpp(conference_info)->getUri();
+	return address && address->isValid() ? address->toC() : nullptr;
 }
 
 void linphone_conference_info_set_uri(LinphoneConferenceInfo *conference_info, LinphoneAddress *uri) {
-	ConferenceInfo::toCpp(conference_info)->setUri(*L_GET_CPP_PTR_FROM_C_OBJECT(uri));
+	ConferenceInfo::toCpp(conference_info)->setUri(Address::toCpp(uri)->getSharedFromThis());
 }
 
 time_t linphone_conference_info_get_date_time(const LinphoneConferenceInfo *conference_info) {
diff --git a/src/c-wrapper/api/c-conference-scheduler.cpp b/src/c-wrapper/api/c-conference-scheduler.cpp
index 31c0c3fb5a32ba9919b82def03c21c5654ee2b34..09d148152cdae7f28fb828f7efbe23e02464e4a6 100644
--- a/src/c-wrapper/api/c-conference-scheduler.cpp
+++ b/src/c-wrapper/api/c-conference-scheduler.cpp
@@ -84,10 +84,9 @@ void linphone_conference_scheduler_notify_state_changed(LinphoneConferenceSchedu
 }
 
 void linphone_conference_scheduler_notify_invitations_sent(LinphoneConferenceScheduler *conference_scheduler,
-                                                           bctbx_list_t *failed_invites) {
+                                                           const bctbx_list_t *failed_invites) {
 	LINPHONE_HYBRID_OBJECT_INVOKE_CBS(ConferenceScheduler, ConferenceScheduler::toCpp(conference_scheduler),
 	                                  linphone_conference_scheduler_cbs_get_invitations_sent, failed_invites);
-	bctbx_list_free_with_data(failed_invites, (bctbx_list_free_func)linphone_address_unref);
 }
 
 void linphone_conference_scheduler_add_callbacks(LinphoneConferenceScheduler *conference_scheduler,
diff --git a/src/c-wrapper/api/c-conference.cpp b/src/c-wrapper/api/c-conference.cpp
index 3cdeb7b3668e186ee73f225e44afc87d5cf791a1..2d5b537db47eb46c369d4722cc407298cc13deb9 100644
--- a/src/c-wrapper/api/c-conference.cpp
+++ b/src/c-wrapper/api/c-conference.cpp
@@ -153,12 +153,12 @@ void linphone_conference_set_conference_address(LinphoneConference *conference,
 	    dynamic_pointer_cast<LinphonePrivate::MediaConference::RemoteConference>(
 	        MediaConference::Conference::toCpp(conference)->getSharedFromThis());
 	if (remoteConference) {
-		MediaConference::Conference::toCpp(conference)->setConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(address));
+		MediaConference::Conference::toCpp(conference)
+		    ->setConferenceAddress(Address::toCpp(address)->getSharedFromThis());
 	}
 }
 
 const LinphoneAddress *linphone_conference_get_conference_address(const LinphoneConference *conference) {
-	const LinphonePrivate::Address &address =
-	    MediaConference::Conference::toCpp(conference)->getConferenceAddress().asAddress();
-	return address.isValid() ? L_GET_C_BACK_PTR(&address) : nullptr;
+	const auto &address = MediaConference::Conference::toCpp(conference)->getConferenceAddress();
+	return address && address->isValid() ? address->toC() : nullptr;
 }
diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp
index df14b003041cad32b42ff707d70be6f953bbd407..59bb56b9babf545f69c6c6bab7da2426b5f2cf90 100644
--- a/src/c-wrapper/api/c-event-log.cpp
+++ b/src/c-wrapper/api/c-event-log.cpp
@@ -213,25 +213,23 @@ void linphone_event_log_delete_from_database(LinphoneEventLog *event_log) {
 const LinphoneAddress *linphone_event_log_get_peer_address(const LinphoneEventLog *event_log) {
 	if (!isConferenceType(linphone_event_log_get_type(event_log))) return nullptr;
 
-	const LinphonePrivate::Address &addr =
+	const std::shared_ptr<LinphonePrivate::Address> &addr =
 	    static_pointer_cast<const LinphonePrivate::ConferenceEvent>(L_GET_CPP_PTR_FROM_C_OBJECT(event_log))
 	        ->getConferenceId()
-	        .getPeerAddress()
-	        .asAddress();
+	        .getPeerAddress();
 
-	return L_GET_C_BACK_PTR(&addr);
+	return addr->toC();
 }
 
 const LinphoneAddress *linphone_event_log_get_local_address(const LinphoneEventLog *event_log) {
 	if (!isConferenceType(linphone_event_log_get_type(event_log))) return nullptr;
 
-	const LinphonePrivate::Address &addr =
+	const std::shared_ptr<LinphonePrivate::Address> &addr =
 	    static_pointer_cast<const LinphonePrivate::ConferenceEvent>(L_GET_CPP_PTR_FROM_C_OBJECT(event_log))
 	        ->getConferenceId()
-	        .getLocalAddress()
-	        .asAddress();
+	        .getLocalAddress();
 
-	return L_GET_C_BACK_PTR(&addr);
+	return addr->toC();
 }
 
 // -----------------------------------------------------------------------------
@@ -292,12 +290,11 @@ LinphoneChatMessage *linphone_event_log_get_chat_message(const LinphoneEventLog
 const LinphoneAddress *linphone_event_log_get_participant_address(const LinphoneEventLog *event_log) {
 	if (!isConferenceParticipantType(linphone_event_log_get_type(event_log))) return nullptr;
 
-	const LinphonePrivate::Address &addr =
+	const std::shared_ptr<LinphonePrivate::Address> &addr =
 	    static_pointer_cast<const LinphonePrivate::ConferenceParticipantEvent>(L_GET_CPP_PTR_FROM_C_OBJECT(event_log))
-	        ->getParticipantAddress()
-	        .asAddress();
+	        ->getParticipantAddress();
 
-	return L_GET_C_BACK_PTR(&addr);
+	return addr->toC();
 }
 
 // -----------------------------------------------------------------------------
@@ -307,12 +304,12 @@ const LinphoneAddress *linphone_event_log_get_participant_address(const Linphone
 const LinphoneAddress *linphone_event_log_get_device_address(const LinphoneEventLog *event_log) {
 	if (!isConferenceParticipantDeviceType(linphone_event_log_get_type(event_log))) return nullptr;
 
-	const LinphonePrivate::Address &addr = static_pointer_cast<const LinphonePrivate::ConferenceParticipantDeviceEvent>(
-	                                           L_GET_CPP_PTR_FROM_C_OBJECT(event_log))
-	                                           ->getDeviceAddress()
-	                                           .asAddress();
+	const std::shared_ptr<LinphonePrivate::Address> &addr =
+	    static_pointer_cast<const LinphonePrivate::ConferenceParticipantDeviceEvent>(
+	        L_GET_CPP_PTR_FROM_C_OBJECT(event_log))
+	        ->getDeviceAddress();
 
-	return L_GET_C_BACK_PTR(&addr);
+	return addr->toC();
 }
 
 // -----------------------------------------------------------------------------
@@ -332,11 +329,9 @@ LINPHONE_PUBLIC LinphoneAddress *
 linphone_event_log_get_security_event_faulty_device_address(const LinphoneEventLog *event_log) {
 	if (!isConferenceSecurityType(linphone_event_log_get_type(event_log))) return nullptr;
 
-	return linphone_address_new(
-	    static_pointer_cast<const LinphonePrivate::ConferenceSecurityEvent>(L_GET_CPP_PTR_FROM_C_OBJECT(event_log))
-	        ->getFaultyDeviceAddress()
-	        .asString()
-	        .c_str());
+	return static_pointer_cast<const LinphonePrivate::ConferenceSecurityEvent>(L_GET_CPP_PTR_FROM_C_OBJECT(event_log))
+	    ->getFaultyDeviceAddress()
+	    ->toC();
 }
 
 // -----------------------------------------------------------------------------
diff --git a/src/c-wrapper/api/c-event.cpp b/src/c-wrapper/api/c-event.cpp
index 5decbb73c425d90e681d6f38b99363a0117931ae..066b1d1e4858b5238b12b4c97f814363cad6173a 100644
--- a/src/c-wrapper/api/c-event.cpp
+++ b/src/c-wrapper/api/c-event.cpp
@@ -58,21 +58,24 @@ int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body
 }
 
 LinphoneEvent *_linphone_core_create_publish(
-    LinphoneCore *core, LinphoneAccount *account, const LinphoneAddress *resource, const char *event, int expires) {
-	return (new EventPublish(L_GET_CPP_PTR_FROM_C_OBJECT(core), Account::toCpp(account)->getSharedFromThis(), resource,
-	                         L_C_TO_STRING(event), expires))
+    LinphoneCore *core, LinphoneAccount *account, LinphoneAddress *resource, const char *event, int expires) {
+	return (new EventPublish(L_GET_CPP_PTR_FROM_C_OBJECT(core), Account::toCpp(account)->getSharedFromThis(),
+	                         Address::toCpp(resource)->getSharedFromThis(), L_C_TO_STRING(event), expires))
 	    ->toC();
 }
 
 LinphoneEvent *
-linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires) {
-	return (new EventPublish(L_GET_CPP_PTR_FROM_C_OBJECT(lc), NULL, resource, L_C_TO_STRING(event), expires))->toC();
+linphone_core_create_publish(LinphoneCore *lc, LinphoneAddress *resource, const char *event, int expires) {
+	return (new EventPublish(L_GET_CPP_PTR_FROM_C_OBJECT(lc), NULL, Address::toCpp(resource)->getSharedFromThis(),
+	                         L_C_TO_STRING(event), expires))
+	    ->toC();
 }
 
 LinphoneEvent *linphone_core_publish(
-    LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body) {
+    LinphoneCore *lc, LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body) {
 	int err;
-	auto ev = (new EventPublish(L_GET_CPP_PTR_FROM_C_OBJECT(lc), resource, L_C_TO_STRING(event), expires));
+	auto ev = (new EventPublish(L_GET_CPP_PTR_FROM_C_OBJECT(lc), Address::toCpp(resource)->getSharedFromThis(),
+	                            L_C_TO_STRING(event), expires));
 	ev->setUnrefWhenTerminated(true);
 	err = _linphone_event_send_publish(ev->toC(), body, FALSE);
 	if (err == -1) {
@@ -82,31 +85,39 @@ LinphoneEvent *linphone_core_publish(
 	return ev->toC();
 }
 
-LinphoneEvent *
-linphone_core_create_one_shot_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event) {
-	return (new EventPublish(L_GET_CPP_PTR_FROM_C_OBJECT(lc), resource, L_C_TO_STRING(event)))->toC();
+LinphoneEvent *linphone_core_create_one_shot_publish(LinphoneCore *lc, LinphoneAddress *resource, const char *event) {
+	return (new EventPublish(L_GET_CPP_PTR_FROM_C_OBJECT(lc), Address::toCpp(resource)->getSharedFromThis(),
+	                         L_C_TO_STRING(event)))
+	    ->toC();
 }
 
-LinphoneEvent *linphone_core_create_notify(LinphoneCore *lc, const LinphoneAddress *resource, const char *event) {
-	return (new EventSubscribe(L_GET_CPP_PTR_FROM_C_OBJECT(lc), resource, L_C_TO_STRING(event)))->toC();
+LinphoneEvent *linphone_core_create_notify(LinphoneCore *lc, LinphoneAddress *resource, const char *event) {
+	return (new EventSubscribe(L_GET_CPP_PTR_FROM_C_OBJECT(lc), Address::toCpp(resource)->getSharedFromThis(),
+	                           L_C_TO_STRING(event)))
+	    ->toC();
 }
 
 LinphoneEvent *
-linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires) {
-	return (new EventSubscribe(L_GET_CPP_PTR_FROM_C_OBJECT(lc), resource, L_C_TO_STRING(event), expires))->toC();
+linphone_core_create_subscribe(LinphoneCore *lc, LinphoneAddress *resource, const char *event, int expires) {
+	return (new EventSubscribe(L_GET_CPP_PTR_FROM_C_OBJECT(lc), Address::toCpp(resource)->getSharedFromThis(),
+	                           L_C_TO_STRING(event), expires))
+	    ->toC();
 }
 
 LinphoneEvent *linphone_core_subscribe(
-    LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body) {
-	auto ev = new EventSubscribe(L_GET_CPP_PTR_FROM_C_OBJECT(lc), resource, L_C_TO_STRING(event), expires);
+    LinphoneCore *lc, LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body) {
+	auto ev = new EventSubscribe(L_GET_CPP_PTR_FROM_C_OBJECT(lc), Address::toCpp(resource)->getSharedFromThis(),
+	                             L_C_TO_STRING(event), expires);
 	ev->setUnrefWhenTerminated(true);
 	ev->send(body);
 	return ev->toC();
 }
 
 LinphoneEvent *linphone_core_create_subscribe_2(
-    LinphoneCore *lc, const LinphoneAddress *resource, LinphoneProxyConfig *cfg, const char *event, int expires) {
-	return (new EventSubscribe(L_GET_CPP_PTR_FROM_C_OBJECT(lc), resource, cfg, L_C_TO_STRING(event), expires))->toC();
+    LinphoneCore *lc, LinphoneAddress *resource, LinphoneProxyConfig *cfg, const char *event, int expires) {
+	return (new EventSubscribe(L_GET_CPP_PTR_FROM_C_OBJECT(lc), Address::toCpp(resource)->getSharedFromThis(), cfg,
+	                           L_C_TO_STRING(event), expires))
+	    ->toC();
 }
 
 // =============================================================================
@@ -387,24 +398,19 @@ const char *linphone_event_get_name(const LinphoneEvent *linphone_event) {
 }
 
 const LinphoneAddress *linphone_event_get_from(const LinphoneEvent *linphone_event) {
-	return Event::toCpp(linphone_event)->getFrom();
+	return Event::toCpp(linphone_event)->getFrom()->toC();
 }
 
 const LinphoneAddress *linphone_event_get_to(const LinphoneEvent *lev) {
-	return Event::toCpp(lev)->getTo();
+	return Event::toCpp(lev)->getTo()->toC();
 }
 
 const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *linphone_event) {
-	return Event::toCpp(linphone_event)->getResource();
+	return Event::toCpp(linphone_event)->getResource()->toC();
 }
 
 const LinphoneAddress *linphone_event_get_remote_contact(const LinphoneEvent *linphone_event) {
-	auto event_subscribe = dynamic_cast<const EventSubscribe *>(Event::toCpp(linphone_event));
-	if (!event_subscribe) {
-		log_bad_cast("linphone_event_get_remote_contact");
-		return NULL;
-	}
-	return event_subscribe->getRemoteContact();
+	return Event::toCpp(linphone_event)->getRemoteContact()->toC();
 }
 
 LinphoneCore *linphone_event_get_core(const LinphoneEvent *linphone_event) {
diff --git a/src/c-wrapper/api/c-nat-policy.cpp b/src/c-wrapper/api/c-nat-policy.cpp
index 45495bd8ed811fc83ba508e67de9e52e0af24d6b..0d44878d37ab9afb513b38e9fc7ece4896f720b1 100644
--- a/src/c-wrapper/api/c-nat-policy.cpp
+++ b/src/c-wrapper/api/c-nat-policy.cpp
@@ -19,7 +19,6 @@
  */
 
 #include "linphone/api/c-nat-policy.h"
-
 #include "core/core.h"
 #include "nat/nat-policy.h"
 
diff --git a/src/c-wrapper/api/c-participant-device-identity.cpp b/src/c-wrapper/api/c-participant-device-identity.cpp
index 7bf2ddf14ecb9dd18961f347189a62123f8ac001..b96e74066131f2db01449db6049013697777ea2c 100644
--- a/src/c-wrapper/api/c-participant-device-identity.cpp
+++ b/src/c-wrapper/api/c-participant-device-identity.cpp
@@ -43,7 +43,8 @@ using namespace LinphonePrivate;
 LinphoneParticipantDeviceIdentity *linphone_participant_device_identity_new(const LinphoneAddress *address,
                                                                             const char *name) {
 #ifdef HAVE_ADVANCED_IM
-	return ParticipantDeviceIdentity::createCObject(*L_GET_CPP_PTR_FROM_C_OBJECT(address), name);
+	return ParticipantDeviceIdentity::createCObject(
+	    Address::toCpp(const_cast<LinphoneAddress *>(address))->getSharedFromThis(), L_C_TO_STRING(name));
 #else
 	return NULL;
 #endif
@@ -58,21 +59,24 @@ linphone_participant_device_identity_ref(LinphoneParticipantDeviceIdentity *devi
 	return NULL;
 #endif
 }
+
 void linphone_participant_device_identity_unref(LinphoneParticipantDeviceIdentity *deviceIdentity) {
 #ifdef HAVE_ADVANCED_IM
 	belle_sip_object_unref(deviceIdentity);
 #endif
 }
+
 void linphone_participant_device_identity_set_capability_descriptor(LinphoneParticipantDeviceIdentity *deviceIdentity,
                                                                     const char *descriptor) {
 #ifdef HAVE_ADVANCED_IM
 	ParticipantDeviceIdentity::toCpp(deviceIdentity)->setCapabilityDescriptor(L_C_TO_STRING(descriptor));
 #endif
 }
+
 const char *linphone_participant_device_identity_get_capability_descriptor(
     const LinphoneParticipantDeviceIdentity *deviceIdentity) {
 #ifdef HAVE_ADVANCED_IM
-	return ParticipantDeviceIdentity::toCpp(deviceIdentity)->getCapabilityDescriptor().c_str();
+	return L_STRING_TO_C(ParticipantDeviceIdentity::toCpp(deviceIdentity)->getCapabilityDescriptor());
 #endif
 	return NULL;
 }
@@ -80,7 +84,7 @@ const char *linphone_participant_device_identity_get_capability_descriptor(
 const LinphoneAddress *
 linphone_participant_device_identity_get_address(const LinphoneParticipantDeviceIdentity *deviceIdentity) {
 #ifdef HAVE_ADVANCED_IM
-	return ParticipantDeviceIdentity::toCpp(deviceIdentity)->getLinphoneAddress();
+	return ParticipantDeviceIdentity::toCpp(deviceIdentity)->getAddress()->toC();
 #endif
 	return NULL;
 }
diff --git a/src/c-wrapper/api/c-participant-device.cpp b/src/c-wrapper/api/c-participant-device.cpp
index d6d49952c47daacd71d3489a581d53b14e632838..d6fd64a982dbbc4f372572e8fe8d621a5d03f06c 100644
--- a/src/c-wrapper/api/c-participant-device.cpp
+++ b/src/c-wrapper/api/c-participant-device.cpp
@@ -48,8 +48,8 @@ void linphone_participant_device_set_user_data(LinphoneParticipantDevice *partic
 }
 
 const LinphoneAddress *linphone_participant_device_get_address(const LinphoneParticipantDevice *participant_device) {
-	const LinphonePrivate::Address &addr = ParticipantDevice::toCpp(participant_device)->getAddress().asAddress();
-	return L_GET_C_BACK_PTR(&addr);
+	const auto &addr = ParticipantDevice::toCpp(participant_device)->getAddress();
+	return addr->toC();
 }
 
 void linphone_participant_device_set_state(LinphoneParticipantDevice *participant_device,
diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp
index 8d0e5786df7f7560016aa375d5aef17a68079666..528136a90c878247835f0e361bf40dc9dd01cffb 100644
--- a/src/c-wrapper/api/c-participant.cpp
+++ b/src/c-wrapper/api/c-participant.cpp
@@ -48,8 +48,8 @@ void linphone_participant_set_user_data(LinphoneParticipant *participant, void *
 }
 
 const LinphoneAddress *linphone_participant_get_address(const LinphoneParticipant *participant) {
-	const LinphonePrivate::Address &addr = LinphonePrivate::Participant::toCpp(participant)->getAddress().asAddress();
-	return L_GET_C_BACK_PTR(&addr);
+	const auto &addr = LinphonePrivate::Participant::toCpp(participant)->getAddress();
+	return addr->toC();
 }
 
 bool_t linphone_participant_is_admin(const LinphoneParticipant *participant) {
@@ -82,11 +82,9 @@ LinphoneParticipantDevice *linphone_participant_find_device_2(const LinphonePart
 
 LinphoneParticipantDevice *linphone_participant_find_device(const LinphoneParticipant *participant,
                                                             const LinphoneAddress *address) {
-	char *addrStr = linphone_address_as_string(address);
-	LinphonePrivate::Address deviceAddress(addrStr);
-	bctbx_free(addrStr);
 	std::shared_ptr<LinphonePrivate::ParticipantDevice> device =
-	    LinphonePrivate::Participant::toCpp(participant)->findDevice(deviceAddress);
+	    LinphonePrivate::Participant::toCpp(participant)
+	        ->findDevice(LinphonePrivate::Address::toCpp(const_cast<LinphoneAddress *>(address))->getSharedFromThis());
 	if (device) {
 		return device->toC();
 	}
diff --git a/src/c-wrapper/api/c-push-notification-message.cpp b/src/c-wrapper/api/c-push-notification-message.cpp
index 661a0d1e778eea2cc43d3a28a816684a7e1f3ff7..f843075d7a608ed8b6288f558aa8e7fb560dfce7 100644
--- a/src/c-wrapper/api/c-push-notification-message.cpp
+++ b/src/c-wrapper/api/c-push-notification-message.cpp
@@ -75,16 +75,15 @@ const char *linphone_push_notification_message_get_subject(const LinphonePushNot
 }
 
 const LinphoneAddress *linphone_push_notification_message_get_from_addr(const LinphonePushNotificationMessage *msg) {
-	return linphone_address_new(PushNotificationMessage::toCpp(msg)->getFromAddr()->asString().c_str());
+	return PushNotificationMessage::toCpp(msg)->getFromAddr()->toC();
 }
 
 const LinphoneAddress *linphone_push_notification_message_get_local_addr(const LinphonePushNotificationMessage *msg) {
-	return linphone_address_new(PushNotificationMessage::toCpp(msg)->getLocalAddr()->asString().c_str());
+	return PushNotificationMessage::toCpp(msg)->getLocalAddr()->toC();
 }
 
 const LinphoneAddress *linphone_push_notification_message_get_peer_addr(const LinphonePushNotificationMessage *msg) {
-	return linphone_address_new(PushNotificationMessage::toCpp(msg)->getPeerAddr()->asString().c_str());
-	;
+	return PushNotificationMessage::toCpp(msg)->getPeerAddr()->toC();
 }
 
 bool_t linphone_push_notification_message_is_icalendar(const LinphonePushNotificationMessage *msg) {
diff --git a/src/c-wrapper/api/c-recorder-params.cpp b/src/c-wrapper/api/c-recorder-params.cpp
index c881bde36456e88771a79ea3d4729b9e7f48bc44..69570055025d0ac8830dfb6d249f1b3962c6473f 100644
--- a/src/c-wrapper/api/c-recorder-params.cpp
+++ b/src/c-wrapper/api/c-recorder-params.cpp
@@ -22,6 +22,7 @@
 
 #include "c-wrapper/internal/c-tools.h"
 #include "call/audio-device/audio-device.h"
+#include "linphone/api/c-recorder-params.h"
 #include "recorder/recorder-params.h"
 
 // =============================================================================
diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h
index 1946cb1b1673baca37da41737430b06190196a26..987221812508e8f610af5262693360b5ced2afc8 100644
--- a/src/c-wrapper/c-wrapper.h
+++ b/src/c-wrapper/c-wrapper.h
@@ -165,7 +165,6 @@ private:
  * The invocation of callbacks can be done with the LINPHONE_HYBRID_OBJECT_INVOKE_CBS() macro.
  */
 template <typename _CppCbsType>
-
 class LINPHONE_PUBLIC CallbacksHolder {
 public:
 	void addCallbacks(const std::shared_ptr<_CppCbsType> &callbacks) {
@@ -256,33 +255,65 @@ LINPHONE_END_NAMESPACE
 
 #define L_REGISTER_ID(CPP_TYPE, C_TYPE) BELLE_SIP_TYPE_ID(Linphone##C_TYPE),
 
+// clang-format off
 /* Only pure belle_sip_object_t defined in C shall be declared here.
  * WARNING HybridObject<> derived don't need to be declared here */
 BELLE_SIP_DECLARE_TYPES_BEGIN(linphone, 10000)
 L_REGISTER_TYPES(L_REGISTER_ID)
-BELLE_SIP_TYPE_ID(LinphoneAccountCreator), BELLE_SIP_TYPE_ID(LinphoneAccountCreatorCbs),
-    BELLE_SIP_TYPE_ID(LinphoneAccountCreatorService), BELLE_SIP_TYPE_ID(LinphoneBuffer),
-    BELLE_SIP_TYPE_ID(LinphoneCallStats), BELLE_SIP_TYPE_ID(LinphoneChatMessageCbs),
-    BELLE_SIP_TYPE_ID(LinphoneChatRoomCbs), BELLE_SIP_TYPE_ID(LinphoneConfig),
-    BELLE_SIP_TYPE_ID(LinphoneContactProvider), BELLE_SIP_TYPE_ID(LinphoneContactSearch),
-    BELLE_SIP_TYPE_ID(LinphoneCoreCbs), BELLE_SIP_TYPE_ID(LinphoneErrorInfo), BELLE_SIP_TYPE_ID(LinphoneFactory),
-    BELLE_SIP_TYPE_ID(LinphoneFriend), BELLE_SIP_TYPE_ID(LinphoneFriendCbs), BELLE_SIP_TYPE_ID(LinphoneFriendList),
-    BELLE_SIP_TYPE_ID(LinphoneFriendListCbs), BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngine),
-    BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngineCbs), BELLE_SIP_TYPE_ID(LinphoneImNotifPolicy),
-    BELLE_SIP_TYPE_ID(LinphoneInfoMessage), BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider),
-    BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch), BELLE_SIP_TYPE_ID(LinphoneLoggingService),
-    BELLE_SIP_TYPE_ID(LinphoneLoggingServiceCbs), BELLE_SIP_TYPE_ID(LinphoneMagicSearchCbs),
-    BELLE_SIP_TYPE_ID(LinphoneParticipant), BELLE_SIP_TYPE_ID(LinphoneParticipantDevice),
-    BELLE_SIP_TYPE_ID(LinphoneParticipantDeviceCbs), BELLE_SIP_TYPE_ID(LinphonePlayer),
-    BELLE_SIP_TYPE_ID(LinphonePlayerCbs), BELLE_SIP_TYPE_ID(LinphonePresenceActivity),
-    BELLE_SIP_TYPE_ID(LinphonePresenceModel), BELLE_SIP_TYPE_ID(LinphonePresenceNote),
-    BELLE_SIP_TYPE_ID(LinphonePresencePerson), BELLE_SIP_TYPE_ID(LinphonePresenceService),
-    BELLE_SIP_TYPE_ID(LinphoneProxyConfig), BELLE_SIP_TYPE_ID(LinphoneRange), BELLE_SIP_TYPE_ID(LinphoneRecorder),
-    BELLE_SIP_TYPE_ID(LinphoneRecorderParams), BELLE_SIP_TYPE_ID(LinphoneTransports), BELLE_SIP_TYPE_ID(LinphoneTunnel),
-    BELLE_SIP_TYPE_ID(LinphoneTunnelConfig), BELLE_SIP_TYPE_ID(LinphoneVcard),
-    BELLE_SIP_TYPE_ID(LinphoneVideoActivationPolicy), BELLE_SIP_TYPE_ID(LinphoneVideoDefinition),
-    BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequest), BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs),
-    BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession) BELLE_SIP_DECLARE_TYPES_END
+BELLE_SIP_TYPE_ID(LinphoneAccount),
+BELLE_SIP_TYPE_ID(LinphoneAccountParams),
+BELLE_SIP_TYPE_ID(LinphoneAccountCreator),
+BELLE_SIP_TYPE_ID(LinphoneAccountCreatorCbs),
+BELLE_SIP_TYPE_ID(LinphoneAccountCreatorService),
+BELLE_SIP_TYPE_ID(LinphoneBuffer),
+BELLE_SIP_TYPE_ID(LinphoneCallStats),
+BELLE_SIP_TYPE_ID(LinphoneChatMessageCbs),
+BELLE_SIP_TYPE_ID(LinphoneChatRoomCbs),
+BELLE_SIP_TYPE_ID(LinphoneConfig),
+BELLE_SIP_TYPE_ID(LinphoneContactProvider),
+BELLE_SIP_TYPE_ID(LinphoneContactSearch),
+BELLE_SIP_TYPE_ID(LinphoneCoreCbs),
+BELLE_SIP_TYPE_ID(LinphoneErrorInfo),
+BELLE_SIP_TYPE_ID(LinphoneFactory),
+BELLE_SIP_TYPE_ID(LinphoneFriend),
+BELLE_SIP_TYPE_ID(LinphoneFriendCbs),
+BELLE_SIP_TYPE_ID(LinphoneFriendList),
+BELLE_SIP_TYPE_ID(LinphoneFriendListCbs),
+BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngine),
+BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngineCbs),
+BELLE_SIP_TYPE_ID(LinphoneImNotifPolicy),
+BELLE_SIP_TYPE_ID(LinphoneInfoMessage),
+BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider),
+BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch),
+BELLE_SIP_TYPE_ID(LinphoneLoggingService),
+BELLE_SIP_TYPE_ID(LinphoneLoggingServiceCbs),
+BELLE_SIP_TYPE_ID(LinphoneMagicSearchCbs),
+BELLE_SIP_TYPE_ID(LinphoneParticipant),
+BELLE_SIP_TYPE_ID(LinphoneParticipantDevice),
+BELLE_SIP_TYPE_ID(LinphoneParticipantDeviceCbs),
+BELLE_SIP_TYPE_ID(LinphonePayloadType),
+BELLE_SIP_TYPE_ID(LinphonePlayer),
+BELLE_SIP_TYPE_ID(LinphonePlayerCbs),
+BELLE_SIP_TYPE_ID(LinphonePresenceActivity),
+BELLE_SIP_TYPE_ID(LinphonePresenceModel),
+BELLE_SIP_TYPE_ID(LinphonePresenceNote),
+BELLE_SIP_TYPE_ID(LinphonePresencePerson),
+BELLE_SIP_TYPE_ID(LinphonePresenceService),
+BELLE_SIP_TYPE_ID(LinphoneProxyConfig),
+BELLE_SIP_TYPE_ID(LinphoneRange),
+BELLE_SIP_TYPE_ID(LinphoneRecorder),
+BELLE_SIP_TYPE_ID(LinphoneRecorderParams),
+BELLE_SIP_TYPE_ID(LinphoneTransports),
+BELLE_SIP_TYPE_ID(LinphoneTunnel),
+BELLE_SIP_TYPE_ID(LinphoneTunnelConfig),
+BELLE_SIP_TYPE_ID(LinphoneVcard),
+BELLE_SIP_TYPE_ID(LinphoneVideoActivationPolicy),
+BELLE_SIP_TYPE_ID(LinphoneVideoDefinition),
+BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequest),
+BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs),
+BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession)
+BELLE_SIP_DECLARE_TYPES_END
+// clang-format on
 
 #undef L_REGISTER_ID
 
diff --git a/src/c-wrapper/internal/c-sal.h b/src/c-wrapper/internal/c-sal.h
index a3fddfff1d279f8a5c5dc2a88fbace0052189226..47d8ec44a620127d668041804e4850cb7d6e2613 100644
--- a/src/c-wrapper/internal/c-sal.h
+++ b/src/c-wrapper/internal/c-sal.h
@@ -27,12 +27,15 @@
 #ifndef _L_C_SAL_H_
 #define _L_C_SAL_H_
 
+#ifdef __cplusplus
+#include <map>
+#endif
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "bctoolbox/crypto.h"
-#include "bctoolbox/map.h"
 #include "belle-sip/belle-sip.h"
 #include "linphone/types.h"
 #include "mediastreamer2/mediastream.h"
@@ -147,6 +150,7 @@ extern "C" {
 const char *sal_transport_to_string(SalTransport transport);
 SalTransport sal_transport_parse(const char *);
 /* Address manipulation API*/
+SalAddress *sal_address_new_empty(void);
 LINPHONE_PUBLIC SalAddress *sal_address_new(const char *uri);
 LINPHONE_PUBLIC SalAddress *sal_address_clone(const SalAddress *addr);
 SalAddress *sal_address_ref(SalAddress *addr);
@@ -171,6 +175,7 @@ void sal_address_set_port(SalAddress *uri, int port);
 void sal_address_clean(SalAddress *addr);
 char *sal_address_as_string(const SalAddress *u);
 char *sal_address_as_string_uri_only(const SalAddress *u);
+SalAddress *sal_address_new_uri_only(const SalAddress *addr);
 LINPHONE_PUBLIC void sal_address_set_param(SalAddress *u, const char *name, const char *value);
 void sal_address_set_transport(SalAddress *addr, SalTransport transport);
 void sal_address_set_transport_name(SalAddress *addr, const char *transport);
@@ -183,7 +188,9 @@ void sal_address_set_uri_param(SalAddress *addr, const char *name, const char *v
 void sal_address_set_uri_params(SalAddress *addr, const char *params);
 bool_t sal_address_has_uri_param(const SalAddress *addr, const char *name);
 const char *sal_address_get_uri_param(const SalAddress *addr, const char *name);
-bctbx_map_t *sal_address_get_uri_params(const SalAddress *addr);
+#ifdef __cplusplus
+void sal_address_get_uri_params(const SalAddress *addr, std::map<std::string, std::string> &params);
+#endif // __cplusplus
 void sal_address_remove_uri_param(const SalAddress *addr, const char *name);
 bool_t sal_address_is_ipv6(const SalAddress *addr);
 bool_t sal_address_is_sip(const SalAddress *addr);
@@ -194,6 +201,8 @@ const char *sal_address_get_header(const SalAddress *addr, const char *name);
 
 int sal_address_equals(const SalAddress *addr_a, const SalAddress *addr_b);
 
+void sal_address_clean_params(const SalAddress *addr);
+
 void sal_set_log_handler(BctbxLogFunc log_handler);
 
 #ifdef __cplusplus
@@ -217,6 +226,18 @@ const char *sal_media_record_to_string(SalMediaRecord record);
 }
 #endif
 
+#ifdef __cplusplus
+inline std::ostream &operator<<(std::ostream &ostr, SalStreamType type) {
+	ostr << sal_stream_type_to_string(type);
+	return ostr;
+}
+
+inline std::ostream &operator<<(std::ostream &ostr, SalMediaProto proto) {
+	ostr << sal_media_proto_to_string(proto);
+	return ostr;
+}
+#endif // __cplusplus
+
 #define SAL_ENDPOINT_CANDIDATE_MAX 2
 
 typedef enum {
@@ -486,6 +507,7 @@ SalCustomHeader *sal_custom_header_ref(SalCustomHeader *ch);
 LINPHONE_PUBLIC void sal_custom_header_unref(SalCustomHeader *ch);
 LINPHONE_PUBLIC SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value);
 const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name);
+bool_t sal_custom_sdp_attribute_is_present(const SalCustomSdpAttribute *csa, const char *name);
 SalCustomHeader *sal_custom_header_remove(SalCustomHeader *ch, const char *name);
 void sal_custom_header_free(SalCustomHeader *ch);
 SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch);
diff --git a/src/call/call-log.cpp b/src/call/call-log.cpp
index 90bd6cb630df34a01bded3d13c260c94bdbd5143..01304b9d2c0c6968efe971662fdf52b3bc0c71d6 100644
--- a/src/call/call-log.cpp
+++ b/src/call/call-log.cpp
@@ -35,11 +35,14 @@ using namespace std;
 
 LINPHONE_BEGIN_NAMESPACE
 
-CallLog::CallLog(shared_ptr<Core> core, LinphoneCallDir direction, LinphoneAddress *from, LinphoneAddress *to)
+CallLog::CallLog(shared_ptr<Core> core,
+                 LinphoneCallDir direction,
+                 const std::shared_ptr<Address> &from,
+                 const std::shared_ptr<Address> &to)
     : CoreAccessor(core) {
 	mDirection = direction;
-	mFrom = from;
-	mTo = to;
+	setFromAddress(from);
+	setToAddress(to);
 
 	mStartTime = std::time(nullptr);
 	mStartDate = Utils::getTimeAsString("%c", mStartTime);
@@ -50,8 +53,6 @@ CallLog::CallLog(shared_ptr<Core> core, LinphoneCallDir direction, LinphoneAddre
 }
 
 CallLog::~CallLog() {
-	if (mFrom != nullptr) linphone_address_unref(mFrom);
-	if (mTo != nullptr) linphone_address_unref(mTo);
 	if (mReporting.reports[LINPHONE_CALL_STATS_AUDIO] != nullptr)
 		linphone_reporting_destroy(mReporting.reports[LINPHONE_CALL_STATS_AUDIO]);
 	if (mReporting.reports[LINPHONE_CALL_STATS_VIDEO] != nullptr)
@@ -87,22 +88,20 @@ void CallLog::setQuality(float quality) {
 	mQuality = quality;
 }
 
-const LinphoneAddress *CallLog::getFromAddress() const {
+const std::shared_ptr<Address> &CallLog::getFromAddress() const {
 	return mFrom;
 }
 
-void CallLog::setFromAddress(LinphoneAddress *address) {
-	if (mFrom) linphone_address_unref(mFrom);
-	mFrom = address;
+void CallLog::setFromAddress(const std::shared_ptr<Address> &address) {
+	mFrom = address->clone()->toSharedPtr();
 }
 
-const LinphoneAddress *CallLog::getToAddress() const {
+const std::shared_ptr<Address> &CallLog::getToAddress() const {
 	return mTo;
 }
 
-void CallLog::setToAddress(LinphoneAddress *address) {
-	if (mTo) linphone_address_unref(mTo);
-	mTo = address;
+void CallLog::setToAddress(const std::shared_ptr<Address> &address) {
+	mTo = address->clone()->toSharedPtr();
 }
 
 const string &CallLog::getCallId() const {
@@ -167,17 +166,15 @@ void CallLog::setErrorInfo(LinphoneErrorInfo *errorInfo) {
 	mErrorInfo = errorInfo;
 }
 
-const LinphoneAddress *CallLog::getRemoteAddress() const {
+const std::shared_ptr<Address> &CallLog::getRemoteAddress() const {
 	return (mDirection == LinphoneCallIncoming) ? mFrom : mTo;
 }
 
-void CallLog::setRemoteAddress(const LinphoneAddress *remoteAddress) {
+void CallLog::setRemoteAddress(const std::shared_ptr<Address> &remoteAddress) {
 	if (mDirection == LinphoneCallIncoming) {
-		if (mFrom) linphone_address_unref(mFrom);
-		mFrom = linphone_address_clone(remoteAddress);
+		setFromAddress(remoteAddress);
 	} else {
-		if (mTo) linphone_address_unref(mTo);
-		mTo = linphone_address_clone(remoteAddress);
+		setToAddress(remoteAddress);
 	}
 }
 
@@ -189,7 +186,7 @@ void CallLog::setUserData(void *userData) {
 	mUserData = userData;
 }
 
-const LinphoneAddress *CallLog::getLocalAddress() const {
+const std::shared_ptr<Address> &CallLog::getLocalAddress() const {
 	return (mDirection == LinphoneCallIncoming) ? mTo : mFrom;
 }
 
@@ -229,13 +226,7 @@ string CallLog::toString() const {
 	os << (mDirection == LinphoneCallIncoming ? "Incoming call" : "Outgoing call") << " with call-id: " << mCallId
 	   << " at " << mStartDate << "\n";
 
-	char *from = linphone_address_as_string(mFrom);
-	char *to = linphone_address_as_string(mTo);
-
-	os << "From: " << from << "\nTo: " << to << "\n";
-
-	bctbx_free(from);
-	bctbx_free(to);
+	os << "From: " << *mFrom << "\nTo: " << *mTo << "\n";
 
 	string status;
 	switch (mStatus) {
diff --git a/src/call/call-log.h b/src/call/call-log.h
index d6c9219333cf504b83007ff97692bfeae1d4ab9a..5e38f18ac9382b1d2c55b6e62d19f3aae6a404d5 100644
--- a/src/call/call-log.h
+++ b/src/call/call-log.h
@@ -35,7 +35,10 @@ LINPHONE_BEGIN_NAMESPACE
 
 class LINPHONE_PUBLIC CallLog : public bellesip::HybridObject<LinphoneCallLog, CallLog>, public CoreAccessor {
 public:
-	CallLog(std::shared_ptr<Core> core, LinphoneCallDir direction, LinphoneAddress *from, LinphoneAddress *to);
+	CallLog(std::shared_ptr<Core> core,
+	        LinphoneCallDir direction,
+	        const std::shared_ptr<Address> &from,
+	        const std::shared_ptr<Address> &to);
 	~CallLog();
 
 	LinphoneCallDir getDirection() const;
@@ -47,11 +50,11 @@ public:
 	float getQuality() const;
 	void setQuality(float quality);
 
-	const LinphoneAddress *getFromAddress() const;
-	void setFromAddress(LinphoneAddress *address);
+	const std::shared_ptr<Address> &getFromAddress() const;
+	void setFromAddress(const std::shared_ptr<Address> &address);
 
-	const LinphoneAddress *getToAddress() const;
-	void setToAddress(LinphoneAddress *address);
+	const std::shared_ptr<Address> &getToAddress() const;
+	void setToAddress(const std::shared_ptr<Address> &address);
 
 	const std::string &getCallId() const;
 	void setCallId(const std::string &callId);
@@ -76,13 +79,13 @@ public:
 	const LinphoneErrorInfo *getErrorInfo() const;
 	void setErrorInfo(LinphoneErrorInfo *errorInfo);
 
-	const LinphoneAddress *getRemoteAddress() const;
-	void setRemoteAddress(const LinphoneAddress *remoteAddress);
+	const std::shared_ptr<Address> &getRemoteAddress() const;
+	void setRemoteAddress(const std::shared_ptr<Address> &remoteAddress);
 
 	void *getUserData() const;
 	void setUserData(void *userData);
 
-	const LinphoneAddress *getLocalAddress() const;
+	const std::shared_ptr<Address> &getLocalAddress() const;
 	const std::string &getStartTimeString() const;
 
 	LinphoneQualityReporting *getQualityReporting();
@@ -99,8 +102,8 @@ private:
 
 	LinphoneCallDir mDirection;                       /**< The direction of the call*/
 	LinphoneCallStatus mStatus = LinphoneCallAborted; /**< The status of the call*/
-	LinphoneAddress *mFrom = nullptr;                 /**<Originator of the call as a LinphoneAddress object*/
-	LinphoneAddress *mTo = nullptr;                   /**<Destination of the call as a LinphoneAddress object*/
+	std::shared_ptr<Address> mFrom = nullptr;         /**<Originator of the call as a LinphoneAddress object*/
+	std::shared_ptr<Address> mTo = nullptr;           /**<Destination of the call as a LinphoneAddress object*/
 	LinphoneQualityReporting mReporting = {};
 	LinphoneErrorInfo *mErrorInfo = nullptr;
 
diff --git a/src/call/call.cpp b/src/call/call.cpp
index 8ec64252cf3f9761ea601bca15923d60fb58273f..0b33d2d7e4628eb320043897f008157d9fbd4745 100644
--- a/src/call/call.cpp
+++ b/src/call/call.cpp
@@ -48,7 +48,7 @@ shared_ptr<CallSession> Call::getActiveSession() const {
 
 shared_ptr<AbstractChatRoom> Call::getChatRoom() {
 	if ((getState() != CallSession::State::End) && (getState() != CallSession::State::Released)) {
-		mChatRoom = getCore()->getOrCreateBasicChatRoom(getLocalAddress(), *getRemoteAddress());
+		mChatRoom = getCore()->getOrCreateBasicChatRoom(getLocalAddress(), getRemoteAddress());
 		if (mChatRoom) {
 			lInfo() << "Setting call id [" << getLog()->getCallId() << "] to ChatRoom [" << mChatRoom << "]";
 			mChatRoom->getPrivate()->setCallId(getLog()->getCallId());
@@ -57,8 +57,8 @@ shared_ptr<AbstractChatRoom> Call::getChatRoom() {
 	return mChatRoom;
 }
 
-LinphoneProxyConfig *Call::getDestProxy() const {
-	return getActiveSession()->getPrivate()->getDestProxy();
+const shared_ptr<Account> &Call::getDestAccount() const {
+	return getActiveSession()->getPrivate()->getDestAccount();
 }
 
 /* This a test-only method.*/
@@ -220,7 +220,7 @@ void Call::pauseForTransfer() {
 	static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->pauseForTransfer();
 }
 
-int Call::startInvite(const Address *destination, const std::string subject, const Content *content) {
+int Call::startInvite(const std::shared_ptr<Address> &destination, const std::string subject, const Content *content) {
 	return getActiveSession()->startInvite(destination, subject, content);
 }
 
@@ -261,7 +261,7 @@ void Call::createPlayer() const {
 
 // -----------------------------------------------------------------------------
 void Call::terminateBecauseOfLostMedia() {
-	lInfo() << "Call [" << this << "]: Media connectivity with " << getRemoteAddress()->asString()
+	lInfo() << "Call [" << this << "]: Media connectivity with " << getRemoteAddress()->toString()
 	        << " is lost, call is going to be terminated";
 	static_pointer_cast<MediaSession>(getActiveSession())->terminateBecauseOfLostMedia();
 }
@@ -337,8 +337,8 @@ void Call::onCallSessionEarlyFailed(const shared_ptr<CallSession> &session, Linp
 		session->setStateToEnded();
 	}
 
-	getCore()->reportEarlyCallFailed(log->getDirection(), linphone_address_clone(log->getFromAddress()),
-	                                 linphone_address_clone(log->getToAddress()), ei, log->getCallId());
+	getCore()->reportEarlyCallFailed(log->getDirection(), log->getFromAddress(), log->getToAddress(), ei,
+	                                 log->getCallId());
 
 	cleanupSessionAndUnrefCObjectCall();
 }
@@ -390,6 +390,22 @@ void Call::onCallSessionStateChanged(const shared_ptr<CallSession> &session,
                                      const string &message) {
 	LinphoneCore *lc = getCore()->getCCore();
 	const auto op = session->getPrivate()->getOp();
+
+	bool remoteContactIsFocus = false;
+	std::shared_ptr<MediaConference::Conference> conference = nullptr;
+	if (op) {
+		if (op->getRemoteContactAddress()) {
+			Address remoteContactAddress;
+			remoteContactAddress.setImpl(op->getRemoteContactAddress());
+			remoteContactIsFocus = (remoteContactAddress.hasParam("isfocus"));
+		}
+
+		if (!op->getTo().empty()) {
+			const auto to = Address::create(op->getTo());
+			conference = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(ConferenceId(to, to));
+		}
+	}
+
 	switch (state) {
 		case CallSession::State::OutgoingInit:
 		case CallSession::State::IncomingReceived:
@@ -407,8 +423,6 @@ void Call::onCallSessionStateChanged(const shared_ptr<CallSession> &session,
 			break;
 		case CallSession::State::Paused:
 			if (!getConference() && op && op->getRemoteContactAddress()) {
-				auto conference = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(
-				    ConferenceId(ConferenceAddress(Address(op->getTo())), ConferenceAddress(Address(op->getTo()))));
 				if (!op->getTo().empty() && conference) {
 					// This code is usually executed when the following scenario occurs:
 					// - ICE is enabled
@@ -420,26 +434,18 @@ void Call::onCallSessionStateChanged(const shared_ptr<CallSession> &session,
 			}
 			break;
 		case CallSession::State::UpdatedByRemote: {
-			if (op && op->getRemoteContactAddress() && !getConference()) {
-				char *remoteContactAddressStr = sal_address_as_string(op->getRemoteContactAddress());
-				Address remoteContactAddress(remoteContactAddressStr);
-				ms_free(remoteContactAddressStr);
-
-				if (remoteContactAddress.hasParam("isfocus")) {
-					// Check if the request was sent by the focus (remote conference)
-					createRemoteConference(session);
-					auto conference = getConference() ? MediaConference::Conference::toCpp(getConference()) : nullptr;
-					if (conference && conference->getState() == ConferenceInterface::State::CreationPending) {
-						conference->finalizeCreation();
-					}
+			if (op && !getConference() && remoteContactIsFocus) {
+				// Check if the request was sent by the focus (remote conference)
+				createRemoteConference(session);
+				auto conference = getConference() ? MediaConference::Conference::toCpp(getConference()) : nullptr;
+				if (conference && conference->getState() == ConferenceInterface::State::CreationPending) {
+					conference->finalizeCreation();
 				}
 			}
 		} break;
 		case CallSession::State::Connected:
 		case CallSession::State::StreamsRunning: {
 			if (op && !getConference()) {
-				auto conference = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(
-				    ConferenceId(ConferenceAddress(Address(op->getTo())), ConferenceAddress(Address(op->getTo()))));
 				if (!op->getTo().empty() && conference) {
 					const auto &resourceList = op->getContentInRemote(ContentType::ResourceLists);
 					if (resourceList.isEmpty()) {
@@ -447,16 +453,12 @@ void Call::onCallSessionStateChanged(const shared_ptr<CallSession> &session,
 					}
 				} else if (op->getRemoteContactAddress()) {
 					const auto &confId = session->getPrivate()->getConferenceId();
-					char *remoteContactAddressStr = sal_address_as_string(op->getRemoteContactAddress());
-					Address remoteContactAddress(remoteContactAddressStr);
-					ms_free(remoteContactAddressStr);
-
 					// Check if the request was sent by the focus
-					if (remoteContactAddress.hasParam("isfocus")) {
+					if (remoteContactIsFocus) {
 						createRemoteConference(session);
 					} else if (!confId.empty()) {
 						auto localAddress = session->getContactAddress();
-						if (localAddress.isValid()) {
+						if (localAddress && localAddress->isValid()) {
 							ConferenceId localConferenceId = ConferenceId(localAddress, localAddress);
 							conference = getCore()->findAudioVideoConference(localConferenceId, false);
 							if (conference) {
@@ -503,9 +505,8 @@ void Call::createRemoteConference(const shared_ptr<CallSession> &session) {
 	// If the call is for a conference stored in the core, then add call to conference once ICE negotiations are
 	// terminated
 	const auto op = session->getPrivate()->getOp();
-	char *remoteContactAddressStr = sal_address_as_string(op->getRemoteContactAddress());
-	Address remoteContactAddress(remoteContactAddressStr);
-	ms_free(remoteContactAddressStr);
+	std::shared_ptr<Address> remoteContactAddress = Address::create();
+	remoteContactAddress->setImpl(op->getRemoteContactAddress());
 	ConferenceId conferenceId = ConferenceId(remoteContactAddress, getLocalAddress());
 
 	const auto &conference = getCore()->findAudioVideoConference(conferenceId, false);
@@ -513,8 +514,8 @@ void Call::createRemoteConference(const shared_ptr<CallSession> &session) {
 	std::shared_ptr<MediaConference::RemoteConference> remoteConference = nullptr;
 
 	if (conference) {
-		lInfo() << "Attaching call (local address " << session->getLocalAddress().asString() << " remote address "
-		        << session->getRemoteAddress()->asString() << ") to conference " << conference->getConferenceAddress()
+		lInfo() << "Attaching call (local address " << session->getLocalAddress()->toString() << " remote address "
+		        << session->getRemoteAddress()->toString() << ") to conference " << conference->getConferenceAddress()
 		        << " ID " << conferenceId;
 		remoteConference = dynamic_pointer_cast<MediaConference::RemoteConference>(conference);
 		if (remoteConference) {
@@ -543,12 +544,12 @@ void Call::createRemoteConference(const shared_ptr<CallSession> &session) {
 				time_t endTime = startTime + static_cast<time_t>(duration) * 60;
 				confParams->setEndTime(endTime);
 			}
-			std::list<IdentityAddress> invitees{conferenceInfo->getOrganizerAddress()};
+			std::list<std::shared_ptr<Address>> invitees{conferenceInfo->getOrganizerAddress()};
 			for (const auto &participant : conferenceInfo->getParticipants()) {
 				invitees.push_back(participant.first);
 			}
 
-			const ConferenceAddress confAddr(conferenceInfo->getUri());
+			const std::shared_ptr<Address> confAddr = conferenceInfo->getUri();
 			const ConferenceId confId(confAddr, session->getLocalAddress());
 			remoteConference = std::shared_ptr<MediaConference::RemoteConference>(
 			    new MediaConference::RemoteConference(getCore(), session, confAddr, confId, invitees, nullptr,
@@ -561,7 +562,7 @@ void Call::createRemoteConference(const shared_ptr<CallSession> &session) {
 			confParams->setEndTime(remoteParams->getPrivate()->getEndTime());
 			auto organizer = Utils::getSipFragAddress(sipfrag);
 			auto invitees = Utils::parseResourceLists(resourceList);
-			invitees.push_back(IdentityAddress(organizer));
+			invitees.push_back(Address::create(organizer));
 			remoteConference = std::shared_ptr<MediaConference::RemoteConference>(
 			    new MediaConference::RemoteConference(getCore(), session, remoteContactAddress, conferenceId, invitees,
 			                                          nullptr, confParams),
@@ -582,8 +583,8 @@ void Call::createRemoteConference(const shared_ptr<CallSession> &session) {
 	setConference(remoteConference->toC());
 
 	// Record conf-id to be used later when terminating the remote conference
-	if (remoteContactAddress.hasUriParam("conf-id")) {
-		setConferenceId(remoteContactAddress.getUriParamValue("conf-id"));
+	if (remoteContactAddress->hasUriParam("conf-id")) {
+		setConferenceId(remoteContactAddress->getUriParamValue("conf-id"));
 	}
 }
 
@@ -779,8 +780,8 @@ void Call::onRemoteRecording(BCTBX_UNUSED(const std::shared_ptr<CallSession> &se
 
 Call::Call(shared_ptr<Core> core,
            LinphoneCallDir direction,
-           const Address &from,
-           const Address &to,
+           const std::shared_ptr<Address> &from,
+           const std::shared_ptr<Address> &to,
            LinphoneProxyConfig *cfg,
            SalCallOp *op,
            const MediaSessionParams *msp)
@@ -791,7 +792,7 @@ Call::Call(shared_ptr<Core> core,
 	mBgTask.setName("Liblinphone call notification");
 
 	// create session
-	mParticipant = Participant::create(nullptr, IdentityAddress((direction == LinphoneCallIncoming) ? to : from));
+	mParticipant = Participant::create(nullptr, ((direction == LinphoneCallIncoming) ? to : from));
 	mParticipant->createSession(getCore(), msp, TRUE, this);
 	mParticipant->getSession()->configure(direction, cfg, op, from, to);
 
@@ -841,12 +842,12 @@ void Call::configureSoundCardsFromCore(const MediaSessionParams *msp) {
 }
 
 void Call::configure(LinphoneCallDir direction,
-                     const Address &from,
-                     const Address &to,
+                     const std::shared_ptr<Address> &from,
+                     const std::shared_ptr<Address> &to,
                      LinphoneProxyConfig *cfg,
                      SalCallOp *op,
                      BCTBX_UNUSED(const MediaSessionParams *msp)) {
-	mParticipant->configure(nullptr, IdentityAddress((direction == LinphoneCallIncoming) ? to : from));
+	mParticipant->configure(nullptr, (direction == LinphoneCallIncoming) ? to : from);
 	mParticipant->getSession()->configure(direction, cfg, op, from, to);
 }
 
@@ -908,8 +909,8 @@ LinphoneStatus Call::redirect(const string &redirectUri) {
 	return getActiveSession()->redirect(redirectUri);
 }
 
-LinphoneStatus Call::redirect(const Address &redirectAddress) {
-	return getActiveSession()->redirect(redirectAddress);
+LinphoneStatus Call::redirect(const std::shared_ptr<Address> &redirectAddress) {
+	return getActiveSession()->redirect(*redirectAddress);
 }
 
 LinphoneStatus Call::resume() {
@@ -982,7 +983,7 @@ LinphoneStatus Call::transfer(const string &dest) {
 	return getActiveSession()->transfer(dest);
 }
 
-LinphoneStatus Call::transfer(const Address &dest) {
+LinphoneStatus Call::transfer(const std::shared_ptr<Address> &dest) {
 	return getActiveSession()->transfer(dest);
 }
 
@@ -1060,7 +1061,7 @@ LinphoneCallDir Call::getDirection() const {
 	return getActiveSession()->getDirection();
 }
 
-const Address &Call::getDiversionAddress() const {
+const std::shared_ptr<Address> Call::getDiversionAddress() const {
 	return getActiveSession()->getDiversionAddress();
 }
 
@@ -1072,7 +1073,7 @@ const LinphoneErrorInfo *Call::getErrorInfo() const {
 	return getActiveSession()->getErrorInfo();
 }
 
-const Address &Call::getLocalAddress() const {
+const std::shared_ptr<Address> Call::getLocalAddress() const {
 	return getActiveSession()->getLocalAddress();
 }
 
@@ -1130,19 +1131,19 @@ shared_ptr<Call> Call::getReferer() const {
 	return nullptr;
 }
 
-const string &Call::getReferTo() const {
+const string Call::getReferTo() const {
 	return getActiveSession()->getReferTo();
 }
 
-const Address &Call::getReferToAddress() const {
+const std::shared_ptr<Address> &Call::getReferToAddress() const {
 	return getActiveSession()->getReferToAddress();
 }
 
-const Address *Call::getRemoteAddress() const {
+const std::shared_ptr<Address> Call::getRemoteAddress() const {
 	return getActiveSession()->getRemoteAddress();
 }
 
-const Address *Call::getRemoteContactAddress() const {
+const std::shared_ptr<Address> Call::getRemoteContactAddress() const {
 	return getActiveSession()->getRemoteContactAddress();
 }
 
@@ -1191,7 +1192,7 @@ LinphoneCallStats *Call::getTextStats() const {
 	return static_pointer_cast<const MediaSession>(getActiveSession())->getTextStats();
 }
 
-const Address &Call::getToAddress() const {
+const std::shared_ptr<Address> Call::getToAddress() const {
 	return getActiveSession()->getToAddress();
 }
 
diff --git a/src/call/call.h b/src/call/call.h
index 0a3858fcd2607bcda1fdc29ce9bbb50ca46db4b0..fdba9fdd3352664a09c6147f2120f88925149eca 100644
--- a/src/call/call.h
+++ b/src/call/call.h
@@ -92,8 +92,8 @@ class LINPHONE_PUBLIC Call : public bellesip::HybridObject<LinphoneCall, Call>,
 public:
 	Call(std::shared_ptr<Core> core,
 	     LinphoneCallDir direction,
-	     const Address &from,
-	     const Address &to,
+	     const std::shared_ptr<Address> &from,
+	     const std::shared_ptr<Address> &to,
 	     LinphoneProxyConfig *cfg,
 	     SalCallOp *op,
 	     const MediaSessionParams *msp);
@@ -103,8 +103,8 @@ public:
 	~Call();
 
 	void configure(LinphoneCallDir direction,
-	               const Address &from,
-	               const Address &to,
+	               const std::shared_ptr<Address> &from,
+	               const std::shared_ptr<Address> &to,
 	               LinphoneProxyConfig *cfg,
 	               SalCallOp *op,
 	               const MediaSessionParams *msp);
@@ -124,7 +124,7 @@ public:
 	LinphoneStatus pauseFromConference();
 	LinphoneStatus pause();
 	LinphoneStatus redirect(const std::string &redirectUri);
-	LinphoneStatus redirect(const Address &redirectAddress);
+	LinphoneStatus redirect(const std::shared_ptr<Address> &redirectAddress);
 	LinphoneStatus resume();
 	LinphoneStatus sendDtmf(char dtmf);
 	LinphoneStatus sendDtmfs(const std::string &dtmfs);
@@ -136,7 +136,7 @@ public:
 	LinphoneStatus takeVideoSnapshot(const std::string &file);
 	LinphoneStatus terminate(const LinphoneErrorInfo *ei = nullptr);
 	LinphoneStatus transfer(const std::shared_ptr<Call> &dest);
-	LinphoneStatus transfer(const Address &dest);
+	LinphoneStatus transfer(const std::shared_ptr<Address> &dest);
 	LinphoneStatus transfer(const std::string &dest);
 	LinphoneStatus update(const MediaSessionParams *msp = nullptr);
 	LinphoneStatus updateFromConference(const MediaSessionParams *msp = nullptr);
@@ -157,10 +157,10 @@ public:
 	const MediaSessionParams *getCurrentParams() const;
 	float getCurrentQuality() const;
 	LinphoneCallDir getDirection() const;
-	const Address &getDiversionAddress() const;
+	const std::shared_ptr<Address> getDiversionAddress() const;
 	int getDuration() const;
 	const LinphoneErrorInfo *getErrorInfo() const;
-	const Address &getLocalAddress() const;
+	const std::shared_ptr<Address> getLocalAddress() const;
 	std::shared_ptr<CallLog> getLog() const;
 	RtpTransport *getMetaRtcpTransport(int streamIndex) const;
 	RtpTransport *getMetaRtpTransport(int streamIndex) const;
@@ -173,10 +173,10 @@ public:
 	LinphoneReason getReason() const;
 	float getRecordVolume() const;
 	std::shared_ptr<Call> getReferer() const;
-	const std::string &getReferTo() const;
-	const Address &getReferToAddress() const;
-	const Address *getRemoteAddress() const;
-	const Address *getRemoteContactAddress() const;
+	const std::string getReferTo() const;
+	const std::shared_ptr<Address> &getReferToAddress() const;
+	const std::shared_ptr<Address> getRemoteAddress() const;
+	const std::shared_ptr<Address> getRemoteContactAddress() const;
 	const std::string &getRemoteContact() const;
 	const MediaSessionParams *getRemoteParams() const;
 	const std::string &getRemoteUserAgent();
@@ -188,7 +188,7 @@ public:
 	int getStreamCount() const;
 	MSFormatType getStreamType(int streamIndex) const;
 	LinphoneCallStats *getTextStats() const;
-	const Address &getToAddress() const;
+	const std::shared_ptr<Address> getToAddress() const;
 	const char *getToHeader(const std::string &name) const;
 	CallSession::State getTransferState() const;
 	std::shared_ptr<Call> getTransferTarget() const;
@@ -213,8 +213,8 @@ public:
 	bool setOutputAudioDevicePrivate(const std::shared_ptr<AudioDevice> &audioDevice);
 	std::shared_ptr<AudioDevice> getInputAudioDevice() const;
 	std::shared_ptr<AudioDevice> getOutputAudioDevice() const;
-	// -----------------------------------------------------------------------------
 
+	// -----------------------------------------------------------------------------
 	void createPlayer() const;
 	void initiateIncoming();
 	bool initiateOutgoing(const std::string &subject = "", const Content *content = nullptr);
@@ -224,16 +224,15 @@ public:
 	void startPushIncomingNotification();
 	void startBasicIncomingNotification();
 	void pauseForTransfer();
-	int startInvite(const Address *destination,
+	int startInvite(const std::shared_ptr<Address> &destination,
 	                const std::string subject = std::string(),
 	                const Content *content = nullptr);
 	std::shared_ptr<Call> startReferredCall(const MediaSessionParams *params);
 
 	// -----------------------------------------------------------------------------
-
 	std::shared_ptr<CallSession> getActiveSession() const;
 	std::shared_ptr<AbstractChatRoom> getChatRoom();
-	LinphoneProxyConfig *getDestProxy() const;
+	const std::shared_ptr<Account> &getDestAccount() const;
 	IceSession *getIceSession() const;
 	unsigned int getAudioStartCount() const;
 	unsigned int getAudioStopCount() const;
diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h
index 2b7fe142e33f10ad1078aff2cb39f69c6c3a51d9..e4cd980ae0f49244a416a393b8ed6edef2e68f2c 100644
--- a/src/chat/chat-message/chat-message-p.h
+++ b/src/chat/chat-message/chat-message-p.h
@@ -69,8 +69,9 @@ public:
 
 	void setDirection(ChatMessage::Direction dir);
 
-	void
-	setParticipantState(const IdentityAddress &participantAddress, ChatMessage::State newState, time_t stateChangeTime);
+	void setParticipantState(const std::shared_ptr<Address> &participantAddress,
+	                         ChatMessage::State newState,
+	                         time_t stateChangeTime);
 
 	virtual void setState(ChatMessage::State newState);
 	void forceState(ChatMessage::State newState) {
@@ -88,7 +89,7 @@ public:
 	void setImdnMessageId(const std::string &imdnMessageId);
 
 	void setForwardInfo(const std::string &fInfo);
-	void setReplyToMessageIdAndSenderAddress(const std::string &id, const IdentityAddress &sender);
+	void setReplyToMessageIdAndSenderAddress(const std::string &id, const std::shared_ptr<Address> &sender);
 
 	void enableEphemeralWithTime(long time);
 
@@ -96,20 +97,20 @@ public:
 
 	void startEphemeralCountDown();
 
-	void setAuthenticatedFromAddress(const IdentityAddress &authenticatedFromAddress) {
+	void setAuthenticatedFromAddress(const Address &authenticatedFromAddress) {
 		this->authenticatedFromAddress = authenticatedFromAddress;
 	}
 
-	void forceFromAddress(const ConferenceAddress &fromAddress) {
+	void forceFromAddress(const std::shared_ptr<Address> &fromAddress) {
 		this->fromAddress = fromAddress;
 	}
 
-	void forceToAddress(const ConferenceAddress &toAddress) {
+	void forceToAddress(const std::shared_ptr<Address> &toAddress) {
 		this->toAddress = toAddress;
 	}
 
 	// Used by the ConferenceScheduler to keep track of the recipient Address in One-To-One Flexisip chat room
-	void setRecipientAddress(const IdentityAddress &recipientAddress) {
+	void setRecipientAddress(const std::shared_ptr<Address> &recipientAddress) {
 		this->recipientAddress = recipientAddress;
 	}
 
@@ -291,18 +292,18 @@ private:
 
 	std::weak_ptr<AbstractChatRoom> chatRoom;
 	ConferenceId conferenceId;
-	ConferenceAddress fromAddress;
-	IdentityAddress authenticatedFromAddress;
+	std::shared_ptr<Address> fromAddress;
+	Address authenticatedFromAddress;
 	bool senderAuthenticationEnabled = true;
 	bool unencryptedContentWarning = false;
-	ConferenceAddress toAddress;
+	std::shared_ptr<Address> toAddress;
 
 	ChatMessage::State state = ChatMessage::State::Idle;
 	ChatMessage::Direction direction = ChatMessage::Direction::Incoming;
 	std::string forwardInfo;
 	std::string replyingToMessageId;
-	IdentityAddress replyingToMessageSender;
-	IdentityAddress recipientAddress;
+	std::shared_ptr<Address> replyingToMessageSender;
+	std::shared_ptr<Address> recipientAddress;
 
 	bool isEphemeral = false;
 	long ephemeralLifetime = 0;
diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp
index d9db83e3ff938950840cfd5acf769aa15939553b..cd17113de4434024af108c30dba604ae2138e46a 100644
--- a/src/chat/chat-message/chat-message.cpp
+++ b/src/chat/chat-message/chat-message.cpp
@@ -119,7 +119,7 @@ bool ChatMessagePrivate::isMarkedAsRead() const {
 	return markedAsRead;
 }
 
-void ChatMessagePrivate::setParticipantState(const IdentityAddress &participantAddress,
+void ChatMessagePrivate::setParticipantState(const std::shared_ptr<Address> &participantAddress,
                                              ChatMessage::State newState,
                                              time_t stateChangeTime) {
 	L_Q();
@@ -138,7 +138,7 @@ void ChatMessagePrivate::setParticipantState(const IdentityAddress &participantA
 
 	if (!isValidStateTransition(currentState, newState)) return;
 
-	lInfo() << "Chat message " << q->getSharedFromThis() << ": moving participant '" << participantAddress.asString()
+	lInfo() << "Chat message " << q->getSharedFromThis() << ": moving participant '" << participantAddress->toString()
 	        << "' state to " << Utils::toString(newState);
 	mainDb->setChatMessageParticipantState(eventLog, participantAddress, newState, stateChangeTime);
 
@@ -146,7 +146,7 @@ void ChatMessagePrivate::setParticipantState(const IdentityAddress &participantA
 	LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q->getChatRoom());
 	auto me = q->getChatRoom()->getMe();
 	auto participant =
-	    participantAddress == me->getAddress() ? me : q->getChatRoom()->findParticipant(participantAddress);
+	    (*participantAddress == *me->getAddress()) ? me : q->getChatRoom()->findParticipant(participantAddress);
 	ParticipantImdnState imdnState(participant, newState, stateChangeTime);
 	const LinphoneParticipantImdnState *c_state = _linphone_participant_imdn_state_from_cpp_obj(imdnState);
 
@@ -186,11 +186,13 @@ void ChatMessagePrivate::setParticipantState(const IdentityAddress &participantA
 		}
 	}
 
-	if (nbNotDeliveredStates > 0) setState(ChatMessage::State::NotDelivered);
-	else if (nbDisplayedStates == states.size()) {
+	if (nbNotDeliveredStates > 0) {
+		setState(ChatMessage::State::NotDelivered);
+	} else if ((states.size() > 0) && (nbDisplayedStates == states.size())) {
 		setState(ChatMessage::State::Displayed);
-	} else if ((nbDisplayedStates + nbDeliveredToUserStates) == states.size())
+	} else if ((states.size() > 0) && ((nbDisplayedStates + nbDeliveredToUserStates) == states.size())) {
 		setState(ChatMessage::State::DeliveredToUser);
+	}
 
 	// When we already marked an incoming message as displayed, start ephemeral countdown when all other recipients have
 	// displayed it as well
@@ -750,8 +752,8 @@ LinphoneReason ChatMessagePrivate::receive() {
 	// In plain text group chat rooms the sender authentication is disabled
 	if (!(q->getSharedFromThis()->getChatRoom()->getCapabilities() & ChatRoom::Capabilities::Encrypted)) {
 		if (q->getSharedFromThis()->getChatRoom()->getCapabilities() & ChatRoom::Capabilities::Basic) {
-			ConferenceAddress sipFromAddress = q->getSharedFromThis()->getFromAddress();
-			setAuthenticatedFromAddress(sipFromAddress);
+			const auto &sipFromAddress = q->getSharedFromThis()->getFromAddress();
+			setAuthenticatedFromAddress(*sipFromAddress);
 		} else {
 			lInfo() << "Sender authentication disabled for clear text group chat";
 			senderAuthenticationEnabled = false;
@@ -826,7 +828,7 @@ LinphoneReason ChatMessagePrivate::receive() {
 
 	// Check if this is in fact an outgoing message (case where this is a message sent by us from an other device).
 	if (chatRoom->getCapabilities() & ChatRoom::Capabilities::Conference &&
-	    chatRoom->getLocalAddress().asAddress().weakEqual(fromAddress.asAddress())) {
+	    chatRoom->getLocalAddress()->weakEqual(*fromAddress)) {
 		setDirection(ChatMessage::Direction::Outgoing);
 	}
 
@@ -1053,8 +1055,10 @@ void ChatMessagePrivate::send() {
 	}
 
 	shared_ptr<Core> core = q->getCore();
+	const auto toAddr = toAddress->toC();
+	const auto fromAddr = fromAddress->toC();
 	if (linphone_config_get_int(core->getCCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) {
-		lcall = linphone_core_get_call_by_remote_address(core->getCCore(), toAddress.asString().c_str());
+		lcall = linphone_core_get_call_by_remote_address2(core->getCCore(), toAddr);
 		if (lcall) {
 			shared_ptr<Call> call = LinphonePrivate::Call::toCpp(lcall)->getSharedFromThis();
 			if ((call->getState() == CallSession::State::Connected) ||
@@ -1066,33 +1070,26 @@ void ChatMessagePrivate::send() {
 				string identity =
 				    linphone_core_find_best_identity(core->getCCore(), linphone_call_get_remote_address(lcall));
 				if (identity.empty()) {
-					LinphoneAddress *addr = linphone_address_new(toAddress.asString().c_str());
-					LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core->getCCore(), addr);
+					LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core->getCCore(), toAddr);
 					if (proxy) {
-						identity =
-						    L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString();
+						identity = Address::toCpp(linphone_proxy_config_get_identity_address(proxy))->toString();
 					} else {
 						identity = linphone_core_get_primary_contact(core->getCCore());
 					}
-					linphone_address_unref(addr);
 				}
 			}
 		}
 	}
 
 	if (!op) {
-		LinphoneAddress *peer = linphone_address_new(toAddress.asString().c_str());
-		LinphoneAddress *local = linphone_address_new(fromAddress.asString().c_str());
 		/* Sending out of call */
 		salOp = op = new SalMessageOp(core->getCCore()->sal.get());
-		linphone_configure_op_2(core->getCCore(), op, local, peer, getSalCustomHeaders(),
+		linphone_configure_op_2(core->getCCore(), op, fromAddr, toAddr, getSalCustomHeaders(),
 		                        !!linphone_config_get_int(core->getCCore()->config, "sip", "chat_msg_with_contact", 0));
 		op->setUserPointer(q); /* If out of call, directly store msg */
-		linphone_address_unref(local);
-		linphone_address_unref(peer);
 	}
-	op->setFrom(fromAddress.asString().c_str());
-	op->setTo(toAddress.asString().c_str());
+	op->setFromAddress(fromAddress->getImpl());
+	op->setToAddress(toAddress->getImpl());
 
 	// ---------------------------------------
 	// Start of message modification
@@ -1420,7 +1417,7 @@ void ChatMessagePrivate::setForwardInfo(const string &fInfo) {
 	forwardInfo = fInfo;
 }
 
-void ChatMessagePrivate::setReplyToMessageIdAndSenderAddress(const string &id, const IdentityAddress &sender) {
+void ChatMessagePrivate::setReplyToMessageIdAndSenderAddress(const string &id, const std::shared_ptr<Address> &sender) {
 	replyingToMessageId = id;
 	replyingToMessageSender = sender;
 }
@@ -1435,7 +1432,7 @@ const string &ChatMessage::getReplyToMessageId() const {
 	return d->replyingToMessageId;
 }
 
-const IdentityAddress &ChatMessage::getReplyToSenderAddress() const {
+const std::shared_ptr<Address> &ChatMessage::getReplyToSenderAddress() const {
 	L_D();
 	return d->replyingToMessageSender;
 }
@@ -1468,28 +1465,28 @@ bool ChatMessage::isRead() const {
 	return d->markedAsRead || d->state == State::Displayed;
 }
 
-const IdentityAddress &ChatMessage::getAuthenticatedFromAddress() const {
+const Address &ChatMessage::getAuthenticatedFromAddress() const {
 	L_D();
 	return d->authenticatedFromAddress;
 }
 
-const ConferenceAddress &ChatMessage::getFromAddress() const {
+const std::shared_ptr<Address> &ChatMessage::getFromAddress() const {
 	L_D();
 	return d->fromAddress;
 }
 
-const ConferenceAddress &ChatMessage::getToAddress() const {
+const std::shared_ptr<Address> &ChatMessage::getToAddress() const {
 	L_D();
 	return d->toAddress;
 }
 
-const ConferenceAddress &ChatMessage::getLocalAddress() const {
+const std::shared_ptr<Address> &ChatMessage::getLocalAddress() const {
 	L_D();
 	if (getDirection() == Direction::Outgoing) return d->fromAddress;
 	else return d->toAddress;
 }
 
-const IdentityAddress &ChatMessage::getRecipientAddress() const {
+const std::shared_ptr<Address> &ChatMessage::getRecipientAddress() const {
 	L_D();
 	return d->recipientAddress;
 }
diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h
index 97ac939276e9f1e13fc54a33fcea962339c5ed3c..623cf3ba21a6d7d4922df0b705da343d271d955e 100644
--- a/src/chat/chat-message/chat-message.h
+++ b/src/chat/chat-message/chat-message.h
@@ -26,9 +26,6 @@
 #include "linphone/api/c-types.h"
 #include "linphone/enums/chat-message-enums.h"
 
-// TODO: Remove me later?
-#include "address/identity-address.h"
-
 #include "core/core-accessor.h"
 #include "object/object.h"
 
@@ -37,6 +34,7 @@
 LINPHONE_BEGIN_NAMESPACE
 
 class AbstractChatRoom;
+class Address;
 class Content;
 class FileContent;
 class FileTransferContent;
@@ -119,16 +117,16 @@ public:
 
 	const std::string &getImdnMessageId() const;
 
-	const IdentityAddress &getAuthenticatedFromAddress() const;
-	const ConferenceAddress &getFromAddress() const;
-	const ConferenceAddress &getToAddress() const;
-	const ConferenceAddress &getLocalAddress() const;
-	const IdentityAddress &getRecipientAddress() const;
+	const Address &getAuthenticatedFromAddress() const;
+	const std::shared_ptr<Address> &getFromAddress() const;
+	const std::shared_ptr<Address> &getToAddress() const;
+	const std::shared_ptr<Address> &getLocalAddress() const;
+	const std::shared_ptr<Address> &getRecipientAddress() const;
 	const std::string &getForwardInfo() const;
 
 	bool isReply() const;
 	const std::string &getReplyToMessageId() const;
-	const IdentityAddress &getReplyToSenderAddress() const;
+	const std::shared_ptr<Address> &getReplyToSenderAddress() const;
 	std::shared_ptr<ChatMessage> getReplyToMessage() const;
 
 	bool isEphemeral() const;
diff --git a/src/chat/chat-message/imdn-message.cpp b/src/chat/chat-message/imdn-message.cpp
index 52d556cc3895f40358ed77f295ac5d491da1e2cf..71b0b3561176c6a313d8206955e0ad47ef6753bf 100644
--- a/src/chat/chat-message/imdn-message.cpp
+++ b/src/chat/chat-message/imdn-message.cpp
@@ -71,7 +71,6 @@ ImdnMessage::ImdnMessage(const std::shared_ptr<ImdnMessage> &message) : ImdnMess
 
 ImdnMessage::ImdnMessage(const Context &context) : NotificationMessage(*new ImdnMessagePrivate(context)) {
 	L_D();
-
 	for (const auto &message : d->context.deliveredMessages) {
 		// Don't send IMDN if the message we send it for has no Message-ID
 		const string &imdnMessageId = message->getImdnMessageId();
diff --git a/src/chat/chat-room/abstract-chat-room.h b/src/chat/chat-room/abstract-chat-room.h
index 0e0fbe0091c33bb90a2d4596472f5135bde06604..f728de83182e55b15b1e9e038a846f11040862c9 100644
--- a/src/chat/chat-room/abstract-chat-room.h
+++ b/src/chat/chat-room/abstract-chat-room.h
@@ -99,8 +99,8 @@ public:
 	virtual bool canHandleCpim() const = 0;
 	virtual bool canHandleMultipart() const = 0;
 
-	virtual const IdentityAddress &getPeerAddress() const = 0;
-	virtual const IdentityAddress &getLocalAddress() const = 0;
+	virtual const std::shared_ptr<Address> &getPeerAddress() const = 0;
+	virtual const std::shared_ptr<Address> &getLocalAddress() const = 0;
 
 	virtual time_t getCreationTime() const = 0;
 	virtual time_t getLastUpdateTime() const = 0;
@@ -129,7 +129,7 @@ public:
 
 	virtual void compose() = 0;
 	virtual bool isRemoteComposing() const = 0;
-	virtual std::list<IdentityAddress> getComposingAddresses() const = 0;
+	virtual std::list<std::shared_ptr<Address>> getComposingAddresses() const = 0;
 
 	virtual std::shared_ptr<ChatMessage> createChatMessage() = 0;
 	virtual std::shared_ptr<ChatMessage> createChatMessage(const std::string &text) = 0;
diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp
index 67c55d54b3f7215625d893f31bf5fa2a22b4c0d0..e46ed0166b0e0dfc128c9b28239831c121be1362 100644
--- a/src/chat/chat-room/basic-chat-room.cpp
+++ b/src/chat/chat-room/basic-chat-room.cpp
@@ -69,8 +69,8 @@ bool BasicChatRoom::canHandleCpim() const {
 	bool cpimAllowedInBasicChatRooms = false;
 
 	LinphoneCore *lc = getCore()->getCCore();
-	Address addr(conferenceId.getLocalAddress().asAddress());
-	LinphoneAccount *account = linphone_core_lookup_account_by_identity(lc, L_GET_C_BACK_PTR(&addr));
+	auto addr = conferenceId.getLocalAddress();
+	LinphoneAccount *account = linphone_core_lookup_account_by_identity(lc, addr->toC());
 	if (account) {
 		const LinphoneAccountParams *params = linphone_account_get_params(account);
 		cpimAllowedInBasicChatRooms = linphone_account_params_cpim_in_basic_chat_room_enabled(params);
@@ -100,9 +100,9 @@ bool BasicChatRoom::isReadOnly() const {
 	return false;
 }
 
-const ConferenceAddress &BasicChatRoom::getConferenceAddress() const {
+const std::shared_ptr<Address> &BasicChatRoom::getConferenceAddress() const {
 	lError() << "a BasicChatRoom does not have a conference address";
-	return Utils::getEmptyConstRefObject<ConferenceAddress>();
+	return Utils::getEmptyConstRefObject<std::shared_ptr<Address>>();
 }
 
 bool BasicChatRoom::addParticipant(BCTBX_UNUSED(std::shared_ptr<Call> call)) {
@@ -110,27 +110,28 @@ bool BasicChatRoom::addParticipant(BCTBX_UNUSED(std::shared_ptr<Call> call)) {
 	return false;
 }
 
-bool BasicChatRoom::addParticipant(BCTBX_UNUSED(const IdentityAddress &participantAddress)) {
+bool BasicChatRoom::addParticipant(BCTBX_UNUSED(const std::shared_ptr<Address> &participantAddress)) {
 	lError() << "addParticipant() is not allowed on a BasicChatRoom";
 	return false;
 }
 
-bool BasicChatRoom::addParticipants(BCTBX_UNUSED(const list<IdentityAddress> &addresses)) {
+bool BasicChatRoom::addParticipants(BCTBX_UNUSED(const list<std::shared_ptr<Address>> &addresses)) {
 	lError() << "addParticipants() is not allowed on a BasicChatRoom";
 	return false;
 }
 
-bool BasicChatRoom::removeParticipant(BCTBX_UNUSED(const shared_ptr<Participant> &participantAddress)) {
+bool BasicChatRoom::removeParticipant(BCTBX_UNUSED(const shared_ptr<Participant> &participant)) {
 	lError() << "removeParticipant() is not allowed on a BasicChatRoom";
 	return false;
 }
 
-bool BasicChatRoom::removeParticipants(BCTBX_UNUSED(const list<shared_ptr<Participant>> &participantAddress)) {
+bool BasicChatRoom::removeParticipants(BCTBX_UNUSED(const list<shared_ptr<Participant>> &participant)) {
 	lError() << "removeParticipants() is not allowed on a BasicChatRoom";
 	return false;
 }
 
-shared_ptr<Participant> BasicChatRoom::findParticipant(const IdentityAddress &) const {
+shared_ptr<Participant>
+BasicChatRoom::findParticipant(BCTBX_UNUSED(const std::shared_ptr<Address> &participantAddress)) const {
 	lError() << "findParticipant() is not allowed on a BasicChatRoom";
 	return nullptr;
 }
@@ -178,7 +179,7 @@ void BasicChatRoom::join() {
 	lError() << "join() is not allowed on a BasicChatRoom";
 }
 
-void BasicChatRoom::join(BCTBX_UNUSED(const IdentityAddress &participantAddress)) {
+void BasicChatRoom::join(BCTBX_UNUSED(const std::shared_ptr<Address> &participantAddress)) {
 	lError() << "join() is not allowed on a BasicChatRoom";
 }
 
diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h
index 21b306ae471ace6d3aee88da8b6381d1d7f3891d..53231264b42ad16c1018537addc0be26f84f4190 100644
--- a/src/chat/chat-room/basic-chat-room.h
+++ b/src/chat/chat-room/basic-chat-room.h
@@ -44,12 +44,12 @@ public:
 	bool hasBeenLeft() const override;
 	bool isReadOnly() const override;
 
-	const ConferenceAddress &getConferenceAddress() const override;
+	const std::shared_ptr<Address> &getConferenceAddress() const override;
 
 	bool removeParticipant(const std::shared_ptr<Participant> &participant) override;
 	bool removeParticipants(const std::list<std::shared_ptr<Participant>> &participants) override;
 
-	std::shared_ptr<Participant> findParticipant(const IdentityAddress &addr) const override;
+	std::shared_ptr<Participant> findParticipant(const std::shared_ptr<Address> &addr) const override;
 
 	std::shared_ptr<Participant> getMe() const override;
 	int getParticipantCount() const override;
@@ -69,10 +69,10 @@ public:
 
 	const ConferenceId &getConferenceId() const override;
 
-	bool addParticipant(const IdentityAddress &participantAddress) override;
+	bool addParticipant(const std::shared_ptr<Address> &participantAddress) override;
 	bool addParticipant(std::shared_ptr<Call> call) override;
-	bool addParticipants(const std::list<IdentityAddress> &addresses) override;
-	void join(const IdentityAddress &participantAddress) override;
+	bool addParticipants(const std::list<std::shared_ptr<Address>> &addresses) override;
+	void join(const std::shared_ptr<Address> &participantAddress) override;
 	bool update(const ConferenceParamsInterface &newParameters) override;
 
 	State getState() const override;
diff --git a/src/chat/chat-room/basic-to-client-group-chat-room.cpp b/src/chat/chat-room/basic-to-client-group-chat-room.cpp
index 9363681f32d44de5ac3178ad113519e9df96bf2c..3edd335e3f9c39e0f241208e37605826c111cc0a 100644
--- a/src/chat/chat-room/basic-to-client-group-chat-room.cpp
+++ b/src/chat/chat-room/basic-to-client-group-chat-room.cpp
@@ -64,10 +64,8 @@ public:
 		ProxyChatRoomPrivate::sendChatMessage(chatMessage);
 		const list<string> &specs = chatMessage->getCore()->getSpecsList();
 		time_t currentRealTime = ms_time(nullptr);
-		LinphoneAddress *lAddr =
-		    linphone_address_new(chatMessage->getChatRoom()->getConferenceId().getLocalAddress().asString().c_str());
+		LinphoneAddress *lAddr = chatMessage->getChatRoom()->getConferenceId().getLocalAddress()->toC();
 		LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(q->getCore()->getCCore(), lAddr);
-		linphone_address_unref(lAddr);
 		const char *conferenceFactoryUri = nullptr;
 		if (proxy) {
 			conferenceFactoryUri = linphone_proxy_config_get_conference_factory_uri(proxy);
@@ -83,9 +81,8 @@ public:
 			return;
 		}
 		migrationRealTime = currentRealTime;
-		char *tmp = linphone_address_as_string(linphone_proxy_config_get_contact(proxy)); // get the gruu address
-		IdentityAddress localAddress(tmp);
-		bctbx_free(tmp);
+		auto localAddress =
+		    Address::toCpp(linphone_proxy_config_get_contact(proxy))->getSharedFromThis(); // get the gruu address
 		string subject = chatRoom->getSubject();
 		if (subject.empty()) subject = "basic to client group migrated";
 		auto params = ChatRoomParams::create(subject, chatRoom->getCapabilities() & ChatRoom::Capabilities::Encrypted,
@@ -93,7 +90,7 @@ public:
 		// make sure to have a one2one chatroom
 		clientGroupChatRoom =
 		    static_pointer_cast<ClientGroupChatRoom>(chatRoom->getCore()->getPrivate()->createChatRoom(
-		        params, localAddress, subject, {chatRoom->getPeerAddress().asAddress()}));
+		        params, localAddress, subject, {chatRoom->getPeerAddress()}));
 		clientGroupChatRoom->getPrivate()->setCallSessionListener(this);
 		clientGroupChatRoom->getPrivate()->setChatRoomListener(this);
 	}
diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h
index dad3b13ff8c41738854702df35b5ea34d9a11e07..f4d7385dea586c785247cb7d5f43bfeb92503551 100644
--- a/src/chat/chat-room/chat-room-p.h
+++ b/src/chat/chat-room/chat-room-p.h
@@ -90,17 +90,17 @@ public:
 	void notifyAggregatedChatMessages() override;
 	void notifyMessageReceived(const std::shared_ptr<ChatMessage> &chatMessage);
 	void notifyChatMessageReceived(const std::shared_ptr<ChatMessage> &chatMessage) override;
-	void notifyIsComposingReceived(const Address &remoteAddress, bool isComposing);
+	void notifyIsComposingReceived(const std::shared_ptr<Address> &remoteAddress, bool isComposing);
 	void notifyStateChanged();
 	void notifyUndecryptableChatMessageReceived(const std::shared_ptr<ChatMessage> &chatMessage) override;
 
 	LinphoneReason onSipMessageReceived(SalOp *op, const SalMessage *message) override;
 	void onChatMessageReceived(const std::shared_ptr<ChatMessage> &chatMessage) override;
 	void onImdnReceived(const std::shared_ptr<ChatMessage> &chatMessage);
-	void onIsComposingReceived(const Address &remoteAddress, const std::string &text);
+	void onIsComposingReceived(const std::shared_ptr<Address> &remoteAddress, const std::string &text);
 	void onIsComposingRefreshNeeded() override;
 	void onIsComposingStateChanged(bool isComposing) override;
-	void onIsRemoteComposingStateChanged(const Address &remoteAddress, bool isComposing) override;
+	void onIsRemoteComposingStateChanged(const std::shared_ptr<Address> &remoteAddress, bool isComposing) override;
 
 	void realtimeTextReceived(uint32_t character, const std::shared_ptr<Call> &call) override;
 	void setCallId(const std::string &value) override {
@@ -113,7 +113,7 @@ public:
 
 	LinphoneChatRoom *getCChatRoom() const;
 
-	std::list<IdentityAddress> remoteIsComposing;
+	std::list<std::shared_ptr<Address>> remoteIsComposing;
 	std::list<std::shared_ptr<EventLog>> transientEvents;
 	std::list<std::shared_ptr<ChatMessage>> transientMessages;
 	std::list<std::shared_ptr<ChatMessage>> aggregatedMessages;
diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp
index ed64a3eeb3aab69bbf9cae322697bc37067407fe..0d97170fdedca6018d18ddfd75e7aad2c1d2b468 100644
--- a/src/chat/chat-room/chat-room.cpp
+++ b/src/chat/chat-room/chat-room.cpp
@@ -22,9 +22,6 @@
 
 #include <bctoolbox/defs.h>
 
-#include "linphone/utils/algorithm.h"
-#include "linphone/utils/utils.h"
-
 #include "c-wrapper/c-wrapper.h"
 #include "call/call.h"
 #include "chat/chat-message/chat-message-p.h"
@@ -34,6 +31,8 @@
 #include "chat/chat-room/chat-room-p.h"
 #include "content/content-manager.h"
 #include "core/core-p.h"
+#include "linphone/utils/algorithm.h"
+#include "linphone/utils/utils.h"
 #include "logger/logger.h"
 
 // =============================================================================
@@ -275,29 +274,33 @@ void ChatRoomPrivate::notifyChatMessageReceived(const shared_ptr<ChatMessage> &c
 	LinphoneChatRoom *cr = getCChatRoom();
 	if (!chatMessage->getPrivate()->getText().empty()) {
 		/* Legacy API */
-		LinphoneAddress *fromAddress = linphone_address_new(chatMessage->getFromAddress().asString().c_str());
+		LinphoneAddress *fromAddress = chatMessage->getFromAddress()->toC();
 		linphone_core_notify_text_message_received(q->getCore()->getCCore(), cr, fromAddress,
 		                                           chatMessage->getPrivate()->getText().c_str());
-		linphone_address_unref(fromAddress);
 	}
 	_linphone_chat_room_notify_message_received(cr, L_GET_C_BACK_PTR(chatMessage));
 	linphone_core_notify_message_received(q->getCore()->getCCore(), cr, L_GET_C_BACK_PTR(chatMessage));
 }
 
-void ChatRoomPrivate::notifyIsComposingReceived(const Address &remoteAddress, bool isComposing) {
+void ChatRoomPrivate::notifyIsComposingReceived(const std::shared_ptr<Address> &remoteAddress, bool isComposing) {
 	L_Q();
 
+	auto it = find_if(remoteIsComposing.cbegin(), remoteIsComposing.cend(),
+	                  [&remoteAddress](const auto &address) { return (*remoteAddress == *address); });
+
 	if (isComposing) {
-		auto it = find(remoteIsComposing.cbegin(), remoteIsComposing.cend(), remoteAddress);
-		if (it == remoteIsComposing.cend()) remoteIsComposing.push_back(remoteAddress);
+		if (it == remoteIsComposing.cend()) {
+			remoteIsComposing.push_back(remoteAddress);
+		}
 	} else {
-		remoteIsComposing.remove(remoteAddress);
+		if (it != remoteIsComposing.cend()) {
+			remoteIsComposing.erase(it);
+		}
 	}
 
 	LinphoneChatRoom *cr = getCChatRoom();
-	LinphoneAddress *lAddr = linphone_address_new(remoteAddress.asString().c_str());
+	LinphoneAddress *lAddr = remoteAddress->toC();
 	_linphone_chat_room_notify_is_composing_received(cr, lAddr, !!isComposing);
-	linphone_address_unref(lAddr);
 	// Legacy notification
 	linphone_core_notify_is_composing_received(q->getCore()->getCCore(), cr);
 }
@@ -331,8 +334,9 @@ std::shared_ptr<ChatMessage> ChatRoomPrivate::getMessageFromSal(SalOp *op, const
 
 	shared_ptr<ChatMessage> msg;
 
-	msg = createChatMessage(IdentityAddress(op->getFrom()) == q->getLocalAddress() ? ChatMessage::Direction::Outgoing
-	                                                                               : ChatMessage::Direction::Incoming);
+	auto from = Address::create(op->getFrom());
+	msg = createChatMessage((*from == *q->getLocalAddress()) ? ChatMessage::Direction::Outgoing
+	                                                         : ChatMessage::Direction::Incoming);
 
 	Content content;
 	if (message->url && ContentType(message->content_type) == ContentType::ExternalBody) {
@@ -385,18 +389,18 @@ void ChatRoomPrivate::onChatMessageReceived(const shared_ptr<ChatMessage> &chatM
 	LinphoneCore *cCore = core->getCCore();
 
 	if (chatMessage->getPrivate()->getContentType() == ContentType::ImIsComposing) {
-		onIsComposingReceived(chatMessage->getFromAddress().asAddress(), chatMessage->getPrivate()->getText());
+		onIsComposingReceived(chatMessage->getFromAddress(), chatMessage->getPrivate()->getText());
 		if (linphone_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) return;
 	} else if (chatMessage->getPrivate()->getContentType() == ContentType::Imdn) {
 		onImdnReceived(chatMessage);
 		if (linphone_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) return;
 	}
 
-	const IdentityAddress &fromAddress = chatMessage->getFromAddress();
+	const std::shared_ptr<Address> &fromAddress = chatMessage->getFromAddress();
 	if ((chatMessage->getPrivate()->getContentType() != ContentType::ImIsComposing) &&
 	    (chatMessage->getPrivate()->getContentType() != ContentType::Imdn)) {
-		isComposingHandler->stopRemoteRefreshTimer(fromAddress.asString());
-		notifyIsComposingReceived(fromAddress.asAddress(), false);
+		isComposingHandler->stopRemoteRefreshTimer(fromAddress->toString());
+		notifyIsComposingReceived(fromAddress, false);
 	}
 
 	if (core->isCurrentlyAggregatingChatMessages()) {
@@ -477,7 +481,7 @@ void ChatRoomPrivate::onImdnReceived(const shared_ptr<ChatMessage> &chatMessage)
 	Imdn::parse(chatMessage);
 }
 
-void ChatRoomPrivate::onIsComposingReceived(const Address &remoteAddress, const string &text) {
+void ChatRoomPrivate::onIsComposingReceived(const std::shared_ptr<Address> &remoteAddress, const string &text) {
 	isComposingHandler->parse(remoteAddress, text);
 }
 
@@ -490,7 +494,7 @@ void ChatRoomPrivate::onIsComposingStateChanged(bool isComposing) {
 	sendIsComposingNotification();
 }
 
-void ChatRoomPrivate::onIsRemoteComposingStateChanged(const Address &remoteAddress, bool isComposing) {
+void ChatRoomPrivate::onIsRemoteComposingStateChanged(const std::shared_ptr<Address> &remoteAddress, bool isComposing) {
 	notifyIsComposingReceived(remoteAddress, isComposing);
 }
 
@@ -537,11 +541,11 @@ ChatRoom::~ChatRoom() {
 
 // -----------------------------------------------------------------------------
 
-const IdentityAddress &ChatRoom::getPeerAddress() const {
+const std::shared_ptr<Address> &ChatRoom::getPeerAddress() const {
 	return getConferenceId().getPeerAddress();
 }
 
-const IdentityAddress &ChatRoom::getLocalAddress() const {
+const std::shared_ptr<Address> &ChatRoom::getLocalAddress() const {
 	return getConferenceId().getLocalAddress();
 }
 
@@ -669,7 +673,7 @@ bool ChatRoom::isRemoteComposing() const {
 	return !d->remoteIsComposing.empty();
 }
 
-list<IdentityAddress> ChatRoom::getComposingAddresses() const {
+list<std::shared_ptr<Address>> ChatRoom::getComposingAddresses() const {
 	L_D();
 	return d->remoteIsComposing;
 }
@@ -718,7 +722,7 @@ shared_ptr<ChatMessage> ChatRoom::createForwardMessage(const shared_ptr<ChatMess
 	if (hidden) {
 		fInfo = "Anonymous";
 	} else {
-		fInfo = msg->getForwardInfo().empty() ? msg->getFromAddress().asString() : msg->getForwardInfo();
+		fInfo = msg->getForwardInfo().empty() ? msg->getFromAddress()->asStringUriOnly() : msg->getForwardInfo();
 	}
 
 	chatMessage->getPrivate()->setForwardInfo(fInfo);
@@ -728,8 +732,7 @@ shared_ptr<ChatMessage> ChatRoom::createForwardMessage(const shared_ptr<ChatMess
 
 shared_ptr<ChatMessage> ChatRoom::createReplyMessage(const shared_ptr<ChatMessage> &msg) {
 	shared_ptr<ChatMessage> chatMessage = createChatMessage();
-	chatMessage->getPrivate()->setReplyToMessageIdAndSenderAddress(msg->getImdnMessageId(),
-	                                                               msg->getFromAddress().getAddressWithoutGruu());
+	chatMessage->getPrivate()->setReplyToMessageIdAndSenderAddress(msg->getImdnMessageId(), msg->getFromAddress());
 	return chatMessage;
 }
 
@@ -838,10 +841,10 @@ bool ChatRoom::removeParticipants(const list<shared_ptr<Participant>> &participa
 	return soFarSoGood;
 }
 
-bool ChatRoom::addParticipants(const std::list<IdentityAddress> &addresses) {
-	list<IdentityAddress> sortedAddresses(addresses);
-	sortedAddresses.sort();
-	sortedAddresses.unique();
+bool ChatRoom::addParticipants(const std::list<std::shared_ptr<Address>> &addresses) {
+	list<std::shared_ptr<Address>> sortedAddresses(addresses);
+	sortedAddresses.sort([](const auto &addr1, const auto &addr2) { return *addr1 < *addr2; });
+	sortedAddresses.unique([](const auto &addr1, const auto &addr2) { return addr1->weakEqual(*addr2); });
 
 	bool soFarSoGood = true;
 	for (const auto &address : sortedAddresses)
diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h
index 879b179c8d93de308059b832626bac8d602b940e..2aeb7c76ee84b600ebee047540a93996f5871075 100644
--- a/src/chat/chat-room/chat-room.h
+++ b/src/chat/chat-room/chat-room.h
@@ -42,8 +42,8 @@ public:
 
 	virtual ~ChatRoom();
 
-	const IdentityAddress &getPeerAddress() const override;
-	const IdentityAddress &getLocalAddress() const override;
+	const std::shared_ptr<Address> &getPeerAddress() const override;
+	const std::shared_ptr<Address> &getLocalAddress() const override;
 
 	time_t getCreationTime() const override;
 	time_t getLastUpdateTime() const override;
@@ -72,7 +72,7 @@ public:
 
 	void compose() override;
 	bool isRemoteComposing() const override;
-	std::list<IdentityAddress> getComposingAddresses() const override;
+	std::list<std::shared_ptr<Address>> getComposingAddresses() const override;
 
 	std::shared_ptr<ChatMessage> createChatMessage() override;
 	std::shared_ptr<ChatMessage> createChatMessage(const std::string &text) override;
@@ -104,7 +104,7 @@ public:
 		return conference;
 	};
 
-	bool addParticipants(const std::list<IdentityAddress> &addresses) override;
+	bool addParticipants(const std::list<std::shared_ptr<Address>> &addresses) override;
 	bool removeParticipants(const std::list<std::shared_ptr<Participant>> &participants) override;
 
 	bool canHandleParticipants() const override {
diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h
index deae90a56d8343adfc7e41934df91a3d96118fc3..de30148e80abc8dfb95a3674a4be920ca5380e57 100644
--- a/src/chat/chat-room/client-group-chat-room-p.h
+++ b/src/chat/chat-room/client-group-chat-room-p.h
@@ -40,8 +40,8 @@ public:
 
 	virtual ~ClientGroupChatRoomPrivate() = default;
 
-	std::list<IdentityAddress> cleanAddressesList(const std::list<IdentityAddress> &addresses) const;
-	std::shared_ptr<CallSession> createSessionTo(Address sessionTo);
+	std::list<std::shared_ptr<Address>> cleanAddressesList(const std::list<std::shared_ptr<Address>> &addresses) const;
+	std::shared_ptr<CallSession> createSessionTo(std::shared_ptr<Address> sessionTo);
 	std::shared_ptr<CallSession> createSession();
 	void notifyReceived(const Content &content);
 	void multipartNotifyReceived(const Content &content);
@@ -70,9 +70,9 @@ public:
 	                               CallSession::State state,
 	                               const std::string &message) override;
 
-	void onChatRoomCreated(const Address &remoteContact);
+	void onChatRoomCreated(const std::shared_ptr<Address> &remoteContact);
 	void onExhumedConference(const ConferenceId &oldConfId, const ConferenceId &newConfId);
-	void onLocallyExhumedConference(const Address &remoteContact);
+	void onLocallyExhumedConference(const std::shared_ptr<Address> &remoteContact);
 	void onRemotelyExhumedConference(SalCallOp *op);
 	void sendChatMessage(const std::shared_ptr<ChatMessage> &chatMessage) override;
 
diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp
index 5f8826920263d85f3922ccda38a8ddb8f5c1b842..21903c66cfae63e093ccd7d04ad3b4d1bca54292 100644
--- a/src/chat/chat-room/client-group-chat-room.cpp
+++ b/src/chat/chat-room/client-group-chat-room.cpp
@@ -52,14 +52,15 @@ LINPHONE_BEGIN_NAMESPACE
 // -----------------------------------------------------------------------------
 // Removes own address and existing participants from the list.
 // Also removes gruu from kept addresses
-list<IdentityAddress> ClientGroupChatRoomPrivate::cleanAddressesList(const list<IdentityAddress> &addresses) const {
+list<std::shared_ptr<Address>>
+ClientGroupChatRoomPrivate::cleanAddressesList(const list<std::shared_ptr<Address>> &addresses) const {
 	L_Q();
-	list<IdentityAddress> cleanedList(addresses);
+	list<std::shared_ptr<Address>> cleanedList(addresses);
 
-	cleanedList.sort();
-	cleanedList.unique();
+	cleanedList.sort([](const auto &addr1, const auto &addr2) { return *addr1 < *addr2; });
+	cleanedList.unique([](const auto &addr1, const auto &addr2) { return addr1->weakEqual(*addr2); });
 	for (auto it = cleanedList.begin(); it != cleanedList.end();) {
-		if (q->findParticipant(*it) || (q->getMe()->getAddress() == *it)) {
+		if (q->findParticipant(*it) || (*q->getMe()->getAddress() == **it)) {
 			it = cleanedList.erase(it);
 		} else {
 			it++;
@@ -68,7 +69,7 @@ list<IdentityAddress> ClientGroupChatRoomPrivate::cleanAddressesList(const list<
 	return cleanedList;
 }
 
-shared_ptr<CallSession> ClientGroupChatRoomPrivate::createSessionTo(Address sessionTo) {
+shared_ptr<CallSession> ClientGroupChatRoomPrivate::createSessionTo(std::shared_ptr<Address> sessionTo) {
 	L_Q();
 
 	CallSessionParams csp;
@@ -84,8 +85,7 @@ shared_ptr<CallSession> ClientGroupChatRoomPrivate::createSessionTo(Address sess
 
 	shared_ptr<Participant> &focus = static_pointer_cast<RemoteConference>(q->getConference())->focus;
 	shared_ptr<CallSession> session = focus->createSession(*q->getConference().get(), &csp, false, callSessionListener);
-	Address meCleanedAddress(q->getMe()->getAddress().asAddress());
-	meCleanedAddress.removeUriParam("gr"); // Remove gr parameter for INVITE.
+	std::shared_ptr<Address> meCleanedAddress = Address::create(q->getMe()->getAddress()->getUriWithoutGruu());
 
 	session->configure(LinphoneCallOutgoing, nullptr, nullptr, meCleanedAddress, sessionTo);
 	session->initiateOutgoing();
@@ -96,9 +96,10 @@ shared_ptr<CallSession> ClientGroupChatRoomPrivate::createSessionTo(Address sess
 
 shared_ptr<CallSession> ClientGroupChatRoomPrivate::createSession() {
 	L_Q();
-	const ConferenceAddress &peerAddress(q->getConferenceId().getPeerAddress());
+	const std::shared_ptr<Address> &peerAddress(q->getConferenceId().getPeerAddress());
 	shared_ptr<Participant> &focus = static_pointer_cast<RemoteConference>(q->getConference())->focus;
-	const Address sessionTo = peerAddress.isValid() ? peerAddress.asAddress() : focus->getAddress().asAddress();
+	const std::shared_ptr<Address> sessionTo =
+	    (peerAddress && peerAddress->isValid()) ? peerAddress : focus->getAddress();
 	return createSessionTo(sessionTo);
 }
 
@@ -148,27 +149,27 @@ void ClientGroupChatRoomPrivate::confirmJoining(SalCallOp *op) {
 	auto focusSession = focus->getSession();
 	bool previousSession = (focusSession != nullptr);
 
+	auto from = Address::create(op->getFrom());
+	auto to = Address::create(op->getTo());
 	shared_ptr<AbstractChatRoom> exhumedChatRoom =
-	    q->getCore()->getPrivate()->findExumedChatRoomFromPreviousConferenceId(
-	        ConferenceId(ConferenceAddress(Address(op->getFrom())), ConferenceAddress(Address(op->getTo()))));
+	    q->getCore()->getPrivate()->findExumedChatRoomFromPreviousConferenceId(ConferenceId(from, to));
 
 	if (previousSession && !exhumedChatRoom) {
 		// Prevents leak
 		auto focusOp = focusSession->getPrivate()->getOp();
-		lInfo() << "Releasing focus session " << focusSession << " (from: " << Address(focusOp->getFrom()) << " to "
-		        << Address(focusOp->getTo()) << ")";
+		lInfo() << "Releasing focus session " << focusSession << " (from: " << *from << " to " << *to << ")";
 		focusOp->terminate();
 		focusOp->release();
 	}
 
 	auto session = focus->createSession(*q->getConference().get(), nullptr, false, this);
-	session->configure(LinphoneCallIncoming, nullptr, op, Address(op->getFrom()), Address(op->getTo()));
+	session->configure(LinphoneCallIncoming, nullptr, op, from, to);
 	session->startIncomingNotification(false);
 
 	bool found = false;
 	for (auto it = previousConferenceIds.begin(); it != previousConferenceIds.end(); it++) {
 		ConferenceId confId = static_cast<ConferenceId>(*it);
-		if (confId.getPeerAddress() == op->getRemoteContact()) {
+		if (*confId.getPeerAddress() == Address(op->getRemoteContact())) {
 			found = true;
 			break;
 		}
@@ -178,7 +179,7 @@ void ClientGroupChatRoomPrivate::confirmJoining(SalCallOp *op) {
 	if (!previousSession && !found) {
 		q->setState(ConferenceInterface::State::CreationPending);
 		// Handle participants addition
-		list<IdentityAddress> identAddresses = Utils::parseResourceLists(op->getRemoteBody());
+		list<std::shared_ptr<Address>> identAddresses = Utils::parseResourceLists(op->getRemoteBody());
 		for (const auto &addr : identAddresses) {
 			auto participant = q->findParticipant(addr);
 			if (!participant) {
@@ -268,9 +269,9 @@ void ClientGroupChatRoomPrivate::onCallSessionStateChanged(const shared_ptr<Call
 		if (q->getState() == ConferenceInterface::State::CreationPending) {
 			auto migration = needToMigrate();
 			if (localExhumePending) {
-				onLocallyExhumedConference(*session->getRemoteContactAddress());
+				onLocallyExhumedConference(session->getRemoteContactAddress());
 			} else {
-				onChatRoomCreated(*session->getRemoteContactAddress());
+				onChatRoomCreated(session->getRemoteContactAddress());
 			}
 
 			if (!migration.first) {
@@ -292,12 +293,11 @@ void ClientGroupChatRoomPrivate::onCallSessionStateChanged(const shared_ptr<Call
 			           << "] received a BYE with reason: " << linphone_error_info_get_protocol_code(errorInfo)
 			           << ", not leaving it.";
 		} else {
-			const auto &remoteAddress = session->getRemoteAddress();
-			ConferenceAddress remoteConferenceAddress = ConferenceAddress(*remoteAddress);
+			const auto &remoteConferenceAddress = session->getRemoteAddress();
 			bool found = false;
 			for (auto it = previousConferenceIds.begin(); it != previousConferenceIds.end(); it++) {
 				ConferenceId confId = static_cast<ConferenceId>(*it);
-				if (confId.getPeerAddress() == remoteConferenceAddress) {
+				if (*confId.getPeerAddress() == *remoteConferenceAddress) {
 					lInfo() << "Found previous chat room conference ID [" << confId
 					        << "] for chat room with current ID [" << q->getConferenceId() << "]";
 					removeConferenceIdFromPreviousList(confId);
@@ -353,12 +353,11 @@ void ClientGroupChatRoomPrivate::addPendingMessage(const std::shared_ptr<ChatMes
 	pendingCreationMessages.push_back(chatMessage);
 }
 
-void ClientGroupChatRoomPrivate::onChatRoomCreated(const Address &remoteContact) {
+void ClientGroupChatRoomPrivate::onChatRoomCreated(const std::shared_ptr<Address> &remoteContact) {
 	L_Q();
 
-	ConferenceAddress addr(remoteContact);
-	q->onConferenceCreated(addr);
-	if (remoteContact.hasParam("isfocus")) {
+	q->onConferenceCreated(remoteContact);
+	if (remoteContact->hasParam("isfocus")) {
 		if (q->getCore()->getPrivate()->remoteListEventHandler->findHandler(q->getConferenceId())) {
 			q->getCore()->getPrivate()->remoteListEventHandler->subscribe();
 		} else {
@@ -378,7 +377,7 @@ void ClientGroupChatRoomPrivate::acceptSession(const shared_ptr<CallSession> &se
 // =============================================================================
 
 ClientGroupChatRoom::ClientGroupChatRoom(const shared_ptr<Core> &core,
-                                         const IdentityAddress &focus,
+                                         const std::shared_ptr<Address> &focus,
                                          const ConferenceId &conferenceId,
                                          const string &subject,
                                          const Content &content,
@@ -419,17 +418,12 @@ ClientGroupChatRoom::ClientGroupChatRoom(const shared_ptr<Core> &core,
 
 ClientGroupChatRoom::ClientGroupChatRoom(const shared_ptr<Core> &core,
                                          const string &factoryUri,
-                                         const IdentityAddress &me,
+                                         const std::shared_ptr<const Address> &me,
                                          const string &subject,
                                          CapabilitiesMask capabilities,
                                          const std::shared_ptr<ChatRoomParams> &params)
-    : ClientGroupChatRoom(core,
-                          IdentityAddress(factoryUri),
-                          ConferenceId(ConferenceAddress(), me),
-                          subject,
-                          Content(),
-                          capabilities,
-                          params) {
+    : ClientGroupChatRoom(
+          core, Address::create(factoryUri), ConferenceId(nullptr, me), subject, Content(), capabilities, params) {
 }
 
 ClientGroupChatRoom::ClientGroupChatRoom(const shared_ptr<Core> &core,
@@ -457,7 +451,7 @@ ClientGroupChatRoom::ClientGroupChatRoom(const shared_ptr<Core> &core,
 	    std::make_shared<RemoteConferenceEventHandler>(getConference().get(), this);
 	addListener(std::shared_ptr<ConferenceListenerInterface>(static_cast<ConferenceListenerInterface *>(this),
 	                                                         [](BCTBX_UNUSED(ConferenceListenerInterface * p)) {}));
-	const ConferenceAddress &peerAddress = conferenceId.getPeerAddress();
+	const std::shared_ptr<Address> &peerAddress = conferenceId.getPeerAddress();
 	static_pointer_cast<RemoteConference>(getConference())->focus =
 	    Participant::create(getConference().get(), peerAddress);
 	static_pointer_cast<RemoteConference>(getConference())->focus->addDevice(peerAddress);
@@ -514,14 +508,14 @@ void ClientGroupChatRoom::setConferenceId(const ConferenceId &conferenceId) {
 		shared_ptr<CallSession> session = static_pointer_cast<RemoteConference>(getConference())->focus->getSession();
 		if (session) {
 			shared_ptr<CallLog> sessionLog = session->getLog();
-			if (conferenceId.getPeerAddress().isValid()) {
+			if (conferenceId.getPeerAddress()->isValid()) {
 				// Use the peer address of the conference ID because it has also the conf-id param hence the To field
 				// can be used to search in the map of chat rooms
-				sessionLog->setToAddress(linphone_address_new(conferenceId.getPeerAddress().asString().c_str()));
+				sessionLog->setToAddress(conferenceId.getPeerAddress());
 			} else {
 				// If the conference ID peer address is not valid, use the address of the focus
 				shared_ptr<Participant> &focus = static_pointer_cast<RemoteConference>(getConference())->focus;
-				sessionLog->setToAddress(linphone_address_new(focus->getAddress().asString().c_str()));
+				sessionLog->setToAddress(focus->getAddress());
 			}
 		}
 	}
@@ -588,13 +582,13 @@ ClientGroupChatRoom::getSecurityLevelExcept(const std::shared_ptr<ParticipantDev
 	std::list<std::string> allDevices{};
 	for (const auto &participant : participants) {
 		for (const auto &device : participant->getDevices()) {
-			allDevices.push_back(device->getAddress().asString());
+			allDevices.push_back(device->getAddress()->asStringUriOnly());
 		}
 	}
 	if (ignoredDevice != nullptr) {
-		allDevices.remove(ignoredDevice->getAddress().asString());
+		allDevices.remove(ignoredDevice->getAddress()->asStringUriOnly());
 	}
-	allDevices.remove(getLocalAddress().asString()); // remove local device from the list
+	allDevices.remove(getLocalAddress()->asStringUriOnly()); // remove local device from the list
 
 	if (allDevices.empty()) {
 		return AbstractChatRoom::SecurityLevel::Safe;
@@ -616,7 +610,7 @@ bool ClientGroupChatRoom::isReadOnly() const {
 	return getState() != State::Created;
 }
 
-const ConferenceAddress &ClientGroupChatRoom::getConferenceAddress() const {
+const std::shared_ptr<Address> &ClientGroupChatRoom::getConferenceAddress() const {
 	return getConference()->getConferenceAddress();
 }
 
@@ -660,13 +654,12 @@ int ClientGroupChatRoom::getHistorySize() const {
 	                                                 MainDb::Filter::ConferenceInfoNoDeviceFilter}));
 }
 
-bool ClientGroupChatRoom::addParticipant(const IdentityAddress &participantAddress) {
-	list<IdentityAddress> addressesList({participantAddress});
-
+bool ClientGroupChatRoom::addParticipant(const std::shared_ptr<Address> &participantAddress) {
+	list<std::shared_ptr<Address>> addressesList({participantAddress});
 	return addParticipants(addressesList);
 }
 
-bool ClientGroupChatRoom::addParticipants(const list<IdentityAddress> &addresses) {
+bool ClientGroupChatRoom::addParticipants(const list<std::shared_ptr<Address>> &addresses) {
 	L_D();
 	if ((getState() != ConferenceInterface::State::Instantiated) &&
 	    (getState() != ConferenceInterface::State::Created)) {
@@ -674,7 +667,7 @@ bool ClientGroupChatRoom::addParticipants(const list<IdentityAddress> &addresses
 		return false;
 	}
 
-	list<IdentityAddress> addressesList = d->cleanAddressesList(addresses);
+	list<std::shared_ptr<Address>> addressesList = d->cleanAddressesList(addresses);
 	if (addressesList.empty()) {
 		lError() << "No participants given.";
 		return false;
@@ -691,19 +684,20 @@ bool ClientGroupChatRoom::addParticipants(const list<IdentityAddress> &addresses
 		setState(ConferenceInterface::State::CreationPending);
 	} else {
 		SalReferOp *referOp = new SalReferOp(getCore()->getCCore()->sal.get());
-		LinphoneAddress *lAddr = L_GET_C_BACK_PTR(&(getConferenceAddress().asAddress()));
+		LinphoneAddress *lAddr = getConferenceAddress()->toC();
 		linphone_configure_op(getCore()->getCCore(), referOp, lAddr, nullptr, true);
 		for (const auto &addr : addresses) {
-			Address referToAddr = addr.asAddress();
+			Address referToAddr(*addr);
 			referToAddr.setParam("text");
-			referOp->sendRefer(referToAddr.getInternalAddress());
+			referOp->sendRefer(referToAddr.getImpl());
 		}
 		referOp->unref();
 	}
 	return true;
 }
 
-void ClientGroupChatRoom::sendInvite(std::shared_ptr<CallSession> &session, const list<IdentityAddress> &addressList) {
+void ClientGroupChatRoom::sendInvite(std::shared_ptr<CallSession> &session,
+                                     const list<std::shared_ptr<Address>> &addressList) {
 	Content content;
 	content.setBodyFromUtf8(Utils::getResourceLists(addressList));
 	content.setContentType(ContentType::ResourceLists);
@@ -719,18 +713,18 @@ bool ClientGroupChatRoom::removeParticipant(const shared_ptr<Participant> &parti
 
 	// TODO handle one-to-one case ?
 	SalReferOp *referOp = new SalReferOp(cCore->sal.get());
-	LinphoneAddress *lAddr = L_GET_C_BACK_PTR(&(getConferenceAddress().asAddress()));
+	LinphoneAddress *lAddr = getConferenceAddress()->toC();
 	linphone_configure_op(cCore, referOp, lAddr, nullptr, false);
-	Address referToAddr = participant->getAddress().asAddress();
+	Address referToAddr(*participant->getAddress());
 	referToAddr.setParam("text");
 	referToAddr.setUriParam("method", "BYE");
-	referOp->sendRefer(referToAddr.getInternalAddress());
+	referOp->sendRefer(referToAddr.getImpl());
 	referOp->unref();
 
 	return true;
 }
 
-shared_ptr<Participant> ClientGroupChatRoom::findParticipant(const IdentityAddress &addr) const {
+shared_ptr<Participant> ClientGroupChatRoom::findParticipant(const std::shared_ptr<Address> &addr) const {
 	return getConference()->findParticipant(addr);
 }
 
@@ -761,12 +755,12 @@ void ClientGroupChatRoom::setParticipantAdminStatus(const shared_ptr<Participant
 	LinphoneCore *cCore = getCore()->getCCore();
 
 	SalReferOp *referOp = new SalReferOp(cCore->sal.get());
-	LinphoneAddress *lAddr = L_GET_C_BACK_PTR(&(getConferenceAddress().asAddress()));
+	LinphoneAddress *lAddr = getConferenceAddress()->toC();
 	linphone_configure_op(cCore, referOp, lAddr, nullptr, false);
-	Address referToAddr = participant->getAddress().asAddress();
+	Address referToAddr(*participant->getAddress());
 	referToAddr.setParam("text");
 	referToAddr.setParam("admin", Utils::toString(isAdmin));
-	referOp->sendRefer(referToAddr.getInternalAddress());
+	referOp->sendRefer(referToAddr.getImpl());
 	referOp->unref();
 }
 
@@ -840,13 +834,13 @@ void ClientGroupChatRoom::exhume() {
 		return;
 	}
 
-	const IdentityAddress &remoteParticipant = getParticipants().front()->getAddress();
+	const std::shared_ptr<Address> &remoteParticipant = getParticipants().front()->getAddress();
 	lInfo() << "Exhuming chat room [" << conference->getConferenceId() << "] with participant [" << remoteParticipant
 	        << "]";
 	d->localExhumePending = true;
 
 	Content content;
-	list<IdentityAddress> addresses;
+	list<std::shared_ptr<Address>> addresses;
 	addresses.push_front(remoteParticipant);
 	content.setBodyFromUtf8(Utils::getResourceLists(addresses));
 	content.setContentType(ContentType::ResourceLists);
@@ -856,7 +850,7 @@ void ClientGroupChatRoom::exhume() {
 	}
 
 	string conferenceFactoryUri = Core::getConferenceFactoryUri(getCore(), getConferenceId().getLocalAddress());
-	Address conferenceFactoryAddress = Address(conferenceFactoryUri);
+	std::shared_ptr<Address> conferenceFactoryAddress = Address::create(conferenceFactoryUri);
 	auto session = d->createSessionTo(conferenceFactoryAddress);
 	session->startInvite(nullptr, getUtf8Subject(), &content);
 	setState(ConferenceInterface::State::CreationPending);
@@ -891,7 +885,7 @@ void ClientGroupChatRoomPrivate::onExhumedConference(const ConferenceId &oldConf
 	L_Q();
 
 	const auto &conference = q->getConference();
-	const ConferenceAddress &addr = newConfId.getPeerAddress();
+	const std::shared_ptr<Address> &addr = newConfId.getPeerAddress();
 
 	conference->setConferenceAddress(addr);
 	static_pointer_cast<RemoteConference>(conference)->confParams->setConferenceAddress(addr);
@@ -904,7 +898,7 @@ void ClientGroupChatRoomPrivate::onExhumedConference(const ConferenceId &oldConf
 }
 
 // Will be called on A when A is sending a message into a chat room with B previously terminated by B
-void ClientGroupChatRoomPrivate::onLocallyExhumedConference(const Address &remoteContact) {
+void ClientGroupChatRoomPrivate::onLocallyExhumedConference(const std::shared_ptr<Address> &remoteContact) {
 	L_Q();
 
 	const auto &conference = q->getConference();
@@ -940,7 +934,7 @@ void ClientGroupChatRoomPrivate::onRemotelyExhumedConference(SalCallOp *op) {
 
 	const auto &conference = q->getConference();
 	ConferenceId oldConfId = conference->getConferenceId();
-	ConferenceId newConfId = ConferenceId(op->getRemoteContact(), oldConfId.getLocalAddress());
+	ConferenceId newConfId = ConferenceId(Address::create(op->getRemoteContact()), oldConfId.getLocalAddress());
 
 	if (q->getState() != ChatRoom::State::Terminated) {
 		lWarning() << "Conference is being exhumed but wasn't terminated first!";
@@ -983,8 +977,7 @@ void ClientGroupChatRoomPrivate::removeConferenceIdFromPreviousList(const Confer
 }
 
 // -----------------------------------------------------------------------------
-
-void ClientGroupChatRoom::onConferenceCreated(const ConferenceAddress &addr) {
+void ClientGroupChatRoom::onConferenceCreated(const std::shared_ptr<Address> &addr) {
 	L_D();
 
 	setConferenceId(ConferenceId(addr, getConferenceId().getLocalAddress()));
@@ -1007,7 +1000,7 @@ void ClientGroupChatRoom::onConferenceKeywordsChanged(const vector<string> &keyw
 		d->capabilities |= ClientGroupChatRoom::Capabilities::Ephemeral;
 }
 
-void ClientGroupChatRoom::onConferenceTerminated(BCTBX_UNUSED(const IdentityAddress &addr)) {
+void ClientGroupChatRoom::onConferenceTerminated(BCTBX_UNUSED(const std::shared_ptr<Address> &addr)) {
 	L_D();
 
 	static_pointer_cast<RemoteConference>(getConference())->eventHandler->unsubscribe();
@@ -1032,7 +1025,7 @@ void ClientGroupChatRoom::onConferenceTerminated(BCTBX_UNUSED(const IdentityAddr
 	}
 }
 
-void ClientGroupChatRoom::onFirstNotifyReceived(BCTBX_UNUSED(const IdentityAddress &addr)) {
+void ClientGroupChatRoom::onFirstNotifyReceived(BCTBX_UNUSED(const std::shared_ptr<Address> &addr)) {
 	L_D();
 
 	if (getState() != ConferenceInterface::State::Created) {
@@ -1141,8 +1134,8 @@ void ClientGroupChatRoom::onSecurityEvent(const shared_ptr<ConferenceSecurityEve
 	shared_ptr<ConferenceSecurityEvent> cleanEvent = nullptr;
 
 	// Remove faulty device if its address is invalid
-	IdentityAddress faultyDevice = event->getFaultyDeviceAddress();
-	if (!faultyDevice.isValid()) {
+	std::shared_ptr<Address> faultyDevice = event->getFaultyDeviceAddress();
+	if (!faultyDevice || !faultyDevice->isValid()) {
 		cleanEvent = make_shared<ConferenceSecurityEvent>(event->getCreationTime(), event->getConferenceId(),
 		                                                  event->getSecurityEventType());
 	}
@@ -1170,7 +1163,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded(const shared_ptr<ConferencePa
                                                    const std::shared_ptr<ParticipantDevice> &device) {
 	L_D();
 
-	const IdentityAddress &addr = event->getParticipantAddress();
+	const std::shared_ptr<Address> &addr = event->getParticipantAddress();
 	shared_ptr<Participant> participant;
 	if (getConference()->isMe(addr)) participant = getMe();
 	else participant = findParticipant(addr);
@@ -1456,7 +1449,7 @@ void ClientGroupChatRoom::sendEphemeralUpdate() {
 	} else {
 		session = d->createSession();
 
-		const IdentityAddress &remoteParticipant = getParticipants().front()->getAddress();
+		const std::shared_ptr<Address> &remoteParticipant = getParticipants().front()->getAddress();
 		lInfo() << "Re-INVITing " << remoteParticipant << " because ephemeral settings of chat room ["
 		        << conference->getConferenceId() << "] have changed";
 
diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h
index c5a22bd587d0b8532ece2aa2480f9c79ab4ef830..ba8daca6dba441b2025a270aa6ac93989324b092 100644
--- a/src/chat/chat-room/client-group-chat-room.h
+++ b/src/chat/chat-room/client-group-chat-room.h
@@ -60,7 +60,7 @@ public:
 	bool hasBeenLeft() const override;
 	bool isReadOnly() const override;
 
-	const ConferenceAddress &getConferenceAddress() const override;
+	const std::shared_ptr<Address> &getConferenceAddress() const override;
 
 	void deleteFromDb() override;
 
@@ -68,13 +68,13 @@ public:
 	std::list<std::shared_ptr<EventLog>> getHistoryRange(int begin, int end) const override;
 	int getHistorySize() const override;
 
-	bool addParticipant(const IdentityAddress &participantAddress) override;
+	bool addParticipant(const std::shared_ptr<Address> &participantAddress) override;
 	bool addParticipant(std::shared_ptr<Call> call) override {
 		return getConference()->addParticipant(call);
 	};
-	bool addParticipants(const std::list<IdentityAddress> &addresses) override;
+	bool addParticipants(const std::list<std::shared_ptr<Address>> &addresses) override;
 
-	void join(const IdentityAddress &participantAddress) override {
+	void join(const std::shared_ptr<Address> &participantAddress) override {
 		getConference()->join(participantAddress);
 	};
 	bool update(const ConferenceParamsInterface &newParameters) override {
@@ -83,7 +83,7 @@ public:
 
 	bool removeParticipant(const std::shared_ptr<Participant> &participant) override;
 
-	std::shared_ptr<Participant> findParticipant(const IdentityAddress &addr) const override;
+	std::shared_ptr<Participant> findParticipant(const std::shared_ptr<Address> &addr) const override;
 
 	std::shared_ptr<Participant> getMe() const override;
 	int getParticipantCount() const override;
@@ -113,7 +113,7 @@ public:
 
 private:
 	ClientGroupChatRoom(const std::shared_ptr<Core> &core,
-	                    const IdentityAddress &focus,
+	                    const std::shared_ptr<Address> &focus,
 	                    const ConferenceId &conferenceId,
 	                    const std::string &subject,
 	                    const Content &content,
@@ -122,7 +122,7 @@ private:
 
 	ClientGroupChatRoom(const std::shared_ptr<Core> &core,
 	                    const std::string &factoryUri,
-	                    const IdentityAddress &me,
+	                    const std::shared_ptr<const Address> &me,
 	                    const std::string &subject,
 	                    CapabilitiesMask capabilities,
 	                    const std::shared_ptr<ChatRoomParams> &params);
@@ -138,18 +138,18 @@ private:
 	                    unsigned int lastNotifyId,
 	                    bool hasBeenLeft = false);
 
-	void sendInvite(std::shared_ptr<CallSession> &session, const std::list<IdentityAddress> &addressList);
+	void sendInvite(std::shared_ptr<CallSession> &session, const std::list<std::shared_ptr<Address>> &addressList);
 	void setConferenceId(const ConferenceId &conferenceId);
 	void sendEphemeralUpdate();
 
 	// TODO: Move me in ClientGroupChatRoomPrivate.
 	// ALL METHODS AFTER THIS POINT.
 
-	void onConferenceCreated(const ConferenceAddress &addr) override;
+	void onConferenceCreated(const std::shared_ptr<Address> &addr) override;
 	void onConferenceKeywordsChanged(const std::vector<std::string> &keywords) override;
-	void onConferenceTerminated(const IdentityAddress &addr) override;
+	void onConferenceTerminated(const std::shared_ptr<Address> &addr) override;
 	void onSecurityEvent(const std::shared_ptr<ConferenceSecurityEvent> &event) override;
-	void onFirstNotifyReceived(const IdentityAddress &addr) override;
+	void onFirstNotifyReceived(const std::shared_ptr<Address> &addr) override;
 	void onFullStateReceived() override;
 	void onParticipantAdded(const std::shared_ptr<ConferenceParticipantEvent> &event,
 	                        const std::shared_ptr<Participant> &participant) override;
diff --git a/src/chat/chat-room/client-group-to-basic-chat-room.cpp b/src/chat/chat-room/client-group-to-basic-chat-room.cpp
index cd1cfb760b9efa0b74d42bdc08d33de8e95f9f9f..0988b90f8ee2af52f55aca28790aefa2e6541a5d 100644
--- a/src/chat/chat-room/client-group-to-basic-chat-room.cpp
+++ b/src/chat/chat-room/client-group-to-basic-chat-room.cpp
@@ -94,7 +94,7 @@ public:
 	}
 
 private:
-	list<IdentityAddress> invitedAddresses;
+	list<std::shared_ptr<Address>> invitedAddresses;
 
 	L_DECLARE_PUBLIC(ClientGroupToBasicChatRoom);
 };
@@ -105,7 +105,7 @@ ClientGroupToBasicChatRoom::ClientGroupToBasicChatRoom(const shared_ptr<ChatRoom
     : ProxyChatRoom(*new ClientGroupToBasicChatRoomPrivate, chatRoom) {
 }
 
-bool ClientGroupToBasicChatRoom::addParticipant(const IdentityAddress &participantAddress) {
+bool ClientGroupToBasicChatRoom::addParticipant(const std::shared_ptr<Address> &participantAddress) {
 	L_D();
 	if (getState() == ConferenceInterface::State::Instantiated) {
 		d->invitedAddresses.clear();
@@ -113,7 +113,8 @@ bool ClientGroupToBasicChatRoom::addParticipant(const IdentityAddress &participa
 	}
 	return ProxyChatRoom::addParticipant(participantAddress);
 }
-bool ClientGroupToBasicChatRoom::addParticipants(const list<IdentityAddress> &addresses) {
+
+bool ClientGroupToBasicChatRoom::addParticipants(const list<std::shared_ptr<Address>> &addresses) {
 	L_D();
 	if ((getState() == ConferenceInterface::State::Instantiated) && (addresses.size() == 1))
 		d->invitedAddresses = addresses;
diff --git a/src/chat/chat-room/client-group-to-basic-chat-room.h b/src/chat/chat-room/client-group-to-basic-chat-room.h
index 6824c62c95ad59f45b684289a824eca0c52833fb..952b88843dcf7a26af997b42432a7dbfbfb31a17 100644
--- a/src/chat/chat-room/client-group-to-basic-chat-room.h
+++ b/src/chat/chat-room/client-group-to-basic-chat-room.h
@@ -35,11 +35,11 @@ public:
 
 	// Addressing compilation error -Werror=overloaded-virtual
 	using LinphonePrivate::ConferenceInterface::addParticipant;
-	bool addParticipant(const IdentityAddress &participantAddress) override;
+	bool addParticipant(const std::shared_ptr<Address> &participantAddress) override;
 
 	// Addressing compilation error -Werror=overloaded-virtual
 	using LinphonePrivate::ConferenceInterface::addParticipants;
-	bool addParticipants(const std::list<IdentityAddress> &addresses) override;
+	bool addParticipants(const std::list<std::shared_ptr<Address>> &addresses) override;
 
 private:
 	L_DECLARE_PRIVATE(ClientGroupToBasicChatRoom);
diff --git a/src/chat/chat-room/proxy-chat-room.cpp b/src/chat/chat-room/proxy-chat-room.cpp
index 4c27fe08e90d1761faabfc257ffdea073359ff57..608f073a0e689acbb5218c243b38770626ad12c3 100644
--- a/src/chat/chat-room/proxy-chat-room.cpp
+++ b/src/chat/chat-room/proxy-chat-room.cpp
@@ -18,6 +18,8 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <bctoolbox/defs.h>
+
 #include "basic-to-client-group-chat-room.h"
 #include "c-wrapper/c-wrapper.h"
 #include "chat-room-p.h"
@@ -60,12 +62,12 @@ const ConferenceId &ProxyChatRoom::getConferenceId() const {
 	return d->chatRoom->getConferenceId();
 }
 
-const IdentityAddress &ProxyChatRoom::getPeerAddress() const {
+const std::shared_ptr<Address> &ProxyChatRoom::getPeerAddress() const {
 	L_D();
 	return d->chatRoom->getPeerAddress();
 }
 
-const IdentityAddress &ProxyChatRoom::getLocalAddress() const {
+const std::shared_ptr<Address> &ProxyChatRoom::getLocalAddress() const {
 	L_D();
 	return d->chatRoom->getLocalAddress();
 }
@@ -193,7 +195,7 @@ bool ProxyChatRoom::isRemoteComposing() const {
 	return d->chatRoom->isRemoteComposing();
 }
 
-list<IdentityAddress> ProxyChatRoom::getComposingAddresses() const {
+list<std::shared_ptr<Address>> ProxyChatRoom::getComposingAddresses() const {
 	L_D();
 	return d->chatRoom->getComposingAddresses();
 }
@@ -288,16 +290,16 @@ bool ProxyChatRoom::ephemeralSupportedByAllParticipants() const {
 
 // -----------------------------------------------------------------------------
 
-const ConferenceAddress &ProxyChatRoom::getConferenceAddress() const {
+const std::shared_ptr<Address> &ProxyChatRoom::getConferenceAddress() const {
 	L_D();
 	return d->chatRoom->getConferenceAddress();
 }
 
 // -----------------------------------------------------------------------------
-void ProxyChatRoom::allowCpim(bool) {
+void ProxyChatRoom::allowCpim(BCTBX_UNUSED(bool value)) {
 }
 
-void ProxyChatRoom::allowMultipart(bool) {
+void ProxyChatRoom::allowMultipart(BCTBX_UNUSED(bool value)) {
 }
 
 bool ProxyChatRoom::canHandleCpim() const {
@@ -315,12 +317,12 @@ bool ProxyChatRoom::addParticipant(std::shared_ptr<Call> call) {
 	return d->chatRoom->addParticipant(call);
 }
 
-bool ProxyChatRoom::addParticipant(const IdentityAddress &participantAddress) {
+bool ProxyChatRoom::addParticipant(const std::shared_ptr<Address> &participantAddress) {
 	L_D();
 	return d->chatRoom->addParticipant(participantAddress);
 }
 
-bool ProxyChatRoom::addParticipants(const list<IdentityAddress> &addresses) {
+bool ProxyChatRoom::addParticipants(const list<std::shared_ptr<Address>> &addresses) {
 	L_D();
 	return d->chatRoom->addParticipants(addresses);
 }
@@ -335,7 +337,7 @@ bool ProxyChatRoom::removeParticipants(const list<shared_ptr<Participant>> &part
 	return d->chatRoom->removeParticipants(participants);
 }
 
-shared_ptr<Participant> ProxyChatRoom::findParticipant(const IdentityAddress &participantAddress) const {
+shared_ptr<Participant> ProxyChatRoom::findParticipant(const std::shared_ptr<Address> &participantAddress) const {
 	L_D();
 	return d->chatRoom->findParticipant(participantAddress);
 }
@@ -384,7 +386,7 @@ void ProxyChatRoom::join() {
 	d->chatRoom->join();
 }
 
-void ProxyChatRoom::join(const IdentityAddress &participantAddress) {
+void ProxyChatRoom::join(const std::shared_ptr<Address> &participantAddress) {
 	L_D();
 	d->chatRoom->join(participantAddress);
 }
diff --git a/src/chat/chat-room/proxy-chat-room.h b/src/chat/chat-room/proxy-chat-room.h
index d986de5dcfbd0827493141cd3fd8812cea9cd727..976826b8de5b8908b055c84112a79d2250ca751c 100644
--- a/src/chat/chat-room/proxy-chat-room.h
+++ b/src/chat/chat-room/proxy-chat-room.h
@@ -36,8 +36,8 @@ class LINPHONE_PUBLIC ProxyChatRoom : public AbstractChatRoom {
 public:
 	const ConferenceId &getConferenceId() const override;
 
-	const IdentityAddress &getPeerAddress() const override;
-	const IdentityAddress &getLocalAddress() const override;
+	const std::shared_ptr<Address> &getPeerAddress() const override;
+	const std::shared_ptr<Address> &getLocalAddress() const override;
 
 	time_t getCreationTime() const override;
 	time_t getLastUpdateTime() const override;
@@ -67,7 +67,7 @@ public:
 
 	void compose() override;
 	bool isRemoteComposing() const override;
-	std::list<IdentityAddress> getComposingAddresses() const override;
+	std::list<std::shared_ptr<Address>> getComposingAddresses() const override;
 
 	std::shared_ptr<ChatMessage> createChatMessage() override;
 	std::shared_ptr<ChatMessage>
@@ -93,7 +93,7 @@ public:
 	AbstractChatRoom::EphemeralMode getEphemeralMode() const override;
 	bool ephemeralSupportedByAllParticipants() const override;
 
-	const ConferenceAddress &getConferenceAddress() const override;
+	const std::shared_ptr<Address> &getConferenceAddress() const override;
 	std::shared_ptr<Conference> getConference() const override;
 	bool canHandleParticipants() const override;
 
@@ -105,7 +105,7 @@ public:
 	bool removeParticipant(const std::shared_ptr<Participant> &participant) override;
 	bool removeParticipants(const std::list<std::shared_ptr<Participant>> &participants) override;
 
-	std::shared_ptr<Participant> findParticipant(const IdentityAddress &participantAddress) const override;
+	std::shared_ptr<Participant> findParticipant(const std::shared_ptr<Address> &participantAddress) const override;
 
 	std::shared_ptr<Participant> getMe() const override;
 	int getParticipantCount() const override;
@@ -131,10 +131,10 @@ public:
 		chatListeners.push_back(listener);
 	}
 
-	bool addParticipant(const IdentityAddress &participantAddress) override;
+	bool addParticipant(const std::shared_ptr<Address> &participantAddress) override;
 	bool addParticipant(std::shared_ptr<Call> call) override;
-	bool addParticipants(const std::list<IdentityAddress> &addresses) override;
-	void join(const IdentityAddress &participantAddress) override;
+	bool addParticipants(const std::list<std::shared_ptr<Address>> &addresses) override;
+	void join(const std::shared_ptr<Address> &participantAddress) override;
 	bool update(const ConferenceParamsInterface &newParameters) override;
 
 	void setState(ConferenceInterface::State state) override;
diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h
index 5e2faced90ba26009391c02b4e924ad5e9030621..0a46c9ee86e28342c7616debb032d0d1f5808a9c 100644
--- a/src/chat/chat-room/server-group-chat-room-p.h
+++ b/src/chat/chat-room/server-group-chat-room-p.h
@@ -39,19 +39,14 @@
 
 LINPHONE_BEGIN_NAMESPACE
 
-class ParticipantDevice;
-
 class ParticipantDeviceIdentity
     : public bellesip::HybridObject<LinphoneParticipantDeviceIdentity, ParticipantDeviceIdentity> {
 public:
-	ParticipantDeviceIdentity(const Address &address, const std::string &name);
+	ParticipantDeviceIdentity(const std::shared_ptr<Address> &address, const std::string &name);
 	void setCapabilityDescriptor(const std::string &capabilities);
-	const Address &getAddress() const {
+	const std::shared_ptr<Address> &getAddress() const {
 		return mDeviceAddress;
 	}
-	const LinphoneAddress *getLinphoneAddress() const {
-		return mDeviceAddressCache;
-	}
 	const std::string &getName() const {
 		return mDeviceName;
 	}
@@ -61,8 +56,7 @@ public:
 	virtual ~ParticipantDeviceIdentity();
 
 private:
-	Address mDeviceAddress;
-	LinphoneAddress *mDeviceAddressCache; // To be removed once Address becomes an HybridObject.
+	std::shared_ptr<Address> mDeviceAddress;
 	std::string mDeviceName;
 	std::string mCapabilityDescriptor; // +org.linphone.specs capability descriptor
 };
@@ -76,7 +70,7 @@ public:
 
 	virtual ~ServerGroupChatRoomPrivate() = default;
 
-	std::shared_ptr<Participant> addParticipant(const IdentityAddress &participantAddress);
+	std::shared_ptr<Participant> addParticipant(const std::shared_ptr<Address> &participantAddress);
 	void removeParticipant(const std::shared_ptr<Participant> &participant);
 
 	void setParticipantDeviceState(const std::shared_ptr<ParticipantDevice> &device,
@@ -101,17 +95,17 @@ public:
 
 	bool initializeParticipants(const std::shared_ptr<Participant> &initiator, SalCallOp *op);
 	void resumeParticipant(const std::shared_ptr<Participant> &participant);
-	bool subscribeRegistrationForParticipants(const std::list<IdentityAddress> &participants, bool newInvited);
-	void unSubscribeRegistrationForParticipant(const IdentityAddress &identAddresses);
+	bool subscribeRegistrationForParticipants(const std::list<std::shared_ptr<Address>> &participants, bool newInvited);
+	void unSubscribeRegistrationForParticipant(const std::shared_ptr<Address> &identAddresses);
 	void handleSubjectChange(SalCallOp *op);
 	void handleEphemeralSettingsChange(const std::shared_ptr<CallSession> &session);
 	void setEphemeralLifetime(long time, const std::shared_ptr<CallSession> &session);
 	void setEphemeralMode(AbstractChatRoom::EphemeralMode mode, const std::shared_ptr<CallSession> &session);
 
-	void setConferenceAddress(const ConferenceAddress &conferenceAddress);
-	void updateParticipantDevices(const IdentityAddress &addr,
+	void setConferenceAddress(const std::shared_ptr<Address> &conferenceAddress);
+	void updateParticipantDevices(const std::shared_ptr<Address> &addr,
 	                              const std::list<std::shared_ptr<ParticipantDeviceIdentity>> &devices);
-	void setParticipantDevicesAtCreation(const IdentityAddress &addr,
+	void setParticipantDevicesAtCreation(const std::shared_ptr<Address> &addr,
 	                                     const std::list<std::shared_ptr<ParticipantDeviceIdentity>> &devices);
 	void updateParticipantDeviceSession(const std::shared_ptr<ParticipantDevice> &device,
 	                                    bool freslyRegistered = false);
@@ -122,9 +116,9 @@ public:
 	LinphoneReason onSipMessageReceived(SalOp *op, const SalMessage *message) override;
 
 	/*These are the two methods called by the registration subscription module*/
-	void setParticipantDevices(const IdentityAddress &addr,
+	void setParticipantDevices(const std::shared_ptr<Address> &addr,
 	                           const std::list<std::shared_ptr<ParticipantDeviceIdentity>> &devices);
-	void notifyParticipantDeviceRegistration(const IdentityAddress &participantDevice);
+	void notifyParticipantDeviceRegistration(const std::shared_ptr<Address> &participantDevice);
 
 private:
 	struct Message {
@@ -132,7 +126,7 @@ private:
 		        const ContentType &contentType,
 		        const std::string &text,
 		        const SalCustomHeader *salCustomHeaders)
-		    : fromAddr(from) {
+		    : fromAddr(Address::create(from)) {
 			content.setContentType(contentType);
 			if (!text.empty()) content.setBodyFromUtf8(text);
 			if (salCustomHeaders) customHeaders = sal_custom_header_clone(salCustomHeaders);
@@ -142,7 +136,7 @@ private:
 			if (customHeaders) sal_custom_header_free(customHeaders);
 		}
 
-		IdentityAddress fromAddr;
+		std::shared_ptr<Address> fromAddr;
 		Content content;
 		std::chrono::system_clock::time_point timestamp = std::chrono::system_clock::now();
 		SalCustomHeader *customHeaders = nullptr;
@@ -154,15 +148,16 @@ private:
 	void addParticipantDevice(const std::shared_ptr<Participant> &participant,
 	                          const std::shared_ptr<ParticipantDeviceIdentity> &deviceInfo);
 	void designateAdmin();
-	void sendMessage(const std::shared_ptr<Message> &message, const IdentityAddress &deviceAddr);
+	void sendMessage(const std::shared_ptr<Message> &message, const std::shared_ptr<Address> &deviceAddr);
 	void finalizeCreation();
 	std::shared_ptr<CallSession> makeSession(const std::shared_ptr<ParticipantDevice> &device);
 	void inviteDevice(const std::shared_ptr<ParticipantDevice> &device);
 	void byeDevice(const std::shared_ptr<ParticipantDevice> &device);
 	bool isAdminLeft() const;
 	void queueMessage(const std::shared_ptr<Message> &message);
-	void queueMessage(const std::shared_ptr<Message> &msg, const IdentityAddress &deviceAddress);
-	void removeParticipantDevice(const std::shared_ptr<Participant> &participant, const IdentityAddress &deviceAddress);
+	void queueMessage(const std::shared_ptr<Message> &msg, const std::shared_ptr<Address> &deviceAddress);
+	void removeParticipantDevice(const std::shared_ptr<Participant> &participant,
+	                             const std::shared_ptr<Address> &deviceAddress);
 
 	void onParticipantDeviceLeft(const std::shared_ptr<ParticipantDevice> &device);
 	void onBye(const std::shared_ptr<ParticipantDevice> &participantLeaving);
@@ -192,8 +187,8 @@ private:
 		                         // holding subscriptions.
 	};
 
-	std::list<IdentityAddress> invitedParticipants; // participants in the process of being added to the chatroom, while
-	                                                // for registration information.
+	std::list<Address> invitedParticipants; // participants in the process of being added to the chatroom, while for
+	                                        // registration information.
 	ChatRoomListener *chatRoomListener = this;
 	std::map<std::string, RegistrationSubscriptionContext>
 	    registrationSubscriptions;               /*map of registrationSubscriptions for each participant*/
diff --git a/src/chat/chat-room/server-group-chat-room.cpp b/src/chat/chat-room/server-group-chat-room.cpp
index ce126c4631a72849e947af7ffbdba10585c46659..22c9fc264cee72b840d43e8ab33047733a6b37d6 100644
--- a/src/chat/chat-room/server-group-chat-room.cpp
+++ b/src/chat/chat-room/server-group-chat-room.cpp
@@ -23,7 +23,6 @@
 #include <bctoolbox/defs.h>
 
 #include "address/address.h"
-#include "address/identity-address.h"
 #include "c-wrapper/c-wrapper.h"
 #include "c-wrapper/internal/c-tools.h"
 #include "chat/chat-message/chat-message-p.h"
@@ -53,9 +52,8 @@ LINPHONE_BEGIN_NAMESPACE
 
 // -----------------------------------------------------------------------------
 
-ParticipantDeviceIdentity::ParticipantDeviceIdentity(const Address &address, const string &name)
+ParticipantDeviceIdentity::ParticipantDeviceIdentity(const std::shared_ptr<Address> &address, const string &name)
     : mDeviceAddress(address), mDeviceName(name) {
-	mDeviceAddressCache = linphone_address_new(address.asString().c_str());
 }
 
 void ParticipantDeviceIdentity::setCapabilityDescriptor(const string &capabilities) {
@@ -63,7 +61,6 @@ void ParticipantDeviceIdentity::setCapabilityDescriptor(const string &capabiliti
 }
 
 ParticipantDeviceIdentity::~ParticipantDeviceIdentity() {
-	linphone_address_unref(mDeviceAddressCache);
 }
 
 // -----------------------------------------------------------------------------
@@ -82,7 +79,7 @@ ParticipantDeviceIdentity::~ParticipantDeviceIdentity() {
 		bctbx_list_free_with_data(callbacksCopy, (bctbx_list_free_func)belle_sip_object_unref);                        \
 	} while (0)
 
-shared_ptr<Participant> ServerGroupChatRoomPrivate::addParticipant(const IdentityAddress &addr) {
+shared_ptr<Participant> ServerGroupChatRoomPrivate::addParticipant(const std::shared_ptr<Address> &addr) {
 	L_Q();
 
 	shared_ptr<Participant> participant = q->findCachedParticipant(addr);
@@ -128,7 +125,7 @@ void ServerGroupChatRoomPrivate::setParticipantDeviceState(const shared_ptr<Part
 	// If a participant is about to leave and its call session state is End, it will be released during shutdown event
 	// though the participant may not be notified yet as it is offline
 	if (linphone_core_get_global_state(q->getCore()->getCCore()) == LinphoneGlobalOn) {
-		string address(device->getAddress().asString());
+		string address(device->getAddress()->toString());
 		lInfo() << q << ": Set participant device '" << address << "' state to " << state;
 		device->setState(state, notify);
 		q->getCore()->getPrivate()->mainDb->updateChatRoomParticipantDevice(q->getSharedFromThis(), device);
@@ -166,18 +163,20 @@ void ServerGroupChatRoomPrivate::confirmCreation() {
 	 * set according to the proxy config used to receive the INVITE.
 	 */
 
-	LinphoneProxyConfig *cfg = session->getPrivate()->getDestProxy();
-	if (!cfg) cfg = linphone_core_get_default_proxy_config(L_GET_C_BACK_PTR(q->getCore()));
-	LinphoneAddress *addr = linphone_address_clone(linphone_proxy_config_get_identity_address(cfg));
+	auto destAccount = session->getPrivate()->getDestAccount();
+	if (!destAccount) {
+		destAccount = Account::toCpp(linphone_core_get_default_account(q->getCore()->getCCore()))->getSharedFromThis();
+	}
+	const auto accountParams = destAccount->getAccountParams();
+	auto addr = accountParams->getIdentityAddress()->clone()->toSharedPtr();
 
 	char token[17];
 	ostringstream os;
 
 	belle_sip_random_token(token, sizeof(token));
 	os << "chatroom-" << token;
-	linphone_address_set_username(addr, os.str().c_str());
-	q->getConference()->confParams->setConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr));
-	linphone_address_unref(addr);
+	addr->setUsername(os.str());
+	q->getConference()->confParams->setConferenceAddress(addr);
 
 	/* Application (conference server) callback to register the name.
 	 * In response, the conference server will call setConferenceAddress().
@@ -244,22 +243,22 @@ void ServerGroupChatRoomPrivate::confirmJoining(SalCallOp *op) {
 	L_Q();
 	shared_ptr<Participant> participant;
 
-	Address contactAddr(op->getRemoteContact());
-	if (contactAddr.getUriParamValue("gr").empty()) {
+	std::shared_ptr<Address> contactAddr = Address::create(op->getRemoteContact());
+	if (contactAddr->getUriParamValue("gr").empty()) {
 		lError() << q << ": Declining INVITE because the contact does not have a 'gr' uri parameter ["
-		         << contactAddr.asString() << "]";
+		         << contactAddr->toString() << "]";
 		op->decline(SalReasonDeclined, "");
 		joiningPendingAfterCreation = false;
 		return;
 	}
 
-	IdentityAddress gruu(contactAddr);
+	std::shared_ptr<Address> gruu(contactAddr);
 	shared_ptr<ParticipantDevice> device;
 	shared_ptr<CallSession> session;
 	if (joiningPendingAfterCreation) {
 		// Check if the participant is already there, this INVITE may come from an unknown device of an already present
 		// participant
-		participant = addParticipant(IdentityAddress(op->getFrom()));
+		participant = addParticipant(Address::create(op->getFrom()));
 		participant->setAdmin(true);
 		device = participant->addDevice(gruu);
 		session = device->getSession();
@@ -277,7 +276,7 @@ void ServerGroupChatRoomPrivate::confirmJoining(SalCallOp *op) {
 		}
 	} else {
 		// INVITE coming from an invited participant
-		participant = q->findCachedParticipant(IdentityAddress(op->getFrom()));
+		participant = q->findCachedParticipant(Address::create(op->getFrom()));
 		if (!participant) {
 			lError() << q << ": Declining INVITE coming from someone that is not a participant";
 			op->decline(SalReasonDeclined, "");
@@ -306,13 +305,12 @@ void ServerGroupChatRoomPrivate::confirmJoining(SalCallOp *op) {
 		CallSessionParams params;
 		// params.addCustomContactParameter("isfocus");
 		session = participant->createSession(*q->getConference().get(), &params, false, this);
-		session->configure(LinphoneCallIncoming, nullptr, op, participant->getAddress().asAddress(),
-		                   Address(op->getTo()));
+		session->configure(LinphoneCallIncoming, nullptr, op, participant->getAddress(), Address::create(op->getTo()));
 		session->startIncomingNotification(false);
-		Address addr = q->getConference()->getConferenceAddress().asAddress();
-		addr.setParam("isfocus");
+		std::shared_ptr<Address> addr = q->getConferenceAddress()->clone()->toSharedPtr();
+		addr->setParam("isfocus");
 		// to force is focus to be added
-		session->getPrivate()->getOp()->setContactAddress(addr.getInternalAddress());
+		session->getPrivate()->getOp()->setContactAddress(addr->getImpl());
 		device->setSession(session);
 	}
 
@@ -342,23 +340,23 @@ void ServerGroupChatRoomPrivate::confirmJoining(SalCallOp *op) {
 void ServerGroupChatRoomPrivate::confirmRecreation(SalCallOp *op) {
 	L_Q();
 
-	auto participant = q->findCachedParticipant(IdentityAddress(op->getFrom()));
+	const auto from = Address::create(op->getFrom());
+	const auto to = Address::create(op->getTo());
+	auto participant = q->findCachedParticipant(from);
 	if (!participant) {
 		lError() << q << " bug - " << op->getFrom() << " is not a participant.";
 		op->decline(SalReasonInternalError, "");
 		return;
 	}
 
-	IdentityAddress confAddr(q->getConference()->getConferenceAddress());
-
 	lInfo() << q << " is re-joined by " << participant->getAddress();
-	Address addr(confAddr.asAddress());
-	addr.setParam("isfocus");
 	shared_ptr<Participant> me = q->getMe();
 	shared_ptr<CallSession> session = me->createSession(*q->getConference().get(), nullptr, false, this);
-	session->configure(LinphoneCallIncoming, nullptr, op, Address(op->getFrom()), Address(op->getTo()));
+	session->configure(LinphoneCallIncoming, nullptr, op, from, to);
 	session->startIncomingNotification(false);
-	session->redirect(addr);
+	auto confAddr = *q->getConferenceAddress();
+	confAddr.setParam("isfocus");
+	session->redirect(confAddr);
 }
 
 void ServerGroupChatRoomPrivate::declineSession(const shared_ptr<CallSession> &session, LinphoneReason reason) {
@@ -374,7 +372,7 @@ void ServerGroupChatRoomPrivate::dispatchQueuedMessages() {
 		 */
 
 		for (const auto &device : participant->getDevices()) {
-			string uri(device->getAddress().asString());
+			string uri(device->getAddress()->toString());
 			auto &msgQueue = queuedMessages[uri];
 
 			if (!msgQueue.empty()) {
@@ -411,14 +409,14 @@ void ServerGroupChatRoomPrivate::removeParticipant(const shared_ptr<Participant>
 	}
 
 	for (const auto &p : q->getParticipants()) {
-		if (participant->getAddress() == p->getAddress()) {
-			lInfo() << q << " 'participant ' " << p->getAddress() << " no more authorized'";
+		if (*participant->getAddress() == *p->getAddress()) {
+			lInfo() << q << " 'participant ' " << p->getAddress()->toString() << " no more authorized'";
 			q->getConference()->removeParticipant(p);
 			break;
 		}
 	}
 
-	queuedMessages.erase(participant->getAddress().asString());
+	queuedMessages.erase(participant->getAddress()->toString());
 
 	shared_ptr<ConferenceParticipantEvent> event =
 	    q->getConference()->notifyParticipantRemoved(time(nullptr), false, participant);
@@ -497,17 +495,18 @@ void ServerGroupChatRoomPrivate::setEphemeralLifetime(long lifetime, const share
  * automatically added to the invitedParticipants list, so that when registration info arrives, they
  * will be added.
  */
-bool ServerGroupChatRoomPrivate::subscribeRegistrationForParticipants(const std::list<IdentityAddress> &identAddresses,
-                                                                      bool newInvited) {
+bool ServerGroupChatRoomPrivate::subscribeRegistrationForParticipants(
+    const std::list<std::shared_ptr<Address>> &identAddresses, bool newInvited) {
 	L_Q();
-	std::list<IdentityAddress> requestedAddresses;
+	std::list<Address> requestedAddresses;
 	bool subscriptionsPending = false;
 
 	// Subscribe to the registration events from the proxy
 	for (const auto &addr : identAddresses) {
-		if (registrationSubscriptions.find(addr.asString()) == registrationSubscriptions.end()) {
-			requestedAddresses.emplace_back(addr);
-			if (newInvited) invitedParticipants.emplace_back(addr);
+		const auto cleanedAddr = addr->getUri();
+		if (registrationSubscriptions.find(cleanedAddr.toString()) == registrationSubscriptions.end()) {
+			requestedAddresses.emplace_back(cleanedAddr);
+			if (newInvited) invitedParticipants.emplace_back(cleanedAddr);
 			unnotifiedRegistrationSubscriptions++;
 			subscriptionsPending = true;
 		}
@@ -515,19 +514,18 @@ bool ServerGroupChatRoomPrivate::subscribeRegistrationForParticipants(const std:
 
 	for (const auto &addr : requestedAddresses) {
 		LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q);
-		LinphoneAddress *laddr = linphone_address_new(addr.asString().c_str());
-		registrationSubscriptions[addr.asString()].context =
+		const auto laddr = addr.toC();
+		registrationSubscriptions[addr.toString()].context =
 		    nullptr; // we 'll put here later a context pointer returned by the callback.
 		CALL_CHAT_ROOM_CBS(cr, ParticipantRegistrationSubscriptionRequested,
 		                   participant_registration_subscription_requested, cr, laddr);
-		linphone_address_unref(laddr);
 	}
 	return subscriptionsPending;
 }
 
-void ServerGroupChatRoomPrivate::unSubscribeRegistrationForParticipant(const IdentityAddress &identAddress) {
+void ServerGroupChatRoomPrivate::unSubscribeRegistrationForParticipant(const std::shared_ptr<Address> &identAddress) {
 	L_Q();
-	auto p = registrationSubscriptions.find(identAddress.asString());
+	auto p = registrationSubscriptions.find(identAddress->toString());
 	if (p == registrationSubscriptions.end()) {
 		lError() << q << " no active subscription for " << identAddress;
 		return;
@@ -535,22 +533,21 @@ void ServerGroupChatRoomPrivate::unSubscribeRegistrationForParticipant(const Ide
 	registrationSubscriptions.erase(p);
 
 	LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q);
-	LinphoneAddress *laddr = linphone_address_new(identAddress.asString().c_str());
+	LinphoneAddress *laddr = identAddress->toC();
 	CALL_CHAT_ROOM_CBS(cr, ParticipantRegistrationUnsubscriptionRequested,
 	                   participant_registration_unsubscription_requested, cr, laddr);
-	linphone_address_unref(laddr);
 }
 
 bool ServerGroupChatRoomPrivate::initializeParticipants(const shared_ptr<Participant> &initiator, SalCallOp *op) {
 
 	handleSubjectChange(op);
 	// Handle participants addition
-	list<IdentityAddress> identAddresses = Utils::parseResourceLists(op->getRemoteBody());
+	list<std::shared_ptr<Address>> identAddresses = Utils::parseResourceLists(op->getRemoteBody());
 	// DO not try to add participants with invalid address
 	for (auto it = identAddresses.begin(); it != identAddresses.end();) {
-		if (!((*it).isValid())) {
+		if (!((*it)->isValid())) {
 			lError() << "ServerGroupChatRoomPrivate::initializeParticipants(): removing invalid address "
-			         << ((*it).asString()) << " at position " << std::distance(it, identAddresses.begin());
+			         << ((*it)->toString()) << " at position " << std::distance(it, identAddresses.begin());
 			it = identAddresses.erase(it);
 		} else {
 			++it;
@@ -583,7 +580,7 @@ bool ServerGroupChatRoomPrivate::initializeParticipants(const shared_ptr<Partici
 LinphoneReason ServerGroupChatRoomPrivate::onSipMessageReceived(SalOp *op, const SalMessage *message) {
 	L_Q();
 	// Check that the message is coming from a participant of the chat room
-	IdentityAddress fromAddr(op->getFrom());
+	std::shared_ptr<Address> fromAddr = Address::create(op->getFrom());
 	if (!q->findParticipant(fromAddr)) {
 		return LinphoneReasonForbidden;
 	}
@@ -599,10 +596,10 @@ LinphoneReason ServerGroupChatRoomPrivate::onSipMessageReceived(SalOp *op, const
 
 // TODO: Move to conference.cpp?
 // If conference address is not valid, then the conference fails to create
-void ServerGroupChatRoomPrivate::setConferenceAddress(const ConferenceAddress &conferenceAddress) {
+void ServerGroupChatRoomPrivate::setConferenceAddress(const std::shared_ptr<Address> &conferenceAddress) {
 	L_Q();
 
-	if (!conferenceAddress.isValid()) {
+	if (!conferenceAddress || !conferenceAddress->isValid()) {
 		shared_ptr<CallSession> session = q->getMe()->getSession();
 		LinphoneErrorInfo *ei = linphone_error_info_new();
 		linphone_error_info_set(ei, "SIP", LinphoneReasonUnknown, 500, "Server internal error", NULL);
@@ -617,17 +614,17 @@ void ServerGroupChatRoomPrivate::setConferenceAddress(const ConferenceAddress &c
 		return;
 	}
 	q->getConference()->confParams->setConferenceAddress(conferenceAddress);
-	lInfo() << "The ServerGroupChatRoom has been given the address " << conferenceAddress.asString()
+	lInfo() << "The ServerGroupChatRoom has been given the address " << conferenceAddress->toString()
 	        << ", now finalizing its creation";
 	finalizeCreation();
 }
 
-void ServerGroupChatRoomPrivate::updateParticipantDevices(const IdentityAddress &participantAddress,
+void ServerGroupChatRoomPrivate::updateParticipantDevices(const std::shared_ptr<Address> &participantAddress,
                                                           const list<shared_ptr<ParticipantDeviceIdentity>> &devices) {
 	L_Q();
 	bool newParticipantReginfo = false;
 
-	auto it = registrationSubscriptions.find(participantAddress.asString());
+	auto it = registrationSubscriptions.find(participantAddress->toString());
 
 	/*
 	 * For security, since registration information might come from outside, make sure that the device list we are asked
@@ -635,11 +632,11 @@ void ServerGroupChatRoomPrivate::updateParticipantDevices(const IdentityAddress
 	 * process of being added to the chatroom
 	 */
 	if (it == registrationSubscriptions.end()) {
-		lError() << "updateParticipantDevices(): " << participantAddress << " registration info was not requested.";
+		lError() << "updateParticipantDevices(): " << *participantAddress << " registration info was not requested.";
 		return;
 	} else {
 		// Check if this registration information is for a participant in the process of being added.
-		auto it = find(invitedParticipants.begin(), invitedParticipants.end(), participantAddress);
+		auto it = std::find(invitedParticipants.begin(), invitedParticipants.end(), *participantAddress);
 		if (it != invitedParticipants.end()) {
 			invitedParticipants.erase(it);
 			unnotifiedRegistrationSubscriptions--;
@@ -652,7 +649,7 @@ void ServerGroupChatRoomPrivate::updateParticipantDevices(const IdentityAddress
 		if (!devices.empty()) {
 			participant = addParticipant(participantAddress);
 		} else {
-			lInfo() << q << participantAddress << " has no compatible devices.";
+			lInfo() << q << " " << participantAddress->toString() << " has no compatible devices.";
 			unSubscribeRegistrationForParticipant(participantAddress);
 			return;
 		}
@@ -664,17 +661,18 @@ void ServerGroupChatRoomPrivate::updateParticipantDevices(const IdentityAddress
 		lError() << q << " participant devices updated for unknown participant, ignored.";
 		return;
 	}
-	lInfo() << q << ": Setting " << devices.size() << " participant device(s) for " << participantAddress.asString();
+	lInfo() << q << ": Setting " << devices.size() << " participant device(s) for " << participantAddress->toString();
 
 	// Remove devices that are in the chatroom but no longer in the given list
 	list<shared_ptr<ParticipantDevice>> devicesToRemove;
 	for (const auto &device : participant->getDevices()) {
 		auto predicate = [device](const shared_ptr<ParticipantDeviceIdentity> &deviceIdentity) {
-			return device->getAddress() == deviceIdentity->getAddress();
+			return *device->getAddress() == *deviceIdentity->getAddress();
 		};
 		auto it = find_if(devices.cbegin(), devices.cend(), predicate);
 		if (it == devices.cend()) {
-			lInfo() << q << " Device " << device << " is no longer registered, it will be removed from the chatroom.";
+			lInfo() << q << " Device " << *device->getAddress()
+			        << " is no longer registered, it will be removed from the chatroom.";
 			devicesToRemove.push_back(device);
 		}
 	}
@@ -726,15 +724,14 @@ void ServerGroupChatRoomPrivate::conclude() {
 }
 
 void ServerGroupChatRoomPrivate::setParticipantDevicesAtCreation(
-    const IdentityAddress &participantAddress, const list<shared_ptr<ParticipantDeviceIdentity>> &devices) {
-
+    const std::shared_ptr<Address> &participantAddress, const list<shared_ptr<ParticipantDeviceIdentity>> &devices) {
 	updateParticipantDevices(participantAddress, devices);
 	if (unnotifiedRegistrationSubscriptions == 0) {
 		conclude();
 	}
 }
 
-void ServerGroupChatRoomPrivate::setParticipantDevices(const IdentityAddress &participantAddress,
+void ServerGroupChatRoomPrivate::setParticipantDevices(const std::shared_ptr<Address> &participantAddress,
                                                        const list<shared_ptr<ParticipantDeviceIdentity>> &devices) {
 
 	if (joiningPendingAfterCreation) {
@@ -803,13 +800,13 @@ void ServerGroupChatRoomPrivate::updateProtocolVersionFromDevice(const shared_pt
 	auto protocols = Utils::parseCapabilityDescriptor(device->getCapabilityDescriptor());
 	auto groupchat = protocols.find("groupchat");
 	if (groupchat == protocols.end()) {
-		lError() << "Device " << device->getAddress().asString()
+		lError() << "Device " << device->getAddress()->toString()
 		         << " has no groupchat capability set: " << device->getCapabilityDescriptor();
 		return;
 	}
 	if (protocolVersion > groupchat->second) {
 		protocolVersion = groupchat->second;
-		lWarning() << "Device " << device->getAddress().asString() << " downgrades chatroom's protocol version to "
+		lWarning() << "Device " << device->getAddress()->toString() << " downgrades chatroom's protocol version to "
 		           << protocolVersion;
 	}
 }
@@ -868,7 +865,8 @@ void ServerGroupChatRoomPrivate::designateAdmin() {
 	}
 }
 
-void ServerGroupChatRoomPrivate::sendMessage(const shared_ptr<Message> &message, const IdentityAddress &deviceAddr) {
+void ServerGroupChatRoomPrivate::sendMessage(const shared_ptr<Message> &message,
+                                             const std::shared_ptr<Address> &deviceAddr) {
 	L_Q();
 
 	shared_ptr<ChatMessage> msg = q->createChatMessage();
@@ -879,8 +877,8 @@ void ServerGroupChatRoomPrivate::sendMessage(const shared_ptr<Message> &message,
 	msg->getPrivate()->forceFromAddress(q->getConferenceAddress());
 	msg->getPrivate()->forceToAddress(deviceAddr);
 	msg->getPrivate()->setApplyModifiers(false);
-	if (message->fromAddr.getUsername() == msg->getToAddress().getUsername() &&
-	    message->fromAddr.getDomain() == msg->getToAddress().getDomain()) {
+	if (message->fromAddr->getUsername() == msg->getToAddress()->getUsername() &&
+	    message->fromAddr->getDomain() == msg->getToAddress()->getDomain()) {
 		// If FROM and TO are the same user (with a different device for example, gruu is not checked), set the
 		// X-fs-message-type header to "chat-service". This lead to disabling push notification for this message.
 		msg->getPrivate()->addSalCustomHeader(XFsMessageTypeHeader::HeaderName, XFsMessageTypeHeader::ChatService);
@@ -890,7 +888,7 @@ void ServerGroupChatRoomPrivate::sendMessage(const shared_ptr<Message> &message,
 
 void ServerGroupChatRoomPrivate::finalizeCreation() {
 	L_Q();
-	ConferenceAddress confAddr(q->getConference()->getConferenceAddress());
+	std::shared_ptr<Address> confAddr = q->getConferenceAddress()->clone()->toSharedPtr();
 	const ConferenceId conferenceId = ConferenceId(confAddr, confAddr);
 	q->getConference()->setConferenceId(conferenceId);
 	q->getCore()->getPrivate()->localListEventHandler->addHandler(
@@ -899,7 +897,7 @@ void ServerGroupChatRoomPrivate::finalizeCreation() {
 	// Let the SIP stack set the domain and the port
 	shared_ptr<Participant> me = q->getMe();
 	me->setAddress(confAddr);
-	Address addr(confAddr.asAddress());
+	auto addr = *confAddr;
 	addr.setParam("isfocus");
 	shared_ptr<CallSession> session = me->getSession();
 	if (session->getState() == CallSession::State::Idle) {
@@ -940,21 +938,18 @@ shared_ptr<CallSession> ServerGroupChatRoomPrivate::makeSession(const std::share
 			csp.addCustomHeader("Ephemerable", "true");
 			csp.addCustomHeader("Ephemeral-Life-Time", to_string(params->getEphemeralLifetime()));
 		}
-		// csp.addCustomContactParameter("isfocus");
-		// csp.addCustomContactParameter("text");
 		shared_ptr<Participant> participant =
 		    const_pointer_cast<Participant>(device->getParticipant()->getSharedFromThis());
 		session = participant->createSession(*q->getConference().get(), &csp, false, this);
-		session->configure(LinphoneCallOutgoing, nullptr, nullptr,
-		                   q->getConference()->getConferenceAddress().asAddress(), device->getAddress().asAddress());
+		session->configure(LinphoneCallOutgoing, nullptr, nullptr, q->getConferenceAddress(), device->getAddress());
 		device->setSession(session);
 		session->initiateOutgoing();
 		session->getPrivate()->createOp();
 		// FIXME jehan check conference server  potential impact
-		Address contactAddr(q->getConference()->getConferenceAddress().asAddress());
+		Address contactAddr(*q->getConferenceAddress());
 		contactAddr.setParam("isfocus");
 		contactAddr.setParam("text");
-		session->getPrivate()->getOp()->setContactAddress(contactAddr.getInternalAddress());
+		session->getPrivate()->getOp()->setContactAddress(contactAddr.getImpl());
 	}
 	return session;
 }
@@ -962,7 +957,7 @@ shared_ptr<CallSession> ServerGroupChatRoomPrivate::makeSession(const std::share
 void ServerGroupChatRoomPrivate::inviteDevice(const shared_ptr<ParticipantDevice> &device) {
 	L_Q();
 
-	lInfo() << q << ": Inviting device '" << device->getAddress().asString() << "'";
+	lInfo() << q << ": Inviting device '" << device->getAddress()->toString() << "'";
 	shared_ptr<Participant> participant =
 	    const_pointer_cast<Participant>(device->getParticipant()->getSharedFromThis());
 	shared_ptr<CallSession> session = makeSession(device);
@@ -978,7 +973,7 @@ void ServerGroupChatRoomPrivate::inviteDevice(const shared_ptr<ParticipantDevice
 		return;
 	}
 
-	list<IdentityAddress> addressesList;
+	list<std::shared_ptr<Address>> addressesList;
 	for (const auto &invitedParticipant : q->getParticipants()) {
 		if (invitedParticipant != participant) addressesList.push_back(invitedParticipant->getAddress());
 	}
@@ -1000,7 +995,7 @@ void ServerGroupChatRoomPrivate::inviteDevice(const shared_ptr<ParticipantDevice
 void ServerGroupChatRoomPrivate::byeDevice(const std::shared_ptr<ParticipantDevice> &device) {
 	L_Q();
 
-	lInfo() << q << ": Asking device '" << device->getAddress().asString() << "' to leave";
+	lInfo() << q << ": Asking device '" << device->getAddress()->toString() << "' to leave";
 	setParticipantDeviceState(device, ParticipantDevice::State::Leaving);
 	shared_ptr<CallSession> session = makeSession(device);
 	switch (session->getState()) {
@@ -1018,7 +1013,8 @@ void ServerGroupChatRoomPrivate::byeDevice(const std::shared_ptr<ParticipantDevi
 
 /*
  * This method is to be called by the conference server when it is notified that a device has just registered*/
-void ServerGroupChatRoomPrivate::notifyParticipantDeviceRegistration(const IdentityAddress &participantDevice) {
+void ServerGroupChatRoomPrivate::notifyParticipantDeviceRegistration(
+    const std::shared_ptr<Address> &participantDevice) {
 	L_Q();
 
 	shared_ptr<Participant> participant = q->findCachedParticipant(participantDevice);
@@ -1055,9 +1051,10 @@ void ServerGroupChatRoomPrivate::queueMessage(const shared_ptr<Message> &msg) {
 	}
 }
 
-void ServerGroupChatRoomPrivate::queueMessage(const shared_ptr<Message> &msg, const IdentityAddress &deviceAddress) {
+void ServerGroupChatRoomPrivate::queueMessage(const shared_ptr<Message> &msg,
+                                              const std::shared_ptr<Address> &deviceAddress) {
 	chrono::system_clock::time_point timestamp = chrono::system_clock::now();
-	string uri(deviceAddress.asString());
+	string uri(deviceAddress->toString());
 	// Remove queued messages older than one week
 	while (!queuedMessages[uri].empty()) {
 		shared_ptr<Message> m = queuedMessages[uri].front();
@@ -1073,7 +1070,7 @@ void ServerGroupChatRoomPrivate::queueMessage(const shared_ptr<Message> &msg, co
  * device unregisters explicitely or removed by an administrator.
  */
 void ServerGroupChatRoomPrivate::removeParticipantDevice(const shared_ptr<Participant> &participant,
-                                                         const IdentityAddress &deviceAddress) {
+                                                         const std::shared_ptr<Address> &deviceAddress) {
 	L_Q();
 	shared_ptr<Participant> participantCopy = participant; // make a copy of the shared_ptr because the participant may
 	                                                       // be removed by setParticipantDeviceState().
@@ -1112,7 +1109,7 @@ void ServerGroupChatRoomPrivate::onParticipantDeviceLeft(const std::shared_ptr<P
 	L_Q();
 
 	unique_ptr<MainDb> &mainDb = q->getCore()->getPrivate()->mainDb;
-	lInfo() << q << ": Participant device '" << device->getAddress().asString() << "' left";
+	lInfo() << q << ": Participant device '" << device->getAddress()->toString() << "' left";
 
 	auto session = device->getSession();
 	if (session) session->setListener(nullptr);
@@ -1121,7 +1118,7 @@ void ServerGroupChatRoomPrivate::onParticipantDeviceLeft(const std::shared_ptr<P
 		shared_ptr<Participant> participant =
 		    const_pointer_cast<Participant>(device->getParticipant()->getSharedFromThis());
 		if (allDevicesLeft(participant) && q->findParticipant(participant->getAddress()) == nullptr) {
-			lInfo() << q << ": Participant '" << participant->getAddress().asString()
+			lInfo() << q << ": Participant '" << participant->getAddress()->toString()
 			        << "'removed and last device left, unsubscribing";
 			unSubscribeRegistrationForParticipant(participant->getAddress());
 			mainDb->deleteChatRoomParticipant(q->getSharedFromThis(), participant->getAddress());
@@ -1302,7 +1299,7 @@ void ServerGroupChatRoomPrivate::onCallSessionStateChanged(const shared_ptr<Call
 				}
 			} else {
 				if (device->getState() == ParticipantDevice::State::Present) {
-					lInfo() << q << ": " << device->getParticipant()->getAddress().asString()
+					lInfo() << q << ": " << device->getParticipant()->getAddress()->toString()
 					        << " is leaving the chatroom.";
 					onBye(device);
 				}
@@ -1367,7 +1364,7 @@ ServerGroupChatRoom::ServerGroupChatRoom(const shared_ptr<Core> &core, SalCallOp
                core,
                ChatRoomParams::getDefaults(core),
                make_shared<LocalConference>(
-                   core, IdentityAddress(op->getTo()), nullptr, ConferenceParams::create(core->getCCore()), this)) {
+                   core, Address::create(op->getTo()), nullptr, ConferenceParams::create(core->getCCore()), this)) {
 	L_D();
 
 	getConference()->setUtf8Subject(op->getSubject());
@@ -1395,7 +1392,9 @@ ServerGroupChatRoom::ServerGroupChatRoom(const shared_ptr<Core> &core, SalCallOp
 	}
 
 	shared_ptr<CallSession> session = getMe()->createSession(*getConference().get(), nullptr, false, d);
-	session->configure(LinphoneCallIncoming, nullptr, op, Address(op->getFrom()), Address(op->getTo()));
+	const auto from = Address::create(op->getFrom());
+	const auto to = Address::create(op->getTo());
+	session->configure(LinphoneCallIncoming, nullptr, op, from, to);
 	d->protocolVersion = CorePrivate::groupChatProtocolVersion;
 
 	/*
@@ -1407,7 +1406,7 @@ ServerGroupChatRoom::ServerGroupChatRoom(const shared_ptr<Core> &core, SalCallOp
 }
 
 ServerGroupChatRoom::ServerGroupChatRoom(const shared_ptr<Core> &core,
-                                         const ConferenceAddress &peerAddress,
+                                         const std::shared_ptr<Address> &peerAddress,
                                          AbstractChatRoom::CapabilitiesMask capabilities,
                                          const shared_ptr<ChatRoomParams> &params,
                                          const string &subject,
@@ -1457,18 +1456,16 @@ shared_ptr<Participant> ServerGroupChatRoom::findParticipant(const shared_ptr<co
 		shared_ptr<ParticipantDevice> device = participant->findDevice(session);
 		if (device || (participant->getSession() == session)) return participant;
 	}
-	lInfo() << "Unable to find participant in server group chat room " << this << " with call session " << session;
+	lInfo() << "Unable to find participant with call session " << session << " in server group chat room " << this;
 	return nullptr;
 }
 
-shared_ptr<Participant> ServerGroupChatRoom::findParticipant(const IdentityAddress &participantAddress) const {
-	IdentityAddress searchedAddr(participantAddress);
-	searchedAddr.setGruu("");
+shared_ptr<Participant> ServerGroupChatRoom::findParticipant(const std::shared_ptr<Address> &participantAddress) const {
 	for (const auto &participant : getParticipants()) {
-		if (participant->getAddress() == searchedAddr) return participant;
+		if (participant->getAddress()->weakEqual(*participantAddress)) return participant;
 	}
-	lInfo() << "Unable to find participant in server group chat room " << this << " with address "
-	        << participantAddress.asString();
+	lInfo() << "Unable to find participant with address " << participantAddress->toString()
+	        << " in server group chat room " << this;
 	return nullptr;
 }
 
@@ -1480,11 +1477,10 @@ shared_ptr<Participant> ServerGroupChatRoom::findCachedParticipant(const shared_
 	return nullptr;
 }
 
-shared_ptr<Participant> ServerGroupChatRoom::findCachedParticipant(const IdentityAddress &participantAddress) const {
-	IdentityAddress searchedAddr(participantAddress);
-	searchedAddr.setGruu("");
+shared_ptr<Participant>
+ServerGroupChatRoom::findCachedParticipant(const std::shared_ptr<Address> &participantAddress) const {
 	for (const auto &participant : cachedParticipants) {
-		if (participant->getAddress() == searchedAddr) return participant;
+		if (participant->getAddress()->weakEqual(*participantAddress)) return participant;
 	}
 	return nullptr;
 }
@@ -1523,17 +1519,17 @@ bool ServerGroupChatRoom::isReadOnly() const {
 	return false;
 }
 
-bool ServerGroupChatRoom::addParticipant(const IdentityAddress &participantAddress) {
+bool ServerGroupChatRoom::addParticipant(const std::shared_ptr<Address> &participantAddress) {
 	L_D();
 
-	if (participantAddress.hasGruu()) {
-		lInfo() << this << ": Not adding participant '" << participantAddress.asString()
+	if (participantAddress->hasUriParam("gr")) {
+		lInfo() << this << ": Not adding participant '" << participantAddress->toString()
 		        << "' because it is a gruu address.";
 		return false;
 	}
 
 	if (findParticipant(participantAddress)) {
-		lInfo() << this << ": Not adding participant '" << participantAddress.asString()
+		lInfo() << this << ": Not adding participant '" << participantAddress->toString()
 		        << "' because it is already a participant";
 		return false;
 	}
@@ -1542,7 +1538,7 @@ bool ServerGroupChatRoom::addParticipant(const IdentityAddress &participantAddre
 
 	if (participant == nullptr && (d->capabilities & ServerGroupChatRoom::Capabilities::OneToOne) &&
 	    getParticipantCount() == 2) {
-		lInfo() << this << ": Not adding participant '" << participantAddress.asString()
+		lInfo() << this << ": Not adding participant '" << participantAddress->toString()
 		        << "' because this OneToOne chat room already has 2 participants";
 		return false;
 	}
@@ -1555,16 +1551,16 @@ bool ServerGroupChatRoom::addParticipant(const IdentityAddress &participantAddre
 	if (participant) {
 		d->resumeParticipant(participant);
 	} else {
-		lInfo() << this << ": Requested to add participant '" << participantAddress.asString()
+		lInfo() << this << ": Requested to add participant '" << participantAddress->toString()
 		        << "', checking capabilities first.";
-		list<IdentityAddress> participantsList;
+		list<std::shared_ptr<Address>> participantsList;
 		participantsList.push_back(participantAddress);
 		d->subscribeRegistrationForParticipants(participantsList, true);
 	}
 	return true;
 }
 
-const ConferenceAddress &ServerGroupChatRoom::getConferenceAddress() const {
+const std::shared_ptr<Address> &ServerGroupChatRoom::getConferenceAddress() const {
 	return getConference()->getConferenceAddress();
 }
 
@@ -1594,11 +1590,11 @@ void ServerGroupChatRoom::join() {
 void ServerGroupChatRoom::leave() {
 }
 
-void ServerGroupChatRoom::onFirstNotifyReceived(const IdentityAddress &addr) {
+void ServerGroupChatRoom::onFirstNotifyReceived(const std::shared_ptr<Address> &addr) {
 	L_D();
 	for (const auto &participant : getParticipants()) {
 		for (const auto &device : participant->getDevices()) {
-			if ((device->getAddress() == addr) && (d->dispatchMessagesAfterFullState(device))) {
+			if ((*device->getAddress() == *addr) && (d->dispatchMessagesAfterFullState(device))) {
 				d->moveDeviceToPresent(device);
 				return;
 			}
@@ -1640,7 +1636,7 @@ void ServerGroupChatRoom::setState(ConferenceInterface::State state) {
 	if (state == ConferenceInterface::State::Created) {
 		// Handle transitional states (joining and leaving of participants)
 		// This is needed when the chat room is loaded from its state in database
-		list<IdentityAddress> participantAddresses;
+		list<std::shared_ptr<Address>> participantAddresses;
 		for (const auto &participant : cachedParticipants) {
 			participantAddresses.emplace_back(participant->getAddress());
 
@@ -1696,22 +1692,15 @@ void ServerGroupChatRoom::setState(ConferenceInterface::State state) {
 void ServerGroupChatRoom::subscribeReceived(const shared_ptr<EventSubscribe> &event) {
 	L_D();
 
-	const LinphoneAddress *lAddr = event->getFrom();
-	char *addrStr = linphone_address_as_string(lAddr);
-	Address participantAddress(addrStr);
-	bctbx_free(addrStr);
-
+	const auto &participantAddress = event->getFrom();
 	shared_ptr<Participant> participant = findCachedParticipant(participantAddress);
-
 	if (participant) {
-		const LinphoneAddress *lContactAddr = event->getRemoteContact();
-		char *contactAddrStr = linphone_address_as_string(lContactAddr);
-		IdentityAddress contactAddr(contactAddrStr);
-		bctbx_free(contactAddrStr);
+		std::shared_ptr<Address> contactAddr = event->getRemoteContact();
 		shared_ptr<ParticipantDevice> device = participant->findDevice(contactAddr);
 		const auto deviceState = device ? device->getState() : ParticipantDevice::State::ScheduledForJoining;
 		if (device && (deviceState == ParticipantDevice::State::ScheduledForJoining)) {
-			lInfo() << "Inviting device " << device->getAddress() << " because it was scheduled to join the chat room";
+			lInfo() << "Inviting device " << device->getAddress()->toString()
+			        << " because it was scheduled to join the chat room";
 			// Invite device as last time round it was attempted, the INVITE session errored out
 			d->inviteDevice(device);
 		}
@@ -1726,7 +1715,9 @@ void ServerGroupChatRoom::subscribeReceived(const shared_ptr<EventSubscribe> &ev
 
 ostream &operator<<(ostream &stream, const ServerGroupChatRoom *chatRoom) {
 	// TODO: Is conference ID needed to be stored in both remote conference and chat room base classes?
-	return stream << "ServerGroupChatRoom [" << chatRoom->getConferenceId().getPeerAddress().asString() << "]";
+	const auto &peerAddress = chatRoom->getConferenceId().getPeerAddress();
+	return stream << "ServerGroupChatRoom [" << (peerAddress ? peerAddress->toString() : std::string("unknown address"))
+	              << "]";
 }
 
 LINPHONE_END_NAMESPACE
diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h
index d4620f4a9132c2be5bce406965c6c4f829752092..cc3be606cfccaf94f87d623444526cc51f8beb0d 100644
--- a/src/chat/chat-room/server-group-chat-room.h
+++ b/src/chat/chat-room/server-group-chat-room.h
@@ -36,7 +36,7 @@ public:
 	ServerGroupChatRoom(const std::shared_ptr<Core> &core, SalCallOp *op);
 
 	ServerGroupChatRoom(const std::shared_ptr<Core> &core,
-	                    const ConferenceAddress &peerAddress,
+	                    const std::shared_ptr<Address> &peerAddress,
 	                    AbstractChatRoom::CapabilitiesMask capabilities,
 	                    const std::shared_ptr<ChatRoomParams> &params,
 	                    const std::string &subject,
@@ -56,14 +56,14 @@ public:
 	bool hasBeenLeft() const override;
 	bool isReadOnly() const override;
 
-	const ConferenceAddress &getConferenceAddress() const override;
+	const std::shared_ptr<Address> &getConferenceAddress() const override;
 
-	bool addParticipant(const IdentityAddress &participantAddress) override;
+	bool addParticipant(const std::shared_ptr<Address> &participantAddress) override;
 	bool addParticipant(std::shared_ptr<Call> call) override {
 		return getConference()->addParticipant(call);
 	};
 
-	void join(const IdentityAddress &participantAddress) override {
+	void join(const std::shared_ptr<Address> &participantAddress) override {
 		getConference()->join(participantAddress);
 	};
 	bool update(const ConferenceParamsInterface &newParameters) override {
@@ -73,9 +73,9 @@ public:
 	bool removeParticipant(const std::shared_ptr<Participant> &participant) override;
 
 	std::shared_ptr<Participant> findParticipant(const std::shared_ptr<const CallSession> &session) const;
-	std::shared_ptr<Participant> findParticipant(const IdentityAddress &participantAddress) const override;
+	std::shared_ptr<Participant> findParticipant(const std::shared_ptr<Address> &participantAddress) const override;
 	std::shared_ptr<Participant> findCachedParticipant(const std::shared_ptr<const CallSession> &session) const;
-	std::shared_ptr<Participant> findCachedParticipant(const IdentityAddress &participantAddress) const;
+	std::shared_ptr<Participant> findCachedParticipant(const std::shared_ptr<Address> &participantAddress) const;
 	std::shared_ptr<ParticipantDevice>
 	findCachedParticipantDevice(const std::shared_ptr<const CallSession> &session) const;
 
@@ -91,7 +91,7 @@ public:
 
 	void join() override;
 	void leave() override;
-	void onFirstNotifyReceived(const IdentityAddress &addr) override;
+	void onFirstNotifyReceived(const std::shared_ptr<Address> &addr) override;
 
 	const ConferenceId &getConferenceId() const override {
 		return getConference()->getConferenceId();
diff --git a/src/chat/encryption/encryption-engine.h b/src/chat/encryption/encryption-engine.h
index 087ef169d83121fa7286f769a506161d8cd5b425..f429f07ded16f935cba365fd01c19da88c88256a 100644
--- a/src/chat/encryption/encryption-engine.h
+++ b/src/chat/encryption/encryption-engine.h
@@ -107,12 +107,12 @@ public:
 	}
 
 	virtual void
-	addSecurityEventInChatrooms(BCTBX_UNUSED(const IdentityAddress &peerDeviceAddr),
+	addSecurityEventInChatrooms(BCTBX_UNUSED(const std::shared_ptr<Address> &peerDeviceAddr),
 	                            BCTBX_UNUSED(ConferenceSecurityEvent::SecurityEventType securityEventType)) {
 	}
 
 	virtual std::shared_ptr<ConferenceSecurityEvent>
-	onDeviceAdded(BCTBX_UNUSED(const IdentityAddress &newDeviceAddr),
+	onDeviceAdded(BCTBX_UNUSED(const std::shared_ptr<Address> &newDeviceAddr),
 	              BCTBX_UNUSED(std::shared_ptr<Participant> participant),
 	              BCTBX_UNUSED(const std::shared_ptr<AbstractChatRoom> &chatRoom),
 	              BCTBX_UNUSED(ChatRoom::SecurityLevel currentSecurityLevel)) {
diff --git a/src/chat/encryption/lime-x3dh-encryption-engine.cpp b/src/chat/encryption/lime-x3dh-encryption-engine.cpp
index 346465407824e8d932f500b61c131905ca2d9c97..bdfcf9c95fc32a3c514659bae81710cefc199781 100644
--- a/src/chat/encryption/lime-x3dh-encryption-engine.cpp
+++ b/src/chat/encryption/lime-x3dh-encryption-engine.cpp
@@ -18,12 +18,11 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "lime-x3dh-encryption-engine.h"
 #include "bctoolbox/crypto.h"
+#include "bctoolbox/exception.hh"
 #include <bctoolbox/defs.h>
 
 #include "account/account.h"
-#include "bctoolbox/exception.hh"
 #include "c-wrapper/c-wrapper.h"
 #include "chat/chat-message/chat-message-p.h"
 #include "chat/chat-room/chat-room-p.h"
@@ -36,6 +35,7 @@
 #include "core/core.h"
 #include "event-log/conference/conference-security-event.h"
 #include "factory/factory.h"
+#include "lime-x3dh-encryption-engine.h"
 #include "private.h"
 #include "sqlite3_bctbx_vfs.h"
 
@@ -92,15 +92,15 @@ void LimeManager::processAuthRequested(void *data, belle_sip_auth_event_t *event
 	shared_ptr<Core> core = userData->core;
 
 	/* extract username and domain from the GRUU stored in userData->username */
-	auto address = IdentityAddress(userData->username);
+	auto address = Address::create(userData->username);
 
 	/* Notes: when registering on the Lime server, the user is already registered on the flexisip server
 	 * the requested auth info shall thus be present in linphone core (except if registering methods are differents on
 	 * flexisip and lime server - very unlikely) This request will thus not use the auth requested callback to get the
 	 * information
 	 * - Stored auth information in linphone core are indexed by username/domain */
-	linphone_core_fill_belle_sip_auth_event(core->getCCore(), event, address.getUsername().data(),
-	                                        address.getDomain().data());
+	linphone_core_fill_belle_sip_auth_event(core->getCCore(), event, address->getUsername().data(),
+	                                        address->getDomain().data());
 }
 
 LimeManager::LimeManager(const string &dbAccess, belle_http_provider_t *prov, shared_ptr<Core> core)
@@ -174,10 +174,9 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processOutgoingMessage(con
 	shared_ptr<ChatMessageModifier::Result> result =
 	    make_shared<ChatMessageModifier::Result>(ChatMessageModifier::Result::Suspended);
 	shared_ptr<AbstractChatRoom> chatRoom = message->getChatRoom();
-	const string &localDeviceId = chatRoom->getLocalAddress().asString();
-	const IdentityAddress &peerAddress = chatRoom->getPeerAddress();
-	shared_ptr<const string> recipientUserId =
-	    make_shared<const string>(peerAddress.getAddressWithoutGruu().asString());
+	const string &localDeviceId = chatRoom->getLocalAddress()->asStringUriOnly();
+	auto peerAddress = chatRoom->getPeerAddress()->getUriWithoutGruu();
+	shared_ptr<const string> recipientUserId = make_shared<const string>(peerAddress.asStringUriOnly());
 
 	// Check if chatroom is encrypted or not
 	if (chatRoom->getCapabilities() & ChatRoom::Capabilities::Encrypted) {
@@ -207,7 +206,7 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processOutgoingMessage(con
 		int nbDevice = 0;
 		const list<shared_ptr<ParticipantDevice>> devices = participant->getDevices();
 		for (const shared_ptr<ParticipantDevice> &device : devices) {
-			recipients->emplace_back(device->getAddress().asString());
+			recipients->emplace_back(device->getAddress()->asStringUriOnly());
 			nbDevice++;
 		}
 		if (nbDevice > maxNbDevicePerParticipant) tooManyDevices = TRUE;
@@ -217,8 +216,8 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processOutgoingMessage(con
 	int nbDevice = 0;
 	const list<shared_ptr<ParticipantDevice>> senderDevices = chatRoom->getMe()->getDevices();
 	for (const auto &senderDevice : senderDevices) {
-		if (senderDevice->getAddress() != chatRoom->getLocalAddress()) {
-			recipients->emplace_back(senderDevice->getAddress().asString());
+		if (*senderDevice->getAddress() != *chatRoom->getLocalAddress()) {
+			recipients->emplace_back(senderDevice->getAddress()->asStringUriOnly());
 			nbDevice++;
 		}
 	}
@@ -371,8 +370,9 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processOutgoingMessage(con
 ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(const shared_ptr<ChatMessage> &message,
                                                                              int &errorCode) {
 	const shared_ptr<AbstractChatRoom> chatRoom = message->getChatRoom();
-	const string &localDeviceId = chatRoom->getLocalAddress().asString();
-	const string &recipientUserId = chatRoom->getPeerAddress().getAddressWithoutGruu().asString();
+	const string &localDeviceId = chatRoom->getLocalAddress()->asStringUriOnly();
+	auto peerAddress = chatRoom->getPeerAddress()->getUriWithoutGruu();
+	const string &recipientUserId = peerAddress.asStringUriOnly();
 
 	// Check if chatroom is encrypted or not
 	if (chatRoom->getCapabilities() & ChatRoom::Capabilities::Encrypted) {
@@ -407,8 +407,8 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con
 		CpimChatMessageModifier ccmm;
 		senderDeviceId = ccmm.parseMinimalCpimContentInLimeMessage(message, content);
 		if (senderDeviceId != "") {
-			IdentityAddress tmpIdentityAddress(senderDeviceId);
-			senderDeviceId = tmpIdentityAddress.asString();
+			const Address tmpIdentityAddress(senderDeviceId);
+			senderDeviceId = tmpIdentityAddress.asStringUriOnly();
 			cpimFound = true;
 		}
 	}
@@ -501,7 +501,7 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processIncomingMessage(con
 	message->setInternalContent(finalContent);
 
 	// Set the contact in sipfrag as the authenticatedFromAddress for sender authentication
-	IdentityAddress sipfragAddress(senderDeviceId);
+	const Address sipfragAddress(senderDeviceId);
 	message->getPrivate()->setAuthenticatedFromAddress(sipfragAddress);
 
 	return ChatMessageModifier::Result::Done;
@@ -658,10 +658,9 @@ list<EncryptionParameter> LimeX3dhEncryptionEngine::getEncryptionParameters() {
 		    << "[LIME] No contactAddress available, unable to setup identity key for ZRTP auxiliary shared secret";
 		return {};
 	}
-	char *identity = linphone_address_as_string(contactAddress);
-	IdentityAddress identityAddress = IdentityAddress(identity);
-	ms_free(identity);
-	string localDeviceId = identityAddress.asString();
+	std::shared_ptr<Address> identityAddress =
+	    Address::toCpp(const_cast<LinphoneAddress *>(contactAddress))->getSharedFromThis();
+	string localDeviceId = identityAddress->asStringUriOnly();
 	vector<uint8_t> Ik;
 
 	try {
@@ -779,7 +778,7 @@ void LimeX3dhEncryptionEngine::authenticationVerified(
 	}
 
 	vector<uint8_t> remoteIk = decodeBase64(remoteIkB64);
-	const IdentityAddress peerDeviceAddr = IdentityAddress(peerDeviceId);
+	const std::shared_ptr<Address> peerDeviceAddr = Address::create(peerDeviceId);
 
 	if (ms_zrtp_getAuxiliarySharedSecretMismatch(zrtpContext) == 2 /*BZRTP_AUXSECRET_UNSET*/) {
 		lInfo() << "[LIME] No auxiliary shared secret exchanged check from SDP if Ik were exchanged";
@@ -836,7 +835,7 @@ void LimeX3dhEncryptionEngine::authenticationVerified(
 void LimeX3dhEncryptionEngine::authenticationRejected(const char *peerDeviceId) {
 	// Get peer's Ik
 	// Warn the user that rejecting the SAS reveals a man-in-the-middle
-	const IdentityAddress peerDeviceAddr = IdentityAddress(peerDeviceId);
+	const std::shared_ptr<Address> peerDeviceAddr = Address::create(peerDeviceId);
 
 	if (limeManager->get_peerDeviceStatus(peerDeviceId) == lime::PeerDeviceStatus::trusted) {
 		addSecurityEventInChatrooms(peerDeviceAddr,
@@ -856,7 +855,7 @@ void LimeX3dhEncryptionEngine::authenticationRejected(const char *peerDeviceId)
 }
 
 void LimeX3dhEncryptionEngine::addSecurityEventInChatrooms(
-    const IdentityAddress &peerDeviceAddr, ConferenceSecurityEvent::SecurityEventType securityEventType) {
+    const std::shared_ptr<Address> &peerDeviceAddr, ConferenceSecurityEvent::SecurityEventType securityEventType) {
 	const list<shared_ptr<AbstractChatRoom>> chatRooms = getCore()->getChatRooms();
 	for (const auto &chatRoom : chatRooms) {
 		if (chatRoom->findParticipant(peerDeviceAddr) &&
@@ -870,11 +869,12 @@ void LimeX3dhEncryptionEngine::addSecurityEventInChatrooms(
 }
 
 shared_ptr<ConferenceSecurityEvent>
-LimeX3dhEncryptionEngine::onDeviceAdded(const IdentityAddress &newDeviceAddr,
+LimeX3dhEncryptionEngine::onDeviceAdded(const std::shared_ptr<Address> &newDeviceAddr,
                                         shared_ptr<Participant> participant,
                                         const shared_ptr<AbstractChatRoom> &chatRoom,
                                         ChatRoom::SecurityLevel currentSecurityLevel) {
-	lime::PeerDeviceStatus newDeviceStatus = limeManager->get_peerDeviceStatus(newDeviceAddr.asString());
+	const auto deviceId = newDeviceAddr->asStringUriOnly();
+	lime::PeerDeviceStatus newDeviceStatus = limeManager->get_peerDeviceStatus(deviceId);
 	int maxNbDevicesPerParticipant = linphone_config_get_int(linphone_core_get_config(L_GET_C_BACK_PTR(getCore())),
 	                                                         "lime", "max_nb_device_per_participant", INT_MAX);
 	int nbDevice = int(participant->getDevices().size());
@@ -886,14 +886,14 @@ LimeX3dhEncryptionEngine::onDeviceAdded(const IdentityAddress &newDeviceAddr,
 		securityEvent = make_shared<ConferenceSecurityEvent>(
 		    time(nullptr), chatRoom->getConferenceId(),
 		    ConferenceSecurityEvent::SecurityEventType::ParticipantMaxDeviceCountExceeded, newDeviceAddr);
-		limeManager->set_peerDeviceStatus(newDeviceAddr.asString(), lime::PeerDeviceStatus::unsafe);
+		limeManager->set_peerDeviceStatus(deviceId, lime::PeerDeviceStatus::unsafe);
 	}
 
 	// Otherwise if the chatroom security level was degraded a corresponding security event is created
 	else {
 		if ((currentSecurityLevel == ChatRoom::SecurityLevel::Safe) &&
 		    (newDeviceStatus != lime::PeerDeviceStatus::trusted)) {
-			lInfo() << "[LIME] chat room security level degraded by " << newDeviceAddr.asString();
+			lInfo() << "[LIME] chat room security level degraded by " << deviceId;
 			securityEvent = make_shared<ConferenceSecurityEvent>(
 			    time(nullptr), chatRoom->getConferenceId(),
 			    ConferenceSecurityEvent::SecurityEventType::SecurityLevelDowngraded, newDeviceAddr);
@@ -969,10 +969,9 @@ void LimeX3dhEncryptionEngine::onRegistrationStateChanged(LinphoneProxyConfig *c
 		return;
 	}
 
-	char *contactAddress = linphone_address_as_string_uri_only(linphone_proxy_config_get_contact(cfg));
-	IdentityAddress identityAddress = IdentityAddress(contactAddress);
-	string localDeviceId = identityAddress.asString();
-	if (contactAddress) ms_free(contactAddress);
+	std::shared_ptr<Address> identityAddress =
+	    Address::toCpp(const_cast<LinphoneAddress *>(linphone_proxy_config_get_contact(cfg)))->getSharedFromThis();
+	string localDeviceId = identityAddress->asStringUriOnly();
 
 	LinphoneCore *lc = linphone_proxy_config_get_core(cfg);
 	LinphoneConfig *lpconfig = linphone_core_get_config(lc);
@@ -1021,10 +1020,7 @@ void LimeX3dhEncryptionEngine::onServerUrlChanged(const std::shared_ptr<Account>
 	if (!contactAddress) {
 		return;
 	}
-	char *contactAddressStr = linphone_address_as_string_uri_only(contactAddress);
-	IdentityAddress identityAddress = IdentityAddress(contactAddressStr);
-	string localDeviceId = identityAddress.asString();
-	if (contactAddressStr) ms_free(contactAddressStr);
+	string localDeviceId = contactAddress->asStringUriOnly();
 
 	LinphoneCore *lc = account->getCore();
 	LinphoneConfig *lpconfig = linphone_core_get_config(lc);
diff --git a/src/chat/encryption/lime-x3dh-encryption-engine.h b/src/chat/encryption/lime-x3dh-encryption-engine.h
index 4cf5d42eed0041692ed22fa692ff1dfe353a205f..6570828e35f058a04fb8057cba14a9b9ddd5ad06 100644
--- a/src/chat/encryption/lime-x3dh-encryption-engine.h
+++ b/src/chat/encryption/lime-x3dh-encryption-engine.h
@@ -121,10 +121,10 @@ public:
 
 	void authenticationRejected(const char *peerDeviceId) override;
 
-	void addSecurityEventInChatrooms(const IdentityAddress &peerDeviceAddr,
+	void addSecurityEventInChatrooms(const std::shared_ptr<Address> &peerDeviceAddr,
 	                                 ConferenceSecurityEvent::SecurityEventType securityEventType) override;
 
-	std::shared_ptr<ConferenceSecurityEvent> onDeviceAdded(const IdentityAddress &newDeviceAddr,
+	std::shared_ptr<ConferenceSecurityEvent> onDeviceAdded(const std::shared_ptr<Address> &newDeviceAddr,
 	                                                       std::shared_ptr<Participant> participant,
 	                                                       const std::shared_ptr<AbstractChatRoom> &chatRoom,
 	                                                       ChatRoom::SecurityLevel currentSecurityLevel) override;
diff --git a/src/chat/encryption/lime-x3dh-server-engine.cpp b/src/chat/encryption/lime-x3dh-server-engine.cpp
index 20e36460f81552322b92e2a9d303cb930e8e543c..f82f018d31c4684594b314228a721cb967824228 100644
--- a/src/chat/encryption/lime-x3dh-server-engine.cpp
+++ b/src/chat/encryption/lime-x3dh-server-engine.cpp
@@ -21,9 +21,9 @@
 #include "lime-x3dh-server-engine.h"
 #include "bctoolbox/crypto.h"
 #include "bctoolbox/exception.hh"
-#include "c-wrapper/c-wrapper.h"
 #include <bctoolbox/defs.h>
 
+#include "c-wrapper/c-wrapper.h"
 #include "chat/chat-message/chat-message-p.h"
 #include "chat/chat-room/chat-room-p.h"
 #include "chat/chat-room/client-group-chat-room.h"
@@ -34,6 +34,7 @@
 #include "content/header/header-param.h"
 #include "core/core.h"
 #include "factory/factory.h"
+#include "lime-x3dh-server-engine.h"
 #include "private.h"
 
 using namespace std;
@@ -56,7 +57,7 @@ LimeX3dhEncryptionServerEngine::processOutgoingMessage(const std::shared_ptr<Cha
                                                        BCTBX_UNUSED(int &errorCode)) {
 	// We use a shared_ptr here due to non synchronism with the lambda in the encrypt method
 	shared_ptr<AbstractChatRoom> chatRoom = message->getChatRoom();
-	const string &toDeviceId = message->getToAddress().asString();
+	const string &toDeviceId = message->getToAddress()->asStringUriOnly();
 	const Content *internalContent;
 
 	// Check if chatroom is encrypted or not
diff --git a/src/chat/ics/ics.cpp b/src/chat/ics/ics.cpp
index 11fe6ad368261b5c2b66b8d47474a039f6b5bafc..43e6e1ee10c78ea37fca8120f3b3c8ec8d4d5fa7 100644
--- a/src/chat/ics/ics.cpp
+++ b/src/chat/ics/ics.cpp
@@ -18,6 +18,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <algorithm>
 #include <iomanip>
 #include <sstream>
 
@@ -289,12 +290,12 @@ std::shared_ptr<ConferenceInfo> Ics::Icalendar::toConferenceInfo() const {
 
 	if (!event->getOrganizerAddress().empty()) {
 		const auto &org = event->getOrganizer();
-		const auto &orgAddress = IdentityAddress(org.first);
+		const auto &orgAddress = Address::create(org.first);
 		const auto &orgParams = org.second;
-		if (orgAddress.isValid()) {
+		if (orgAddress && orgAddress->isValid()) {
 			confInfo->setOrganizer(orgAddress, orgParams);
 		} else {
-			lWarning() << "Could not parse organizer's address:" << event->getOrganizerAddress()
+			lWarning() << "Could not parse organizer's address: " << event->getOrganizerAddress()
 			           << " because it is not a valid address";
 		}
 	}
@@ -303,11 +304,11 @@ std::shared_ptr<ConferenceInfo> Ics::Icalendar::toConferenceInfo() const {
 		auto address = attendee.first;
 		auto params = attendee.second;
 		if (!address.empty()) {
-			const auto &addr = IdentityAddress(address);
-			if (addr.isValid()) {
+			const auto addr = Address::create(address);
+			if (addr && addr->isValid()) {
 				confInfo->addParticipant(addr, params);
 			} else {
-				lWarning() << "Could not parse attendee's address:" << address << " because it is not a valid address";
+				lWarning() << "Could not parse attendee's address: " << address << " because it is not a valid address";
 			}
 		}
 	}
@@ -322,8 +323,8 @@ std::shared_ptr<ConferenceInfo> Ics::Icalendar::toConferenceInfo() const {
 	}
 
 	if (!event->getXConfUri().empty()) {
-		const ConferenceAddress uri(event->getXConfUri());
-		if (uri.isValid()) {
+		const std::shared_ptr<Address> uri = Address::create(event->getXConfUri());
+		if (uri && uri->isValid()) {
 			confInfo->setUri(uri);
 		} else {
 			lWarning() << "Could not parse conference's uri address:" << event->getXConfUri()
diff --git a/src/chat/ics/parser/ics-parser.cpp b/src/chat/ics/parser/ics-parser.cpp
index 5b296f2b73a594ba695a23ac600236c1b7a9e08d..bf56c86f8f31321b21eed2a4d1966a79b30c1056 100644
--- a/src/chat/ics/parser/ics-parser.cpp
+++ b/src/chat/ics/parser/ics-parser.cpp
@@ -210,17 +210,20 @@ public:
 		}
 	}
 
-	void setOrganizer(const string &organizer) {
-		if (!organizer.empty()) {
+	Ics::Event::organizer_t parseMemberLine(const string &line, const string keyword) {
+		if (!line.empty()) {
 			Ics::Event::attendee_params_t params;
-			size_t paramStart = organizer.find("ORGANIZER");
+			size_t paramStart = line.find(keyword);
 			// Chop off ATTENDEE
-			const auto &paramAddress = organizer.substr(paramStart + strlen("ORGANIZER"));
+			const auto &paramAddress = line.substr(paramStart + keyword.size());
 			size_t addressStart = paramAddress.find(":");
 			// Split parameters and address.
 			// Parameters end at the first : sign
 			const auto &paramsStr = paramAddress.substr(0, addressStart);
-			const auto &address = paramAddress.substr(addressStart + 1, organizer.size());
+			// The address length is the size of the string contaning member parameters and address minus the position
+			// at which the address starts minus 1
+			const auto addressLength = paramAddress.size() - addressStart - 3;
+			const auto &address = paramAddress.substr(addressStart + 1, addressLength);
 			if (!paramsStr.empty()) {
 				const auto &splittedValue = bctoolbox::Utils::split(Utils::trim(paramsStr), ";");
 				for (const auto &param : splittedValue) {
@@ -232,33 +235,19 @@ public:
 					}
 				}
 			}
-			mOrganizer = std::make_pair(address, params);
+			return std::make_pair(address, params);
 		}
+		return Ics::Event::organizer_t();
+	}
+
+	void setOrganizer(const string &organizer) {
+		mOrganizer = parseMemberLine(organizer, "ORGANIZER");
 	}
 
 	void addAttendee(const string &attendee) {
-		if (!attendee.empty()) {
-			Ics::Event::attendee_params_t params;
-			size_t paramStart = attendee.find("ATTENDEE");
-			// Chop off ATTENDEE
-			const auto &paramAddress = attendee.substr(paramStart + strlen("ATTENDEE"));
-			size_t addressStart = paramAddress.find(":");
-			// Split parameters and address.
-			// Parameters end at the first : sign
-			const auto &paramsStr = paramAddress.substr(0, addressStart);
-			const auto &address = paramAddress.substr(addressStart + 1, attendee.size());
-			if (!paramsStr.empty()) {
-				const auto &splittedValue = bctoolbox::Utils::split(Utils::trim(paramsStr), ";");
-				for (const auto &param : splittedValue) {
-					if (!param.empty()) {
-						auto equal = param.find("=");
-						string name = param.substr(0, equal);
-						string value = param.substr(equal + 1, param.size());
-						params.insert(std::make_pair(name, value));
-					}
-				}
-			}
-			mAttendees.insert(std::make_pair(address, params));
+		auto mAttendee = parseMemberLine(attendee, "ATTENDEE");
+		if (mAttendee != Ics::Event::organizer_t()) {
+			mAttendees.insert(mAttendee);
 		}
 	}
 
diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp
index b00456244a72adf9c0d962faef805d982bdd31e6..51a4861ac66f01e8f3c08cba623c34647037163f 100644
--- a/src/chat/modifier/cpim-chat-message-modifier.cpp
+++ b/src/chat/modifier/cpim-chat-message-modifier.cpp
@@ -25,6 +25,7 @@
 
 #include "address/address.h"
 #include "chat/chat-message/chat-message-p.h"
+#include "chat/chat-room/chat-room.h"
 #include "chat/cpim/cpim.h"
 #include "content/content-disposition.h"
 #include "content/content-type.h"
@@ -56,10 +57,10 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode(const shared_ptr<Cha
                                                             BCTBX_UNUSED(int &errorCode)) {
 	Cpim::Message cpimMessage;
 
-	cpimMessage.addMessageHeader(Cpim::FromHeader(cpimAddressUri(message->getFromAddress().asAddress()),
-	                                              cpimAddressDisplayName(message->getFromAddress().asAddress())));
-	cpimMessage.addMessageHeader(Cpim::ToHeader(cpimAddressUri(message->getToAddress().asAddress()),
-	                                            cpimAddressDisplayName(message->getToAddress().asAddress())));
+	cpimMessage.addMessageHeader(
+	    Cpim::FromHeader(cpimAddressUri(message->getFromAddress()), cpimAddressDisplayName(message->getFromAddress())));
+	cpimMessage.addMessageHeader(
+	    Cpim::ToHeader(cpimAddressUri(message->getToAddress()), cpimAddressDisplayName(message->getToAddress())));
 	cpimMessage.addMessageHeader(Cpim::DateTimeHeader(message->getTime()));
 
 	if (message->getPrivate()->getPositiveDeliveryNotificationRequired() ||
@@ -96,8 +97,8 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode(const shared_ptr<Cha
 			}
 			cpimMessage.addMessageHeader(
 			    Cpim::GenericHeader(linphoneNamespace + "." + linphoneReplyingToMessageIdHeader, replyToMessageId));
-			const IdentityAddress &senderAddress = message->getReplyToSenderAddress();
-			string address = senderAddress.asString();
+			const std::shared_ptr<Address> &senderAddress = message->getReplyToSenderAddress();
+			string address = senderAddress->toString();
 			cpimMessage.addMessageHeader(
 			    Cpim::GenericHeader(linphoneNamespace + "." + linphoneReplyingToMessageSenderHeader, address));
 		}
@@ -198,9 +199,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode(const shared_ptr<Cha
 	}
 
 	auto fromHeader = static_pointer_cast<const Cpim::FromHeader>(cpimMessage->getMessageHeader("From"));
-	Address cpimFromAddress(fromHeader->getValue());
-	auto toHeader = static_pointer_cast<const Cpim::ToHeader>(cpimMessage->getMessageHeader("To"));
-	Address cpimToAddress(toHeader->getValue());
+	std::shared_ptr<Address> cpimFromAddress = Address::create(fromHeader->getValue());
 	auto dateTimeHeader = static_pointer_cast<const Cpim::DateTimeHeader>(cpimMessage->getMessageHeader("DateTime"));
 	if (dateTimeHeader) message->getPrivate()->setTime(dateTimeHeader->getTime());
 
@@ -240,7 +239,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode(const shared_ptr<Cha
 		auto replyToSenderHeader = cpimMessage->getMessageHeader(linphoneReplyingToMessageSenderHeader, linphoneNsName);
 		if (replyToMessageIdHeader && replyToSenderHeader) {
 			message->getPrivate()->setReplyToMessageIdAndSenderAddress(
-			    replyToMessageIdHeader->getValue(), IdentityAddress(replyToSenderHeader->getValue()));
+			    replyToMessageIdHeader->getValue(), Address::create(replyToSenderHeader->getValue()));
 		}
 	}
 
@@ -248,7 +247,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode(const shared_ptr<Cha
 
 	// Discard message if sender authentication is enabled and failed
 	if (message->getPrivate()->senderAuthenticationEnabled) {
-		if (cpimFromAddress == message->getAuthenticatedFromAddress().asAddress()) {
+		if (*cpimFromAddress == message->getAuthenticatedFromAddress()) {
 			lInfo() << "[CPIM] Sender authentication successful";
 		} else {
 			lWarning() << "[CPIM] Sender authentication failed";
@@ -259,26 +258,25 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode(const shared_ptr<Cha
 
 	// Modify the initial message since there was no error
 	message->setInternalContent(newContent);
-	if (cpimFromAddress.isValid()) message->getPrivate()->forceFromAddress(cpimFromAddress);
+	if (cpimFromAddress && cpimFromAddress->isValid()) message->getPrivate()->forceFromAddress(cpimFromAddress);
 
 	return ChatMessageModifier::Result::Done;
 }
 
-string CpimChatMessageModifier::cpimAddressDisplayName(const Address &addr) const {
-	return addr.getDisplayName();
+string CpimChatMessageModifier::cpimAddressDisplayName(const std::shared_ptr<Address> &addr) const {
+	return addr->getDisplayName();
 }
 
-string CpimChatMessageModifier::cpimAddressUri(const Address &addr) const {
-	return addr.asStringUriOnly();
+string CpimChatMessageModifier::cpimAddressUri(const std::shared_ptr<Address> &addr) const {
+	return addr->asStringUriOnly();
 }
 
 Content *CpimChatMessageModifier::createMinimalCpimContentForLimeMessage(const shared_ptr<ChatMessage> &message) const {
 	shared_ptr<AbstractChatRoom> chatRoom = message->getChatRoom();
-	const string &localDeviceId = chatRoom->getLocalAddress().asString();
+	const string &localDeviceId = chatRoom->getLocalAddress()->asStringUriOnly();
 
 	Cpim::Message cpimMessage;
-	cpimMessage.addMessageHeader(
-	    Cpim::FromHeader(localDeviceId, cpimAddressDisplayName(message->getToAddress().asAddress())));
+	cpimMessage.addMessageHeader(Cpim::FromHeader(localDeviceId, cpimAddressDisplayName(message->getToAddress())));
 	cpimMessage.addMessageHeader(Cpim::NsHeader(imdnNamespaceUrn, imdnNamespace));
 	cpimMessage.addMessageHeader(
 	    Cpim::GenericHeader(imdnNamespace + "." + imdnMessageIdHeader, message->getImdnMessageId()));
diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h
index 929ca4375c99f24b753a1906a2bf94ffe3f4a989..e2b7ba6632865d0b05b2a50cbb501602d9508296 100644
--- a/src/chat/modifier/cpim-chat-message-modifier.h
+++ b/src/chat/modifier/cpim-chat-message-modifier.h
@@ -38,8 +38,8 @@ public:
 	                                                 const Content &cpimContent) const;
 
 private:
-	std::string cpimAddressDisplayName(const Address &addr) const;
-	std::string cpimAddressUri(const Address &addr) const;
+	std::string cpimAddressDisplayName(const std::shared_ptr<Address> &addr) const;
+	std::string cpimAddressUri(const std::shared_ptr<Address> &addr) const;
 };
 
 LINPHONE_END_NAMESPACE
diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp
index 7765f5051aec0fde391a2a8768895d9b7d00e4aa..26d7d95639582248eda068ef28e3fab071abbb77 100644
--- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp
+++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp
@@ -461,8 +461,8 @@ void FileTransferChatMessageModifier::processAuthRequestedUpload(belle_sip_auth_
 	 * the requested auth info shall thus be present in linphone core
 	 * This request will thus not use the auth requested callback to get the information
 	 * - Stored auth information in linphone core are indexed by username/domain */
-	linphone_core_fill_belle_sip_auth_event(message->getCore()->getCCore(), event, address.getUsername().data(),
-	                                        address.getDomain().data());
+	linphone_core_fill_belle_sip_auth_event(message->getCore()->getCCore(), event, address->getUsername().data(),
+	                                        address->getDomain().data());
 
 	// For digest auth: If there is no body handler, now it is a good time to add it
 	if (belle_sip_auth_event_get_mode(event) == BELLE_SIP_AUTH_MODE_HTTP_DIGEST) {
@@ -543,7 +543,7 @@ int FileTransferChatMessageModifier::startHttpTransfer(const string &url,
 	httpRequest = belle_http_request_create(
 	    action.c_str(), uri,
 	    belle_http_header_create("User-Agent", linphone_core_get_user_agent(message->getCore()->getCCore())),
-	    belle_http_header_create("From", message->getLocalAddress().asString().c_str()), nullptr);
+	    belle_http_header_create("From", message->getLocalAddress()->toString().c_str()), nullptr);
 
 	if (!httpRequest) {
 		lWarning() << "Could not create http request for uri " << url;
@@ -881,8 +881,8 @@ void FileTransferChatMessageModifier::processAuthRequestedDownload(belle_sip_aut
 	 * the requested auth info shall thus be present in linphone core
 	 * This request will thus not use the auth requested callback to get the information
 	 * - Stored auth information in linphone core are indexed by username/domain */
-	linphone_core_fill_belle_sip_auth_event(message->getCore()->getCCore(), event, address.getUsername().data(),
-	                                        address.getDomain().data());
+	linphone_core_fill_belle_sip_auth_event(message->getCore()->getCCore(), event, address->getUsername().data(),
+	                                        address->getDomain().data());
 }
 
 static void _chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) {
diff --git a/src/chat/notification/imdn.cpp b/src/chat/notification/imdn.cpp
index b0c6581c567563ed3e263529b19c1a3dfd6f11a7..b1353dd49647a72da6b15d5ccc2a34a902c2026a 100644
--- a/src/chat/notification/imdn.cpp
+++ b/src/chat/notification/imdn.cpp
@@ -153,7 +153,6 @@ void Imdn::onNetworkReachable(bool sipNetworkReachable, BCTBX_UNUSED(bool mediaN
 }
 
 // -----------------------------------------------------------------------------
-
 #ifndef _MSC_VER
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
@@ -246,7 +245,10 @@ void Imdn::parse(const shared_ptr<ChatMessage> &chatMessage) {
 
 			auto policy = linphone_core_get_im_notif_policy(cr->getCore()->getCCore());
 			time_t imdnTime = chatMessage->getTime();
-			const IdentityAddress &participantAddress = chatMessage->getFromAddress().getAddressWithoutGruu();
+			std::shared_ptr<Address> participantAddress =
+			    Address::create(chatMessage->getFromAddress()->getUriWithoutGruu());
+			std::shared_ptr<Address> localAddress = cr->getLocalAddress();
+			std::shared_ptr<Address> chatMessageFromAddress = cm->getFromAddress();
 			auto &deliveryNotification = imdn->getDeliveryNotification();
 			auto &displayNotification = imdn->getDisplayNotification();
 			if (deliveryNotification.present()) {
@@ -261,10 +263,10 @@ void Imdn::parse(const shared_ptr<ChatMessage> &chatMessage) {
 					// When the IMDN status is failed for reason code 488 (Not acceptable here) and the chatroom is
 					// encrypted, something is wrong with our encryption session with this peer, stale the active
 					// session the next message (which can be a resend of this one) will be encrypted with a new session
-					if (cr->getLocalAddress() ==
-					        cm->getFromAddress() // check the imdn is in response to a message sent by the local user
-					    && status.getFailed().present() // that we have a fail tag
-					    && status.getReason().present() // and a reason tag
+					if (localAddress->weakEqual(*chatMessageFromAddress) // check the imdn is in response to a message
+					                                                     // sent by the local user
+					    && status.getFailed().present()                  // that we have a fail tag
+					    && status.getReason().present()                  // and a reason tag
 					    &&
 					    (cr->getCapabilities() & ChatRoom::Capabilities::Encrypted)) { // and the chatroom is encrypted
 						// Check the reason code is 488
@@ -273,11 +275,11 @@ void Imdn::parse(const shared_ptr<ChatMessage> &chatMessage) {
 						if ((reason.getCode() == 488) && imee) {
 							// stale the encryption sessions with this device: something went wrong, we will create a
 							// new one at next encryption
-							lWarning() << "Peer " << chatMessage->getFromAddress().asString()
-							           << " could not decrypt message from " << cm->getFromAddress().asString()
+							lWarning() << "Peer " << chatMessage->getFromAddress()->toString()
+							           << " could not decrypt message from " << chatMessageFromAddress->toString()
 							           << " -> Stale the lime X3DH session";
-							imee->staleSession(cm->getFromAddress().asString(),
-							                   chatMessage->getFromAddress().asString());
+							imee->staleSession(chatMessageFromAddress->asStringUriOnly(),
+							                   chatMessage->getFromAddress()->asStringUriOnly());
 						}
 					}
 				}
@@ -285,8 +287,7 @@ void Imdn::parse(const shared_ptr<ChatMessage> &chatMessage) {
 				auto &status = displayNotification.get().getStatus();
 				if (status.getDisplayed().present() && linphone_im_notif_policy_get_recv_imdn_displayed(policy)) {
 					cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::Displayed, imdnTime);
-					if (cr->getLocalAddress().getAddressWithoutGruu() ==
-					    chatMessage->getFromAddress().getAddressWithoutGruu()) {
+					if (localAddress->weakEqual(*participantAddress)) {
 						auto lastMsg = cr->getLastChatMessageInHistory();
 						if (lastMsg == cm) {
 							lInfo() << "Received Display IMDN from ourselves for last message in this chat room, "
@@ -356,12 +357,11 @@ bool Imdn::aggregationEnabled() const {
 }
 
 LinphoneProxyConfig *Imdn::getRelatedProxyConfig() {
-	LinphoneAddress *addr = linphone_address_new(chatRoom->getLocalAddress().asString().c_str());
+	LinphoneAddress *addr = chatRoom->getLocalAddress()->toC();
 	if (!addr) {
 		return NULL;
 	}
 	LinphoneProxyConfig *cfg = linphone_core_lookup_proxy_by_identity_strict(chatRoom->getCore()->getCCore(), addr);
-	linphone_address_unref(addr);
 	return cfg;
 }
 
diff --git a/src/chat/notification/is-composing-listener.h b/src/chat/notification/is-composing-listener.h
index e047015675509ede05aec73238f059b5e847c057..cf4fa214171f0b7fa76d1a1caa9f9fc3bf3ce5ee 100644
--- a/src/chat/notification/is-composing-listener.h
+++ b/src/chat/notification/is-composing-listener.h
@@ -34,7 +34,7 @@ public:
 	virtual ~IsComposingListener() = default;
 
 	virtual void onIsComposingStateChanged(bool isComposing) = 0;
-	virtual void onIsRemoteComposingStateChanged(const Address &remoteAddr, bool isComposing) = 0;
+	virtual void onIsRemoteComposingStateChanged(const std::shared_ptr<Address> &remoteAddr, bool isComposing) = 0;
 	virtual void onIsComposingRefreshNeeded() = 0;
 };
 
diff --git a/src/chat/notification/is-composing.cpp b/src/chat/notification/is-composing.cpp
index 73af9dc924ce0b7676e54662ea382c281c70d69e..479fab66ca2b1bb6c4b56fb5cbe8301920f65c64 100644
--- a/src/chat/notification/is-composing.cpp
+++ b/src/chat/notification/is-composing.cpp
@@ -87,7 +87,7 @@ string IsComposing::createXml(bool isComposing) {
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
-void IsComposing::parse(const Address &remoteAddr, const string &text) {
+void IsComposing::parse(const std::shared_ptr<Address> &remoteAddr, const string &text) {
 #ifdef HAVE_ADVANCED_IM
 	istringstream data(text);
 	unique_ptr<Xsd::IsComposing::IsComposing> node(
@@ -97,10 +97,10 @@ void IsComposing::parse(const Address &remoteAddr, const string &text) {
 	if (node->getState() == "active") {
 		unsigned long long refresh = 0;
 		if (node->getRefresh().present()) refresh = node->getRefresh().get();
-		startRemoteRefreshTimer(remoteAddr.asStringUriOnly(), refresh);
+		startRemoteRefreshTimer(remoteAddr->asStringUriOnly(), refresh);
 		listener->onIsRemoteComposingStateChanged(remoteAddr, true);
 	} else if (node->getState() == "idle") {
-		stopRemoteRefreshTimer(remoteAddr.asStringUriOnly());
+		stopRemoteRefreshTimer(remoteAddr->asStringUriOnly());
 		listener->onIsRemoteComposingStateChanged(remoteAddr, false);
 	}
 #else
@@ -190,7 +190,7 @@ int IsComposing::refreshTimerExpired() {
 }
 
 int IsComposing::remoteRefreshTimerExpired(const string &uri) {
-	listener->onIsRemoteComposingStateChanged(Address(uri), false);
+	listener->onIsRemoteComposingStateChanged(Address::create(uri), false);
 	stopRemoteRefreshTimer(uri);
 	return BELLE_SIP_STOP;
 }
diff --git a/src/chat/notification/is-composing.h b/src/chat/notification/is-composing.h
index 49a68365b6aa79c0c1c64634f0cb690b643f287a..e63544f7b3ff9aff216ab09b926cb066501e5f98 100644
--- a/src/chat/notification/is-composing.h
+++ b/src/chat/notification/is-composing.h
@@ -40,7 +40,7 @@ public:
 	~IsComposing();
 
 	std::string createXml(bool isComposing);
-	void parse(const Address &remoteAddr, const std::string &content);
+	void parse(const std::shared_ptr<Address> &remoteAddr, const std::string &content);
 	void startIdleTimer();
 	void startRefreshTimer();
 	void stopIdleTimer();
diff --git a/src/conference/conference-id.cpp b/src/conference/conference-id.cpp
index 0efaa36ac042623362500ced4d22a4c46603525c..5188957267d1d6e475fbd9e493759f3355bb03cc 100644
--- a/src/conference/conference-id.cpp
+++ b/src/conference/conference-id.cpp
@@ -19,6 +19,7 @@
  */
 
 #include "conference-id.h"
+#include "logger/logger.h"
 
 // =============================================================================
 
@@ -29,9 +30,15 @@ LINPHONE_BEGIN_NAMESPACE
 ConferenceId::ConferenceId() {
 }
 
-ConferenceId::ConferenceId(const ConferenceAddress &peerAddress, const ConferenceAddress &localAddress) {
-	this->peerAddress = peerAddress;
-	this->localAddress = localAddress;
+ConferenceId::ConferenceId(const std::shared_ptr<Address> &peerAddress,
+                           const std::shared_ptr<const Address> &localAddress) {
+	this->peerAddress = (peerAddress) ? Address::create(peerAddress->getUri()) : nullptr;
+	this->localAddress = (localAddress) ? Address::create(localAddress->getUri()) : nullptr;
+}
+
+ConferenceId::ConferenceId(const std::shared_ptr<Address> &peerAddress, const std::shared_ptr<Address> &localAddress) {
+	this->peerAddress = (peerAddress) ? Address::create(peerAddress->getUri()) : nullptr;
+	this->localAddress = (localAddress) ? Address::create(localAddress->getUri()) : nullptr;
 }
 
 ConferenceId::ConferenceId(const ConferenceId &other)
@@ -45,7 +52,8 @@ ConferenceId &ConferenceId::operator=(const ConferenceId &other) {
 }
 
 bool ConferenceId::operator==(const ConferenceId &other) const {
-	return peerAddress == other.peerAddress && localAddress == other.localAddress;
+	return peerAddress && other.peerAddress && (*peerAddress == *(other.peerAddress)) && localAddress &&
+	       other.localAddress && (*localAddress == *(other.localAddress));
 }
 
 bool ConferenceId::operator!=(const ConferenceId &other) const {
@@ -53,19 +61,28 @@ bool ConferenceId::operator!=(const ConferenceId &other) const {
 }
 
 bool ConferenceId::operator<(const ConferenceId &other) const {
-	return peerAddress < other.peerAddress || (peerAddress == other.peerAddress && localAddress < other.localAddress);
+	return *peerAddress < *(other.peerAddress) ||
+	       (*peerAddress == *(other.peerAddress) && *localAddress < *(other.localAddress));
+}
+
+void ConferenceId::setPeerAddress(const std::shared_ptr<Address> &addr) {
+	peerAddress = addr;
+}
+
+void ConferenceId::setLocalAddress(const std::shared_ptr<Address> &addr) {
+	localAddress = addr;
 }
 
-const ConferenceAddress &ConferenceId::getPeerAddress() const {
+const std::shared_ptr<Address> &ConferenceId::getPeerAddress() const {
 	return peerAddress;
 }
 
-const ConferenceAddress &ConferenceId::getLocalAddress() const {
+const std::shared_ptr<Address> &ConferenceId::getLocalAddress() const {
 	return localAddress;
 }
 
 bool ConferenceId::isValid() const {
-	return peerAddress.isValid() && localAddress.isValid();
+	return peerAddress && peerAddress->isValid() && localAddress && localAddress->isValid();
 }
 
 LINPHONE_END_NAMESPACE
diff --git a/src/conference/conference-id.h b/src/conference/conference-id.h
index 5c13cce317dac61b67c2cbec954385a67100ab76..bfafa5098e88801f8fe223036d10e8b3a48d7228 100644
--- a/src/conference/conference-id.h
+++ b/src/conference/conference-id.h
@@ -21,7 +21,7 @@
 #ifndef _L_CONFERENCE_ID_H_
 #define _L_CONFERENCE_ID_H_
 
-#include "address/identity-address.h"
+#include "address/address.h"
 
 // =============================================================================
 
@@ -30,7 +30,8 @@ LINPHONE_BEGIN_NAMESPACE
 class LINPHONE_PUBLIC ConferenceId {
 public:
 	ConferenceId();
-	ConferenceId(const ConferenceAddress &peerAddress, const ConferenceAddress &localAddress);
+	ConferenceId(const std::shared_ptr<Address> &peerAddress, const std::shared_ptr<const Address> &localAddress);
+	ConferenceId(const std::shared_ptr<Address> &peerAddress, const std::shared_ptr<Address> &localAddress);
 	ConferenceId(const ConferenceId &other);
 
 	virtual ~ConferenceId() = default;
@@ -46,18 +47,25 @@ public:
 
 	bool operator<(const ConferenceId &other) const;
 
-	const ConferenceAddress &getPeerAddress() const;
-	const ConferenceAddress &getLocalAddress() const;
+	const std::shared_ptr<Address> &getPeerAddress() const;
+	const std::shared_ptr<Address> &getLocalAddress() const;
+
+	void setPeerAddress(const std::shared_ptr<Address> &addr);
+	void setLocalAddress(const std::shared_ptr<Address> &addr);
 
 	bool isValid() const;
 
 private:
-	ConferenceAddress peerAddress;
-	ConferenceAddress localAddress;
+	std::shared_ptr<Address> peerAddress;
+	std::shared_ptr<Address> localAddress;
 };
 
 inline std::ostream &operator<<(std::ostream &os, const ConferenceId &conferenceId) {
-	os << "ConferenceId(peer=" << conferenceId.getPeerAddress() << ", local=" << conferenceId.getLocalAddress() << ")";
+	auto peerAddress =
+	    (conferenceId.getPeerAddress()) ? conferenceId.getPeerAddress()->asStringUriOnly() : std::string("<undefined>");
+	auto localAddress = (conferenceId.getLocalAddress()) ? conferenceId.getLocalAddress()->asStringUriOnly()
+	                                                     : std::string("<undefined>");
+	os << "ConferenceId(peer=" << peerAddress << ", local=" << localAddress << ")";
 	return os;
 }
 
@@ -68,8 +76,9 @@ namespace std {
 template <>
 struct hash<LinphonePrivate::ConferenceId> {
 	std::size_t operator()(const LinphonePrivate::ConferenceId &conferenceId) const {
-		return hash<string>()(conferenceId.getPeerAddress().asString()) ^
-		       (hash<string>()(conferenceId.getLocalAddress().asString()) << 1);
+		const auto peerAddress = conferenceId.getPeerAddress() ? conferenceId.getPeerAddress()->asString() : "sip:";
+		const auto localAddress = conferenceId.getLocalAddress() ? conferenceId.getLocalAddress()->asString() : "sip:";
+		return hash<string>()(peerAddress) ^ (hash<string>()(localAddress) << 1);
 	}
 };
 } // namespace std
diff --git a/src/conference/conference-info.cpp b/src/conference/conference-info.cpp
index 3474257be9b77f176e8239f05cb4a5525efc3b49..233772236807c7271ee375009368c5186c9d889e 100644
--- a/src/conference/conference-info.cpp
+++ b/src/conference/conference-info.cpp
@@ -38,22 +38,19 @@ const std::string ConferenceInfo::sequenceParam = "X-SEQ";
 ConferenceInfo::ConferenceInfo() {
 }
 
-ConferenceInfo::~ConferenceInfo() {
-}
-
 const ConferenceInfo::organizer_t &ConferenceInfo::getOrganizer() const {
 	return mOrganizer;
 }
 
-const IdentityAddress &ConferenceInfo::getOrganizerAddress() const {
+const std::shared_ptr<Address> &ConferenceInfo::getOrganizerAddress() const {
 	return getOrganizer().first;
 }
 
-void ConferenceInfo::setOrganizer(const IdentityAddress &organizer, const participant_params_t &params) {
-	mOrganizer = std::make_pair(organizer, params);
+void ConferenceInfo::setOrganizer(const std::shared_ptr<Address> &organizer, const participant_params_t &params) {
+	mOrganizer = std::make_pair(Address::create(organizer->getUri()), params);
 }
 
-void ConferenceInfo::setOrganizer(const IdentityAddress &organizer) {
+void ConferenceInfo::setOrganizer(const std::shared_ptr<Address> &organizer) {
 	ConferenceInfo::participant_params_t params;
 	setOrganizer(organizer, params);
 }
@@ -75,67 +72,67 @@ const ConferenceInfo::participant_list_t &ConferenceInfo::getParticipants() cons
 	return mParticipants;
 }
 
-const bctbx_list_t *ConferenceInfo::getParticipantsCList() const {
-	return mParticipantsList.construct(mParticipants,
-	                                   [](const pair<IdentityAddress, participant_params_t> &p) -> LinphoneAddress * {
-		                                   return linphone_address_new(p.first.asString().c_str());
-	                                   });
-}
-
 void ConferenceInfo::setParticipants(const participant_list_t &participants) {
-	mParticipants = participants;
+	for (const auto &p : participants) {
+		addParticipant(p.first, p.second);
+	}
 }
 
-void ConferenceInfo::addParticipant(const IdentityAddress &participant) {
+void ConferenceInfo::addParticipant(const std::shared_ptr<Address> &participant) {
 	ConferenceInfo::participant_params_t params;
 	addParticipant(participant, params);
 }
 
-void ConferenceInfo::addParticipant(const IdentityAddress &participant, const participant_params_t &params) {
-	mParticipants.insert(std::make_pair(participant, params));
+void ConferenceInfo::addParticipant(const std::shared_ptr<Address> &participant, const participant_params_t &params) {
+	mParticipants.insert(std::make_pair(Address::create(participant->getUri()), params));
 }
 
-void ConferenceInfo::removeParticipant(const IdentityAddress &participant) {
-	const auto it = std::find_if(mParticipants.cbegin(), mParticipants.cend(),
-	                             [&participant](const auto &p) { return (p.first == participant); });
+void ConferenceInfo::removeParticipant(const std::shared_ptr<Address> &participant) {
+	auto it = std::find_if(mParticipants.begin(), mParticipants.end(),
+	                       [&participant](const auto &p) { return (participant->weakEqual(*p.first)); });
 	if (it == mParticipants.cend()) {
 		lInfo() << "Unable to find participant with address " << participant << " in conference info " << this
-		        << " (address " << getUri() << ")";
+		        << " (address " << *getUri() << ")";
 	} else {
 		mParticipants.erase(it);
 	}
 }
 
-void ConferenceInfo::addParticipantParam(const IdentityAddress &participant,
+void ConferenceInfo::addParticipantParam(const std::shared_ptr<Address> &participant,
                                          const std::string &param,
                                          const std::string &value) {
-	try {
-		auto &params = mParticipants.at(participant);
+	auto it = std::find_if(mParticipants.begin(), mParticipants.end(),
+	                       [&participant](const auto &p) { return (participant->weakEqual(*p.first)); });
+	if (it != mParticipants.end()) {
+		auto &params = (*it).second;
 		params[param] = value;
-	} catch (std::out_of_range &) {
 	}
 }
 
-const std::string ConferenceInfo::getParticipantParam(const IdentityAddress &participant,
+const std::string ConferenceInfo::getParticipantParam(const std::shared_ptr<Address> &participant,
                                                       const std::string &param) const {
 	try {
-		const auto &params = mParticipants.at(participant);
-		return params.at(param);
+		auto it = std::find_if(mParticipants.begin(), mParticipants.end(),
+		                       [&participant](const auto &p) { return (participant->weakEqual(*p.first)); });
+		if (it != mParticipants.cend()) {
+			const auto &params = (*it).second;
+			return params.at(param);
+		}
 	} catch (std::out_of_range &) {
-		return std::string();
 	}
+	return std::string();
 }
 
 bool ConferenceInfo::isValidUri() const {
-	return (mUri != ConferenceAddress());
+	return (mUri != nullptr) && mUri->isValid();
 }
 
-const ConferenceAddress &ConferenceInfo::getUri() const {
+const std::shared_ptr<Address> &ConferenceInfo::getUri() const {
 	return mUri;
 }
 
-void ConferenceInfo::setUri(const ConferenceAddress uri) {
-	mUri = uri;
+void ConferenceInfo::setUri(const std::shared_ptr<Address> uri) {
+	mUri = Address::create(uri->getUri());
 }
 
 time_t ConferenceInfo::getDateTime() const {
@@ -265,23 +262,23 @@ const string ConferenceInfo::toIcsString(bool cancel, int sequence) const {
 
 	auto event = make_shared<Ics::Event>();
 	const auto &organizerAddress = getOrganizerAddress();
-	if (organizerAddress.isValid()) {
-		const auto uri = organizerAddress.getAddressWithoutGruu().asString();
+	if (organizerAddress && organizerAddress->isValid()) {
+		const auto uri = organizerAddress->asStringUriOnly();
 		event->setOrganizer(uri, mOrganizer.second);
 	}
 
 	event->setSummary(mSubject);
 	event->setDescription(mDescription);
 
-	if (mUri.isValid()) {
-		const auto uri = mUri.asString();
+	if (mUri && mUri->isValid()) {
+		const auto uri = mUri->asStringUriOnly();
 		event->setXConfUri(uri);
 	}
 
 	for (const auto &participant : mParticipants) {
 		const auto &address = participant.first;
-		if (address.isValid()) {
-			const auto uri = address.getAddressWithoutGruu().asString();
+		if (address && address->isValid()) {
+			const auto uri = address->asStringUriOnly();
 			event->addAttendee(uri, participant.second);
 		}
 	}
diff --git a/src/conference/conference-info.h b/src/conference/conference-info.h
index ed6fef59692166af0e1745a948972a558038a229..c5f56bbed4f1fa59cbed25775c5d40217d1715f2 100644
--- a/src/conference/conference-info.h
+++ b/src/conference/conference-info.h
@@ -25,12 +25,11 @@
 #include <map>
 #include <string>
 
-#include "address/address.h"
-#include "address/identity-address.h"
+#include <belle-sip/object++.hh>
 
+#include "address/address.h"
 #include "linphone/api/c-types.h"
 #include "linphone/types.h"
-#include <belle-sip/object++.hh>
 
 // =============================================================================
 
@@ -67,10 +66,16 @@ private:
 
 class LINPHONE_PUBLIC ConferenceInfo : public bellesip::HybridObject<LinphoneConferenceInfo, ConferenceInfo> {
 public:
+	struct AddressCmp {
+		bool operator()(const std::shared_ptr<Address> &lhs, const std::shared_ptr<Address> &rhs) const {
+			return *lhs < *rhs;
+		}
+	};
+
 	static const std::string sequenceParam;
 	using participant_params_t = std::map<std::string, std::string>;
-	using participant_list_t = std::map<IdentityAddress, participant_params_t>;
-	using organizer_t = std::pair<IdentityAddress, participant_params_t>;
+	using participant_list_t = std::map<std::shared_ptr<Address>, participant_params_t, AddressCmp>;
+	using organizer_t = std::pair<std::shared_ptr<Address>, participant_params_t>;
 
 	enum class State {
 		New = LinphoneConferenceInfoStateNew,
@@ -79,7 +84,6 @@ public:
 	};
 
 	ConferenceInfo();
-	virtual ~ConferenceInfo();
 
 	ConferenceInfo *clone() const override {
 		return new ConferenceInfo(*this);
@@ -89,26 +93,27 @@ public:
 	static const participant_params_t stringToMemberParameters(const std::string &params);
 
 	const organizer_t &getOrganizer() const;
-	const IdentityAddress &getOrganizerAddress() const;
-	void setOrganizer(const IdentityAddress &organizer, const participant_params_t &params);
-	void setOrganizer(const IdentityAddress &organizer);
+	const std::shared_ptr<Address> &getOrganizerAddress() const;
+	void setOrganizer(const std::shared_ptr<Address> &organizer, const participant_params_t &params);
+	void setOrganizer(const std::shared_ptr<Address> &organizer);
 
 	void addOrganizerParam(const std::string &param, const std::string &value);
 	const std::string getOrganizerParam(const std::string &param) const;
 
 	const participant_list_t &getParticipants() const;
-	const bctbx_list_t *getParticipantsCList() const;
 	void setParticipants(const participant_list_t &participants);
-	void addParticipant(const IdentityAddress &participant);
-	void addParticipant(const IdentityAddress &participant, const participant_params_t &params);
-	void removeParticipant(const IdentityAddress &participant);
+	void addParticipant(const std::shared_ptr<Address> &participant);
+	void addParticipant(const std::shared_ptr<Address> &participant, const participant_params_t &params);
+	void removeParticipant(const std::shared_ptr<Address> &participant);
 
-	void addParticipantParam(const IdentityAddress &participant, const std::string &param, const std::string &value);
-	const std::string getParticipantParam(const IdentityAddress &participant, const std::string &param) const;
+	void addParticipantParam(const std::shared_ptr<Address> &participant,
+	                         const std::string &param,
+	                         const std::string &value);
+	const std::string getParticipantParam(const std::shared_ptr<Address> &participant, const std::string &param) const;
 
 	bool isValidUri() const;
-	const ConferenceAddress &getUri() const;
-	void setUri(const ConferenceAddress uri);
+	const std::shared_ptr<Address> &getUri() const;
+	void setUri(const std::shared_ptr<Address> uri);
 
 	time_t getDateTime() const;
 	void setDateTime(time_t dateTime);
@@ -147,7 +152,7 @@ public:
 private:
 	organizer_t mOrganizer;
 	participant_list_t mParticipants;
-	ConferenceAddress mUri;
+	std::shared_ptr<Address> mUri;
 	time_t mDateTime = (time_t)-1;
 	unsigned int mDuration = 0;
 	std::string mSubject = "";
@@ -155,7 +160,6 @@ private:
 	mutable unsigned int mIcsSequence = 0;
 	mutable std::string mIcsUid = "";
 	State mState = State::New;
-	CListCache mParticipantsList;
 	time_t mCreationTime = (time_t)-1;
 };
 
diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h
index 0da5e2c0f32cea0ce471edb1fa64c7c1080eb983..e69745d3a6b4719176ae78b3d3cf0cbdd6ee0a84 100644
--- a/src/conference/conference-interface.h
+++ b/src/conference/conference-interface.h
@@ -21,12 +21,13 @@
 #ifndef _L_CONFERENCE_INTERFACE_H_
 #define _L_CONFERENCE_INTERFACE_H_
 
+#include <list>
+
 #include <bctoolbox/defs.h>
 
 #include "event-log/events.h"
 #include "linphone/enums/conference-enums.h"
 #include "linphone/utils/general.h"
-#include <list>
 
 // =============================================================================
 
@@ -34,7 +35,7 @@ LINPHONE_BEGIN_NAMESPACE
 
 class Call;
 class ConferenceListenerInterface;
-class IdentityAddress;
+class Address;
 class CallSessionParams;
 class Participant;
 class ConferenceFactoryInterface;
@@ -109,7 +110,7 @@ public:
 	 Get the conference ID of this conference.
 	 @return The Address of the conference.
 	 **/
-	virtual const ConferenceAddress &getConferenceAddress() const = 0;
+	virtual const std::shared_ptr<Address> &getConferenceAddress() const = 0;
 
 	/*
 	 * Get the subject of this conference
@@ -159,11 +160,11 @@ public:
 	 <br>
 	 @param[in] participantAddress The address of the participant to add to this Conference.
 	*/
-	virtual bool addParticipant(const IdentityAddress &participantAddress) = 0;
+	virtual bool addParticipant(const std::shared_ptr<Address> &participantAddress) = 0;
 
 	/*
-	 * Same as function addParticipant(const IdentityAddress &participantAddress), except that call to add is passed by
-	 * the user application.
+	 * Same as function addParticipant(const std::shared_ptr<Address> &participantAddress), except that call to add is
+	 * passed by the user application.
 	 * @param[in] call to be added tot he conference.
 	 * @return True if everything is OK, False otherwise
 	 */
@@ -174,20 +175,20 @@ public:
 	 * @param[in] addresses
 	 * @return True if everything is OK, False otherwise
 	 */
-	virtual bool addParticipants(const std::list<IdentityAddress> &addresses) = 0;
+	virtual bool addParticipants(const std::list<std::shared_ptr<Address>> &addresses) = 0;
 
 	/*
 	 * Add local participant to this conference, this fonction is only available for local focus. Behavior is the same
 	 * as
 	 */
-	virtual void join(const IdentityAddress &participantAddress) = 0;
+	virtual void join(const std::shared_ptr<Address> &participantAddress) = 0;
 
 	/*
 	 * Find a participant  from  its address.
 	 * @param[in] participantAddress The address to search in the list of participants of the chat room
 	 * @return The participant if found, NULL otherwise.
 	 */
-	virtual std::shared_ptr<Participant> findParticipant(const IdentityAddress &participantAddress) const = 0;
+	virtual std::shared_ptr<Participant> findParticipant(const std::shared_ptr<Address> &participantAddress) const = 0;
 
 	/*
 	 * Get the number of participants in this conference (that is without ourselves).
@@ -436,14 +437,13 @@ public:
 	 *Created. If not set the conference is instanciated with a local focus. In this case conferenceId must be set.
 	 * @param[in] Address of the conference factory (ex: sip:conference-factory@conf.linphone.org).
 	 */
-	virtual void setConferenceFactoryAddress(const Address &address) = 0;
+	virtual void setConferenceFactoryAddress(const std::shared_ptr<Address> &address) = 0;
 
 	/*Set focus address of this conference. If set, the Conference is created as an Adhoc conference from a remote
 	 *conferencing server
 	 * @param[in]  The Address of the conference focus.
 	 **/
-	// virtual void setConferenceAddress (const Address conferenceAddress) = 0;
-	virtual void setConferenceAddress(const ConferenceAddress conferenceAddress) = 0;
+	virtual void setConferenceAddress(const std::shared_ptr<Address> conferenceAddress) = 0;
 
 	/*
 	 * Set the subject of this conference. If not focus,  this operation is only available if the local participant
@@ -464,7 +464,7 @@ public:
 	 *If set this participant is added to the conference
 	 * @param[in]  participantAddress of the conference focus.
 	 */
-	virtual void setMe(const IdentityAddress &participantAddress) = 0;
+	virtual void setMe(const std::shared_ptr<Address> &participantAddress) = 0;
 
 	/*
 	 * Enable audio media type for a conference
@@ -524,7 +524,7 @@ class LINPHONE_PUBLIC ConferenceFactoryInterface {
 	 * @param participants initial list of participants
 	 */
 	std::shared_ptr<ConferenceInterface> &createConference(const std::shared_ptr<ConferenceParamsInterface> &params,
-	                                                       const std::list<IdentityAddress> &participants);
+	                                                       const std::list<std::shared_ptr<Address>> &participants);
 };
 
 std::ostream &operator<<(std::ostream &lhs, ConferenceInterface::State e);
diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h
index d5df082392b672f0f3fbb092b136ba36c55c1737..03ba2941f22d1b8418764c43ed2af1f357da2226 100644
--- a/src/conference/conference-listener.h
+++ b/src/conference/conference-listener.h
@@ -35,16 +35,15 @@ class LINPHONE_PUBLIC ConferenceListener {
 public:
 	virtual ~ConferenceListener() = default;
 
-	virtual void onConferenceCreated(BCTBX_UNUSED(const ConferenceAddress &addr)) {
+	virtual void onConferenceCreated(BCTBX_UNUSED(const std::shared_ptr<Address> &addr)) {
 	}
 	virtual void onConferenceKeywordsChanged(BCTBX_UNUSED(const std::vector<std::string> &keywords)) {
 	}
-	virtual void onConferenceTerminated(BCTBX_UNUSED(const IdentityAddress &addr)) {
+	virtual void onConferenceTerminated(BCTBX_UNUSED(const std::shared_ptr<Address> &addr)) {
 	}
 	virtual void onSecurityEvent(BCTBX_UNUSED(const std::shared_ptr<ConferenceSecurityEvent> &event)) {
 	}
-
-	virtual void onFirstNotifyReceived(BCTBX_UNUSED(const IdentityAddress &addr)) {
+	virtual void onFirstNotifyReceived(BCTBX_UNUSED(const std::shared_ptr<Address> &addr)) {
 	}
 	virtual void onParticipantsCleared() {
 	}
diff --git a/src/conference/conference-params.cpp b/src/conference/conference-params.cpp
index c9745757d49a23d55820bd9b5263d47bc13a7d76..d23672d42cb09885b71674dbf19ea02f7a7a247f 100644
--- a/src/conference/conference-params.cpp
+++ b/src/conference/conference-params.cpp
@@ -37,7 +37,10 @@ ConferenceParams::ConferenceParams(const LinphoneCore *core) {
 		enableVideo(policy->automatically_initiate);
 		setParticipantListType(
 		    static_cast<ParticipantListType>(linphone_core_get_conference_participant_list_type(core)));
-		updateFromAccount(linphone_core_get_default_account(core));
+		const auto defaultAccount = linphone_core_get_default_account(core);
+		if (defaultAccount) {
+			updateFromAccount(Account::toCpp(defaultAccount)->getSharedFromThis());
+		}
 	}
 }
 
@@ -60,33 +63,31 @@ ConferenceParams::ConferenceParams(const ConferenceParams &params) : HybridObjec
 	m_static = params.m_static;
 }
 
-void ConferenceParams::setAccount(LinphoneAccount *a) {
+void ConferenceParams::setAccount(const shared_ptr<Account> &a) {
 	m_account = a;
 	updateFromAccount(m_account);
 }
 
-void ConferenceParams::updateFromAccount(LinphoneAccount *account) { // Update Me and default factory from account.
+void ConferenceParams::updateFromAccount(
+    const shared_ptr<Account> &account) { // Update Me and default factory from account.
 	if (account) {
-		auto account_params = linphone_account_get_params(account);
-		if (account_params) {
-			auto identity = linphone_account_params_get_identity_address(account_params);
-			setMe(identity ? IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(identity)) : IdentityAddress());
+		auto accountParams = account->getAccountParams();
+		if (accountParams) {
+			auto identity = accountParams->getIdentityAddress();
+			if (identity) {
+				setMe(identity);
+			} else {
+				setMe(nullptr);
+			}
 			if (m_useDefaultFactoryAddress) {
-				auto core = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_account_get_core(account));
-				const LinphoneAddress *factory_addr =
-				    Account::toCpp(account)->getAccountParams()->getAudioVideoConferenceFactoryAddress();
-				char *conferenceFactoryAddressString = factory_addr ? linphone_address_as_string(factory_addr) : NULL;
-				const Address conferenceFactoryAddress(L_C_TO_STRING(conferenceFactoryAddressString));
-				m_factoryAddress = Address(conferenceFactoryAddress);
-				if (linphone_core_get_global_state(linphone_account_get_core(account)) != LinphoneGlobalStartup) {
-					ms_message("Update conference parameters from account, factory:%s", conferenceFactoryAddressString);
-				}
-				if (conferenceFactoryAddressString) {
-					ms_free(conferenceFactoryAddressString);
+				auto core = account->getCore();
+				m_factoryAddress = accountParams->getAudioVideoConferenceFactoryAddress();
+				if (m_factoryAddress && (linphone_core_get_global_state(core) != LinphoneGlobalStartup)) {
+					lInfo() << "Update conference parameters from account, factory: " << m_factoryAddress->toString();
 				}
 			}
-		} else ms_message("Update conference parameters from account: no account parameters");
-	} else ms_message("Update conference parameters from account: no account");
+		} else lInfo() << "Update conference parameters from account: no account parameters";
+	} else lInfo() << "Update conference parameters from account: no account";
 }
 
 void ConferenceParams::setUtf8Description(const std::string &description) {
@@ -105,4 +106,7 @@ const std::string ConferenceParams::getUtf8Subject() const {
 	return Utils::localeToUtf8(m_subject);
 };
 
+void ConferenceParams::setConferenceAddress(const std::shared_ptr<Address> conferenceAddress) {
+	m_conferenceAddress = Address::create(conferenceAddress->getUri());
+};
 LINPHONE_END_NAMESPACE
diff --git a/src/conference/conference-params.h b/src/conference/conference-params.h
index cb4702e3f0f9d923f4081d21fdc67167f789ec7a..43962a172c7e5f86cbb87214013a8fa872e63e6f 100644
--- a/src/conference/conference-params.h
+++ b/src/conference/conference-params.h
@@ -31,6 +31,7 @@
 
 LINPHONE_BEGIN_NAMESPACE
 
+class Account;
 namespace MediaConference { // They are in a special namespace because of conflict of generic Conference classes in
 	                        // src/conference/*
 class Conference;
@@ -52,12 +53,12 @@ public:
 		return new ConferenceParams(*this);
 	}
 
-	virtual void setConferenceFactoryAddress(const Address &address) override {
+	virtual void setConferenceFactoryAddress(const std::shared_ptr<Address> &address) override {
 		m_useDefaultFactoryAddress = false;
-		m_factoryAddress = address; // Setting with Address("") means that we want a local conference
+		m_factoryAddress = address; // Setting to nullptr means that we want to host a conference on the local device
 	};
 
-	const Address &getConferenceFactoryAddress() const {
+	const std::shared_ptr<Address> &getConferenceFactoryAddress() const {
 		return m_factoryAddress;
 	};
 
@@ -103,10 +104,8 @@ public:
 		return m_allowOneParticipantConference;
 	}
 
-	virtual void setConferenceAddress(const ConferenceAddress conferenceAddress) override {
-		m_conferenceAddress = conferenceAddress;
-	};
-	const ConferenceAddress &getConferenceAddress() const {
+	virtual void setConferenceAddress(const std::shared_ptr<Address> conferenceAddress) override;
+	const std::shared_ptr<Address> &getConferenceAddress() const {
 		return m_conferenceAddress;
 	};
 
@@ -128,15 +127,15 @@ public:
 		return m_subject;
 	};
 
-	virtual void setMe(const IdentityAddress &participantAddress) override {
-		m_me = participantAddress;
+	virtual void setMe(const std::shared_ptr<Address> &participantAddress) override {
+		m_me = participantAddress ? participantAddress->clone()->toSharedPtr() : nullptr;
 	};
-	const IdentityAddress &getMe() const {
+	const std::shared_ptr<Address> &getMe() const {
 		return m_me;
 	};
 
-	void setAccount(LinphoneAccount *a);
-	LinphoneAccount *getAccount() const {
+	void setAccount(const std::shared_ptr<Account> &a);
+	const std::shared_ptr<Account> &getAccount() const {
 		return m_account;
 	};
 
@@ -169,7 +168,7 @@ public:
 	};
 
 private:
-	void updateFromAccount(LinphoneAccount *account); // Update Me and default factory from account.
+	void updateFromAccount(const std::shared_ptr<Account> &account); // Update Me and default factory from account.
 
 	bool m_enableVideo = false;
 	bool m_enableAudio = false;
@@ -178,15 +177,15 @@ private:
 	bool m_allowOneParticipantConference = false;
 	ParticipantListType m_participantListType = ParticipantListType::Open;
 	JoiningMode m_joinMode = JoiningMode::DialIn;
-	ConferenceAddress m_conferenceAddress = ConferenceAddress();
-	Address m_factoryAddress = Address();
+	std::shared_ptr<Address> m_conferenceAddress = nullptr;
+	std::shared_ptr<Address> m_factoryAddress = nullptr;
 	bool m_useDefaultFactoryAddress = true;
 	std::string m_subject = "";
 	std::string m_description = "";
-	IdentityAddress m_me = IdentityAddress();
+	std::shared_ptr<Address> m_me = nullptr;
 	time_t m_startTime = (time_t)-1;
 	time_t m_endTime = (time_t)-1;
-	LinphoneAccount *m_account = nullptr;
+	std::shared_ptr<Account> m_account = nullptr;
 	bool m_static = false;
 };
 
diff --git a/src/conference/conference-scheduler.cpp b/src/conference/conference-scheduler.cpp
index c15a692ce6bd1256d4b625e7448aa5771e79c08b..6d401347b366943f93a674dd89484cfc500be2c5 100644
--- a/src/conference/conference-scheduler.cpp
+++ b/src/conference/conference-scheduler.cpp
@@ -21,6 +21,7 @@
 #include <bctoolbox/defs.h>
 
 #include "account/account.h"
+#include "c-wrapper/c-wrapper.h"
 #include "chat/chat-message/chat-message-p.h"
 #include "conference-scheduler.h"
 #include "conference/params/call-session-params-p.h"
@@ -86,7 +87,7 @@ void ConferenceScheduler::fillCancelList(const ConferenceInfo::participant_list_
 	mCancelToSend.clear();
 	for (const auto &participant : oldList) {
 		const bool participantFound = (std::find_if(newList.cbegin(), newList.cend(), [&participant](const auto &e) {
-			                               return (e.first == participant.first);
+			                               return (e.first->weakEqual(*participant.first));
 		                               }) != newList.cend());
 		if (!participantFound) {
 			auto sequence = -1;
@@ -133,37 +134,39 @@ void ConferenceScheduler::setInfo(const std::shared_ptr<ConferenceInfo> &info) {
 		}
 	}
 
-	const auto creator = mAccount
-	                         ? Address(*L_GET_CPP_PTR_FROM_C_OBJECT(mAccount->getAccountParams()->getIdentityAddress()))
-	                         : Address(linphone_core_get_identity(getCore()->getCCore()));
-	if (!creator.isValid()) {
+	const auto creator = mAccount ? mAccount->getAccountParams()->getIdentityAddress()
+	                              : Address::create(linphone_core_get_identity(getCore()->getCCore()));
+	if (!creator || !creator->isValid()) {
 		lWarning() << "[Conference Scheduler] [" << this << "] Core address attempting to set conference information!";
 		return;
 	}
 
 	const auto &organizer = clone->getOrganizerAddress();
+	const auto &conferenceAddress = clone->getUri();
 	const auto &participants = clone->getParticipants();
 	const auto participantListEmpty = participants.empty();
 	const bool participantFound = (std::find_if(participants.cbegin(), participants.cend(), [&creator](const auto &p) {
-		                               return (creator.weakEqual(p.first.asAddress()));
+		                               return (creator->weakEqual(*(p.first)));
 	                               }) != participants.cend());
-	if (!creator.weakEqual(organizer.asAddress()) && !participantFound) {
-		lWarning() << "[Conference Scheduler] [" << this << "] Address " << creator
+	if (!creator->weakEqual(*organizer) && !participantFound) {
+		lWarning() << "[Conference Scheduler] [" << this << "] Address " << creator->toString()
 		           << " is trying to modify the conference information but he/she is neither an invited participant "
 		              "nor the organizer ("
-		           << organizer << ") of conference " << clone->getUri();
+		           << organizer << ") of conference "
+		           << (conferenceAddress ? conferenceAddress->toString() : std::string("<unknown>"));
 		setState(State::Error);
 		return;
 	}
 
 	bool isUpdate = false;
 #ifdef HAVE_DB_STORAGE
-	if (clone->getUri().isValid()) {
+	if (conferenceAddress && conferenceAddress->isValid()) {
 		auto &mainDb = getCore()->getPrivate()->mainDb;
-		auto confInfo = mainDb->getConferenceInfoFromURI(clone->getUri());
+		auto confInfo = mainDb->getConferenceInfoFromURI(conferenceAddress);
 		if (confInfo) {
 			lInfo() << "[Conference Scheduler] [" << this
-			        << "] Found matching conference info in database for address [" << clone->getUri() << "]";
+			        << "] Found matching conference info in database for address ["
+			        << (conferenceAddress ? conferenceAddress->toString() : std::string("<unknown>")) << "]";
 			isUpdate = true;
 			setState(State::Updating);
 			clone->updateFrom(confInfo);
@@ -181,7 +184,7 @@ void ConferenceScheduler::setInfo(const std::shared_ptr<ConferenceInfo> &info) {
 
 	if (mConferenceInfo == nullptr && !isUpdate) {
 		setState(State::AllocationPending);
-		if (clone->getUri().isValid()) {
+		if (conferenceAddress && conferenceAddress->isValid()) {
 			// This is a hack for the tester
 			lError() << "[Conference Scheduler] [" << this
 			         << "] This is a hack for liblinphone-tester, you shouldn't see this in production!";
@@ -226,14 +229,14 @@ void ConferenceScheduler::setInfo(const std::shared_ptr<ConferenceInfo> &info) {
 		}
 	}
 
-	std::list<IdentityAddress> invitees;
+	std::list<std::shared_ptr<Address>> invitees;
 	for (const auto &p : mConferenceInfo->getParticipants()) {
 		invitees.push_back(p.first);
 	}
 
 	if (isUpdate) {
 		// Updating an existing conference
-		mSession = getCore()->createOrUpdateConferenceOnServer(conferenceParams, creator, invitees, clone->getUri());
+		mSession = getCore()->createOrUpdateConferenceOnServer(conferenceParams, creator, invitees, conferenceAddress);
 	} else {
 		// Creating conference
 		mSession = getCore()->createConferenceOnServer(conferenceParams, creator, invitees);
@@ -256,14 +259,14 @@ void ConferenceScheduler::setInfo(const std::shared_ptr<ConferenceInfo> &info) {
 
 void ConferenceScheduler::onChatMessageStateChanged(const shared_ptr<ChatMessage> &message, ChatMessage::State state) {
 	shared_ptr<AbstractChatRoom> chatRoom = message->getChatRoom();
-	IdentityAddress participantAddress = message->getRecipientAddress();
+	auto participantAddress = message->getRecipientAddress();
 	if (state == ChatMessage::State::NotDelivered) {              // Message wasn't delivered
 		if (chatRoom->getState() == Conference::State::Created) { // Chat room was created successfully
 			if (chatRoom->getCapabilities() &
 			    ChatRoom::Capabilities::OneToOne) { // Message was sent using a 1-1 chat room
 				lError() << "[Conference Scheduler] [" << this << "] Invitation couldn't be sent to participant ["
-				         << participantAddress << "]";
-				mInvitationsInError.push_back(Address(participantAddress.asAddress()));
+				         << *participantAddress << "]";
+				mInvitationsInError.push_back(participantAddress);
 			} else { // Message was sent using a group chat room
 				lError() << "[Conference Scheduler] [" << this
 				         << "] At least some participants of the chat room haven't received the invitation!";
@@ -272,28 +275,28 @@ void ConferenceScheduler::onChatMessageStateChanged(const shared_ptr<ChatMessage
 				for (auto &participant : message->getParticipantsByImdnState(ChatMessage::State::NotDelivered)) {
 					participantAddress = participant.getParticipant()->getAddress();
 					lError() << "[Conference Scheduler] [" << this << "] Invitation couldn't be sent to participant ["
-					         << participantAddress << "]";
-					mInvitationsInError.push_back(Address(participantAddress.asAddress()));
+					         << *participantAddress << "]";
+					mInvitationsInError.push_back(participantAddress);
 				}
 			}
 		} else { // Chat room wasn't created
 			if (chatRoom->getCapabilities() &
 			    ChatRoom::Capabilities::OneToOne) { // Message was sent using a 1-1 chat room
 				lError() << "[Conference Scheduler] [" << this << "] Invitation couldn't be sent to participant ["
-				         << participantAddress << "]";
-				mInvitationsInError.push_back(Address(participantAddress.asAddress()));
+				         << *participantAddress << "]";
+				mInvitationsInError.push_back(participantAddress);
 			} else { // Message was sent using a group chat room
 				lError() << "[Conference Scheduler] [" << this
 				         << "] Chat room wasn't created, so no one received the invitation!";
 				for (auto &participant : mInvitationsToSend) {
-					mInvitationsInError.push_back(Address(participant.asAddress()));
+					mInvitationsInError.push_back(participant);
 				}
 			}
 		}
 	} else if (state == ChatMessage::State::Delivered || state == ChatMessage::State::DeliveredToUser ||
 	           state == ChatMessage::State::Displayed) { // Message was delivered (first received state can be any of
 		                                                 // those 3)
-		lInfo() << "[Conference Scheduler] [" << this << "] Invitation to participant [" << participantAddress
+		lInfo() << "[Conference Scheduler] [" << this << "] Invitation to participant [" << *participantAddress
 		        << "] was delivered (" << state << ")";
 		mInvitationsSent += 1;
 		message->removeListener(getSharedFromThis());
@@ -302,14 +305,15 @@ void ConferenceScheduler::onChatMessageStateChanged(const shared_ptr<ChatMessage
 	}
 
 	if (mInvitationsSent + mInvitationsInError.size() == mInvitationsToSend.size()) {
-		linphone_conference_scheduler_notify_invitations_sent(toC(),
-		                                                      L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(mInvitationsInError));
+		ListHolder<Address> erroredInvitations;
+		erroredInvitations.mList = mInvitationsInError;
+		linphone_conference_scheduler_notify_invitations_sent(toC(), erroredInvitations.getCList());
 	}
 }
 
-void ConferenceScheduler::setConferenceAddress(const ConferenceAddress &conferenceAddress) {
+void ConferenceScheduler::setConferenceAddress(const std::shared_ptr<Address> &conferenceAddress) {
 	if (mConferenceInfo == nullptr) {
-		lError() << "[Conference Scheduler] [" << this << "] Can't update conference address " << conferenceAddress
+		lError() << "[Conference Scheduler] [" << this << "] Can't update conference address " << *conferenceAddress
 		         << " on null conference info";
 		setState(State::Error);
 		return;
@@ -320,7 +324,7 @@ void ConferenceScheduler::setConferenceAddress(const ConferenceAddress &conferen
 #ifdef HAVE_DB_STORAGE
 	auto &mainDb = getCore()->getPrivate()->mainDb;
 	if (mainDb) {
-		lInfo() << "[Conference Scheduler] [" << this << "] Conference address " << conferenceAddress
+		lInfo() << "[Conference Scheduler] [" << this << "] Conference address " << *conferenceAddress
 		        << " is known, inserting conference info in database";
 		mainDb->insertConferenceInfo(mConferenceInfo);
 	}
@@ -330,29 +334,30 @@ void ConferenceScheduler::setConferenceAddress(const ConferenceAddress &conferen
 }
 
 void ConferenceScheduler::onCallSessionSetTerminated(const shared_ptr<CallSession> &session) {
-	const Address *remoteAddress = session->getRemoteContactAddress();
+	const std::shared_ptr<Address> remoteAddress = session->getRemoteContactAddress();
 	if (remoteAddress == nullptr) {
 		auto conferenceAddress = mConferenceInfo->getUri();
 		lError() << "[Conference Scheduler] [" << this
 		         << "] The session to update the conference information of conference "
-		         << (conferenceAddress.isValid() ? conferenceAddress.asString() : std::string("<unknown-address>"))
+		         << (conferenceAddress && conferenceAddress->isValid() ? conferenceAddress->toString()
+		                                                               : std::string("<unknown-address>"))
 		         << " did not succesfully establish hence it is likely that the request wasn't taken into account by "
 		            "the server";
 		setState(State::Error);
 	} else if (getState() != State::Error) {
 		// Do not try to call inpromptu conference if a participant updates its informations
 		if ((getState() == State::AllocationPending) && (session->getParams()->getPrivate()->getStartTime() < 0)) {
-			lInfo() << "Automatically rejoining conference " << *remoteAddress;
+			lInfo() << "Automatically rejoining conference " << remoteAddress->toString();
 			auto new_params = linphone_core_create_call_params(getCore()->getCCore(), nullptr);
 			// Participant with the focus call is admin
 			L_GET_CPP_PTR_FROM_C_OBJECT(new_params)->addCustomContactParameter("admin", Utils::toString(true));
-			std::list<IdentityAddress> addressesList;
+			std::list<std::shared_ptr<Address>> addressesList;
 			for (const auto &p : mConferenceInfo->getParticipants()) {
 				addressesList.push_back(p.first);
 			}
 
-			addressesList.sort();
-			addressesList.unique();
+			addressesList.sort([](const auto &addr1, const auto &addr2) { return *addr1 < *addr2; });
+			addressesList.unique([](const auto &addr1, const auto &addr2) { return addr1->weakEqual(*addr2); });
 
 			if (!addressesList.empty()) {
 				Content content;
@@ -368,14 +373,14 @@ void ConferenceScheduler::onCallSessionSetTerminated(const shared_ptr<CallSessio
 			linphone_call_params_enable_video(
 			    new_params, static_pointer_cast<MediaSession>(session)->getMediaParams()->videoEnabled());
 
-			linphone_core_invite_address_with_params_2(getCore()->getCCore(), L_GET_C_BACK_PTR(remoteAddress),
-			                                           new_params, L_STRING_TO_C(mConferenceInfo->getSubject()), NULL);
+			linphone_core_invite_address_with_params_2(getCore()->getCCore(), remoteAddress->toC(), new_params,
+			                                           L_STRING_TO_C(mConferenceInfo->getSubject()), NULL);
 			linphone_call_params_unref(new_params);
 		}
 
-		auto conferenceAddress = ConferenceAddress(*remoteAddress);
+		auto conferenceAddress = remoteAddress;
 		lInfo() << "[Conference Scheduler] [" << this
-		        << "] Conference has been succesfully created: " << conferenceAddress;
+		        << "] Conference has been succesfully created: " << *conferenceAddress;
 		setConferenceAddress(conferenceAddress);
 	}
 }
@@ -396,13 +401,14 @@ void ConferenceScheduler::onCallSessionStateChanged(const shared_ptr<CallSession
 }
 
 shared_ptr<ChatMessage> ConferenceScheduler::createInvitationChatMessage(shared_ptr<AbstractChatRoom> chatRoom,
-                                                                         const IdentityAddress participant,
+                                                                         const std::shared_ptr<Address> participant,
                                                                          bool cancel) {
 	shared_ptr<LinphonePrivate::ChatMessage> message;
 	int sequence = -1;
-	if (participant.isValid()) {
-		const auto cancelParticipant = std::find_if(mCancelToSend.cbegin(), mCancelToSend.cend(),
-		                                            [&participant](const auto &p) { return (p.first == participant); });
+	if (participant && participant->isValid()) {
+		const auto cancelParticipant =
+		    std::find_if(mCancelToSend.cbegin(), mCancelToSend.cend(),
+		                 [&participant](const auto &p) { return (participant->weakEqual(*p.first)); });
 		if (cancelParticipant == mCancelToSend.cend()) {
 			const auto participantSequence =
 			    mConferenceInfo->getParticipantParam(participant, ConferenceInfo::sequenceParam);
@@ -447,23 +453,22 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 		}
 	}
 
-	const auto sender = mAccount
-	                        ? Address(*L_GET_CPP_PTR_FROM_C_OBJECT(mAccount->getAccountParams()->getIdentityAddress()))
-	                        : Address(linphone_core_get_identity(getCore()->getCCore()));
-	if (!sender.isValid()) {
+	const auto sender = mAccount ? mAccount->getAccountParams()->getIdentityAddress()
+	                             : Address::create(linphone_core_get_identity(getCore()->getCCore()));
+	if (!sender || !sender->isValid()) {
 		lWarning() << "[Conference Scheduler] [" << this << "] Core address attempting to send invitation isn't valid!";
 		return;
 	}
 
 	const auto &participants = mConferenceInfo->getParticipants();
 	const bool participantFound = (std::find_if(participants.cbegin(), participants.cend(), [&sender](const auto &p) {
-		                               return (p.first == sender);
+		                               return (sender->weakEqual(*p.first));
 	                               }) != participants.cend());
 	const auto &organizer = mConferenceInfo->getOrganizerAddress();
-	if (!sender.weakEqual(organizer.asAddress()) && !participantFound) {
+	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 " << *mConferenceInfo->getUri();
 		return;
 	}
 
@@ -478,7 +483,7 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 		return;
 	}
 
-	std::list<IdentityAddress> invitees;
+	std::list<std::shared_ptr<Address>> invitees;
 	for (const auto &p : participants) {
 		invitees.push_back(p.first);
 	}
@@ -488,8 +493,8 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 
 	mInvitationsToSend.clear();
 	for (auto participant : invitees) {
-		if (!sender.weakEqual(participant.asAddress())) {
-			mInvitationsToSend.push_back(Address(participant.asAddress()));
+		if (!sender->weakEqual(*participant)) {
+			mInvitationsToSend.push_back(participant);
 		} else {
 			lInfo() << "[Conference Scheduler] [" << this << "] Removed conference participant [" << participant
 			        << "] from chat room participants as it is ourselves";
@@ -504,13 +509,18 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 	const int newOrganizerSequence = (organizerSequence.empty()) ? 0 : std::atoi(organizerSequence.c_str()) + 1;
 	mConferenceInfo->addOrganizerParam(ConferenceInfo::sequenceParam, std::to_string(newOrganizerSequence));
 
-	if (!sender.weakEqual(organizer.asAddress())) {
+	if (!sender->weakEqual(*organizer)) {
 		const bool organizerFound =
 		    (std::find(mInvitationsToSend.cbegin(), mInvitationsToSend.cend(), organizer) != mInvitationsToSend.cend());
 		if (!organizerFound) {
 			lInfo() << "[Conference Scheduler] [" << this << "] Organizer [" << organizer
 			        << "] not found in conference participants, adding it to chat room participants";
-			mInvitationsToSend.push_back(Address(organizer.asAddress()));
+			mInvitationsToSend.push_back(organizer);
+		}
+		const bool organizerInInviteesFound =
+		    (std::find(invitees.cbegin(), invitees.cend(), organizer) != invitees.cend());
+		if (!organizerInInviteesFound) {
+			invitees.push_back(organizer);
 		}
 	}
 
@@ -518,26 +528,26 @@ void ConferenceScheduler::sendInvitations(shared_ptr<ChatRoomParams> chatRoomPar
 	mInvitationsSent = 0;
 
 	// Sending the ICS once for each participant in a separated chat room each time.
-	for (auto participant : mInvitationsToSend) {
-		list<IdentityAddress> participantList;
+	for (auto participant : invitees) {
+		list<std::shared_ptr<Address>> participantList;
 		participantList.push_back(participant);
 		shared_ptr<AbstractChatRoom> chatRoom =
-		    getCore()->getPrivate()->searchChatRoom(chatRoomParams, sender, IdentityAddress(), participantList);
+		    getCore()->getPrivate()->searchChatRoom(chatRoomParams, sender, nullptr, participantList);
 
 		if (!chatRoom) {
-			lInfo() << "[Conference Scheduler] [" << this << "] Existing chat room between [" << sender << "] and ["
-			        << participant << "] wasn't found, creating it.";
+			lInfo() << "[Conference Scheduler] [" << this << "] Existing chat room between [" << *sender << "] and ["
+			        << *participant << "] wasn't found, creating it.";
 			chatRoom = getCore()->getPrivate()->createChatRoom(chatRoomParams, sender, participantList);
 		} else {
 			lInfo() << "[Conference Scheduler] [" << this << "] Found existing chat room ["
-			        << chatRoom->getPeerAddress() << "] between [" << sender << "] and [" << participant
+			        << *chatRoom->getPeerAddress() << "] between [" << *sender << "] and [" << *participant
 			        << "], using it";
 		}
 
 		if (!chatRoom) {
 			lError() << "[Conference Scheduler] [" << this << "] Couldn't find nor create a chat room between ["
-			         << sender << "] and [" << participant << "]";
-			mInvitationsInError.push_back(Address(participant.asAddress()));
+			         << *sender << "] and [" << *participant << "]";
+			mInvitationsInError.push_back(participant);
 			continue;
 		}
 
diff --git a/src/conference/conference-scheduler.h b/src/conference/conference-scheduler.h
index ff45833ad4ac5b1f680f3506535b7b5134828266..b3365820a47457d5f0564c28816afbee2924e899 100644
--- a/src/conference/conference-scheduler.h
+++ b/src/conference/conference-scheduler.h
@@ -69,7 +69,7 @@ public:
 	void cancelConference(const std::shared_ptr<ConferenceInfo> &info);
 	void setInfo(const std::shared_ptr<ConferenceInfo> &info);
 
-	void setConferenceAddress(const ConferenceAddress &conferenceAddress);
+	void setConferenceAddress(const std::shared_ptr<Address> &conferenceAddress);
 
 	void sendInvitations(std::shared_ptr<ChatRoomParams> chatRoomParams);
 
@@ -81,7 +81,7 @@ private:
 	std::string stateToString(State state);
 
 	std::shared_ptr<ChatMessage> createInvitationChatMessage(std::shared_ptr<AbstractChatRoom> chatRoom,
-	                                                         const IdentityAddress participant,
+	                                                         const std::shared_ptr<Address> participant,
 	                                                         bool cancel);
 	void fillCancelList(const ConferenceInfo::participant_list_t &oldList,
 	                    const ConferenceInfo::participant_list_t &newList);
@@ -92,9 +92,9 @@ private:
 	std::shared_ptr<Account> mAccount = nullptr;
 
 	unsigned long mInvitationsSent = 0;
-	std::list<IdentityAddress> mInvitationsToSend;
-	std::map<IdentityAddress, int> mCancelToSend;
-	std::list<Address> mInvitationsInError;
+	std::list<std::shared_ptr<Address>> mInvitationsToSend;
+	std::map<std::shared_ptr<Address>, int> mCancelToSend;
+	std::list<std::shared_ptr<Address>> mInvitationsInError;
 };
 
 class ConferenceSchedulerCbs : public bellesip::HybridObject<LinphoneConferenceSchedulerCbs, ConferenceSchedulerCbs>,
diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp
index 7a1fcbad85933f80b76baed0b2e820f87fb5593b..f571ab225c286b8a10a664b10b823674c94f4af8 100644
--- a/src/conference/conference.cpp
+++ b/src/conference/conference.cpp
@@ -47,7 +47,7 @@ using namespace std;
 LINPHONE_BEGIN_NAMESPACE
 
 Conference::Conference(const shared_ptr<Core> &core,
-                       const IdentityAddress &myAddress,
+                       const std::shared_ptr<Address> &myAddress,
                        CallSessionListener *listener,
                        const std::shared_ptr<ConferenceParams> params)
     : CoreAccessor(core) {
@@ -87,16 +87,18 @@ bool Conference::addParticipant(BCTBX_UNUSED(std::shared_ptr<Call> call)) {
 	return false;
 }
 
-bool Conference::addParticipant(const IdentityAddress &participantAddress) {
+bool Conference::addParticipant(const std::shared_ptr<Address> &participantAddress) {
 	shared_ptr<Participant> participant = findParticipant(participantAddress);
 	if (participant) {
-		lWarning() << "Not adding participant '" << participantAddress.asString()
+		lWarning() << "Not adding participant '" << participantAddress->toString()
 		           << "' because it is already a participant of the Conference";
 		return false;
 	}
 	participant = Participant::create(this, participantAddress);
 	participant->createSession(*this, nullptr, (confParams->chatEnabled() == false), listener);
-	participant->setFocus(participantAddress == getConferenceAddress());
+	const auto confAddr = getConferenceAddress();
+	bool isFocus = participantAddress && confAddr && (*participantAddress == *confAddr);
+	participant->setFocus(isFocus);
 	participant->setPreserveSession(false);
 	participants.push_back(participant);
 	if (!activeParticipant) activeParticipant = participant;
@@ -107,10 +109,10 @@ const std::shared_ptr<CallSession> Conference::getMainSession() const {
 	return me->getSession();
 }
 
-bool Conference::addParticipants(const std::list<IdentityAddress> &addresses) {
-	list<IdentityAddress> sortedAddresses(addresses);
-	sortedAddresses.sort();
-	sortedAddresses.unique();
+bool Conference::addParticipants(const std::list<std::shared_ptr<Address>> &addresses) {
+	list<std::shared_ptr<Address>> sortedAddresses(addresses);
+	sortedAddresses.sort([](const auto &addr1, const auto &addr2) { return *addr1 < *addr2; });
+	sortedAddresses.unique([](const auto &addr1, const auto &addr2) { return addr1->weakEqual(*addr2); });
 
 	bool soFarSoGood = true;
 	for (const auto &address : sortedAddresses)
@@ -170,11 +172,11 @@ void Conference::setLayout(const ConferenceLayout layout) {
 	}
 }
 
-const ConferenceAddress &Conference::getConferenceAddress() const {
+const std::shared_ptr<Address> &Conference::getConferenceAddress() const {
 	return confParams->getConferenceAddress();
 }
 
-void Conference::setConferenceAddress(const ConferenceAddress &conferenceAddress) {
+void Conference::setConferenceAddress(const std::shared_ptr<Address> &conferenceAddress) {
 	confParams->setConferenceAddress(conferenceAddress);
 }
 
@@ -220,7 +222,7 @@ const string &Conference::getUsername() const {
 	return mUsername;
 }
 
-void Conference::join(BCTBX_UNUSED(const IdentityAddress &participantAddress)) {
+void Conference::join(BCTBX_UNUSED(const std::shared_ptr<Address> &participantAddress)) {
 }
 
 void Conference::join() {
@@ -250,7 +252,7 @@ bool Conference::update(const ConferenceParamsInterface &newParameters) {
 
 bool Conference::removeParticipant(const shared_ptr<Participant> &participant) {
 	for (const auto &p : participants) {
-		if (participant->getAddress() == p->getAddress()) {
+		if (*participant->getAddress() == *p->getAddress()) {
 			participants.remove(p);
 			return true;
 		}
@@ -370,18 +372,16 @@ void Conference::setUsername(const string &username) {
 
 // -----------------------------------------------------------------------------
 
-shared_ptr<Participant> Conference::findParticipant(const IdentityAddress &addr) const {
-
-	IdentityAddress searchedAddr(addr);
-	searchedAddr.setGruu("");
+shared_ptr<Participant> Conference::findParticipant(const std::shared_ptr<Address> &addr) const {
 	for (const auto &participant : participants) {
-		if (participant->getAddress() == searchedAddr) {
+		if (participant->getAddress()->weakEqual(*addr)) {
 			return participant;
 		}
 	}
 
-	lWarning() << "Unable to find participant in conference " << getConferenceAddress() << " (" << this
-	           << ") with address " << addr.asString();
+	lWarning() << "Unable to find participant in conference "
+	           << (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<unknown address>"))
+	           << " (" << this << ") with address " << addr->toString();
 	return nullptr;
 }
 
@@ -393,16 +393,17 @@ shared_ptr<ParticipantDevice> Conference::findParticipantDeviceByLabel(const std
 		}
 	}
 
-	lDebug() << "Unable to find participant device in conference " << getConferenceAddress() << " with label " << label;
+	lDebug() << "Unable to find participant device in conference "
+	         << (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<unknown address>"))
+	         << " with label " << label;
 
 	return nullptr;
 }
 
-shared_ptr<ParticipantDevice> Conference::findParticipantDevice(const IdentityAddress &pAddr,
-                                                                const IdentityAddress &dAddr) const {
-
+shared_ptr<ParticipantDevice> Conference::findParticipantDevice(const std::shared_ptr<Address> &pAddr,
+                                                                const std::shared_ptr<Address> &dAddr) const {
 	for (const auto &participant : participants) {
-		if (pAddr == participant->getAddress()) {
+		if (pAddr->weakEqual(*participant->getAddress())) {
 			auto device = participant->findDevice(dAddr, false);
 			if (device) {
 				return device;
@@ -410,8 +411,9 @@ shared_ptr<ParticipantDevice> Conference::findParticipantDevice(const IdentityAd
 		}
 	}
 
-	lDebug() << "Unable to find participant device in conference " << getConferenceAddress() << " with device address "
-	         << dAddr << " belonging to participant " << pAddr;
+	lDebug() << "Unable to find participant device in conference "
+	         << (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<unknown-address>"))
+	         << " with device address " << dAddr->toString() << " belonging to participant " << pAddr->toString();
 
 	return nullptr;
 }
@@ -425,8 +427,9 @@ shared_ptr<ParticipantDevice> Conference::findParticipantDevice(const shared_ptr
 		}
 	}
 
-	lDebug() << "Unable to find participant device in conference " << getConferenceAddress() << " with call session "
-	         << session;
+	lDebug() << "Unable to find participant device in conference "
+	         << (getConferenceAddress() ? getConferenceAddress()->toString() : std::string("<unknown-address>"))
+	         << " with call session " << session;
 
 	return nullptr;
 }
@@ -445,11 +448,9 @@ std::map<ConferenceMediaCapabilities, bool> Conference::getMediaCapabilities() c
 
 // -----------------------------------------------------------------------------
 
-bool Conference::isMe(const IdentityAddress &addr) const {
-	IdentityAddress cleanedAddr(addr);
-	cleanedAddr.setGruu("");
-	IdentityAddress cleanedMeAddr(me->getAddress());
-	cleanedMeAddr.setGruu("");
+bool Conference::isMe(const std::shared_ptr<Address> &addr) const {
+	Address cleanedAddr = addr->getUriWithoutGruu();
+	Address cleanedMeAddr = me->getAddress()->getUriWithoutGruu();
 	return cleanedMeAddr == cleanedAddr;
 }
 
@@ -685,8 +686,8 @@ std::shared_ptr<ConferenceInfo> Conference::createOrGetConferenceInfo() const {
 }
 
 std::shared_ptr<ConferenceInfo>
-Conference::createConferenceInfo(const IdentityAddress &organizer,
-                                 const std::list<IdentityAddress> invitedParticipants) const {
+Conference::createConferenceInfo(const std::shared_ptr<Address> &organizer,
+                                 const std::list<std::shared_ptr<Address>> invitedParticipants) const {
 	std::shared_ptr<ConferenceInfo> info = ConferenceInfo::create();
 	info->setOrganizer(organizer);
 	for (const auto &participant : invitedParticipants) {
@@ -694,7 +695,7 @@ Conference::createConferenceInfo(const IdentityAddress &organizer,
 	}
 
 	const auto &conferenceAddress = getConferenceAddress();
-	if (conferenceAddress.isValid()) {
+	if (conferenceAddress && conferenceAddress->isValid()) {
 		info->setUri(conferenceAddress);
 	}
 
@@ -724,7 +725,7 @@ void Conference::updateSubjectInConferenceInfo(const std::string &subject) const
 			// contact address of the call
 			auto &mainDb = getCore()->getPrivate()->mainDb;
 			if (mainDb) {
-				lInfo() << "Updating conference information of conference " << getConferenceAddress()
+				lInfo() << "Updating conference information of conference " << *getConferenceAddress()
 				        << " because its subject has been changed to " << subject;
 				mainDb->insertConferenceInfo(info);
 			}
@@ -732,7 +733,7 @@ void Conference::updateSubjectInConferenceInfo(const std::string &subject) const
 	}
 }
 
-void Conference::updateParticipantsInConferenceInfo(const IdentityAddress &participantAddress) const {
+void Conference::updateParticipantsInConferenceInfo(const std::shared_ptr<Address> &participantAddress) const {
 	if ((getState() == ConferenceInterface::State::CreationPending) ||
 	    (getState() == ConferenceInterface::State::Created)) {
 		auto info = createOrGetConferenceInfo();
@@ -740,7 +741,7 @@ void Conference::updateParticipantsInConferenceInfo(const IdentityAddress &parti
 			const auto &currentParticipants = info->getParticipants();
 			const auto participantAddressIt =
 			    std::find_if(currentParticipants.begin(), currentParticipants.end(),
-			                 [&participantAddress](const auto &p) { return (p.first == participantAddress); });
+			                 [&participantAddress](const auto &p) { return (*p.first == *participantAddress); });
 			if (participantAddressIt == currentParticipants.end()) {
 				info->addParticipant(participantAddress);
 
@@ -748,8 +749,8 @@ void Conference::updateParticipantsInConferenceInfo(const IdentityAddress &parti
 				// 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";
+					lInfo() << "Updating conference information of conference " << *getConferenceAddress()
+					        << " because participant " << *participantAddress << " has been added";
 					mainDb->insertConferenceInfo(info);
 				}
 			}
diff --git a/src/conference/conference.h b/src/conference/conference.h
index cd317c9be9397ecf0c48bd017efdc73735d24c07..58d36212fb5b494f3cdff2b073a4242d5f1c9514 100644
--- a/src/conference/conference.h
+++ b/src/conference/conference.h
@@ -71,8 +71,8 @@ public:
 	std::shared_ptr<Participant> getActiveParticipant() const;
 
 	std::shared_ptr<ParticipantDevice> findParticipantDevice(const std::shared_ptr<const CallSession> &session) const;
-	std::shared_ptr<ParticipantDevice> findParticipantDevice(const IdentityAddress &pAddr,
-	                                                         const IdentityAddress &dAddr) const;
+	std::shared_ptr<ParticipantDevice> findParticipantDevice(const std::shared_ptr<Address> &pAddr,
+	                                                         const std::shared_ptr<Address> &dAddr) const;
 	std::shared_ptr<ParticipantDevice> findParticipantDeviceByLabel(const std::string &label) const;
 	std::shared_ptr<ParticipantDevice> getActiveSpeakerParticipantDevice() const;
 
@@ -85,18 +85,18 @@ public:
 	virtual bool addParticipants(const std::list<std::shared_ptr<LinphonePrivate::Call>> &call);
 
 	/* ConferenceInterface */
-	std::shared_ptr<Participant> findParticipant(const IdentityAddress &addr) const override;
+	std::shared_ptr<Participant> findParticipant(const std::shared_ptr<Address> &addr) const override;
 	std::shared_ptr<Participant> getMe() const override;
-	bool isMe(const IdentityAddress &addr) const;
+	bool isMe(const std::shared_ptr<Address> &addr) const;
 	bool addParticipant(std::shared_ptr<Call> call) override;
-	bool addParticipant(const IdentityAddress &participantAddress) override;
-	bool addParticipants(const std::list<IdentityAddress> &addresses) override;
+	bool addParticipant(const std::shared_ptr<Address> &participantAddress) override;
+	bool addParticipants(const std::list<std::shared_ptr<Address>> &addresses) override;
 	int getParticipantCount() const override;
 	const std::list<std::shared_ptr<Participant>> &getParticipants() const override;
-	const std::list<std::shared_ptr<ParticipantDevice>> getParticipantDevices() const override;
+	virtual const std::list<std::shared_ptr<ParticipantDevice>> getParticipantDevices() const override;
 	const std::string &getSubject() const override;
 	const std::string getUtf8Subject() const override;
-	void join(const IdentityAddress &participantAddress) override;
+	void join(const std::shared_ptr<Address> &participantAddress) override;
 	void leave() override;
 	bool removeParticipant(const std::shared_ptr<Participant> &participant) override;
 	bool removeParticipants(const std::list<std::shared_ptr<Participant>> &participants) override;
@@ -108,8 +108,8 @@ public:
 		return *confParams;
 	}
 
-	virtual const ConferenceAddress &getConferenceAddress() const override;
-	void setConferenceAddress(const ConferenceAddress &conferenceAddress);
+	virtual const std::shared_ptr<Address> &getConferenceAddress() const override;
+	void setConferenceAddress(const std::shared_ptr<Address> &conferenceAddress);
 
 	void setParticipantAdminStatus(const std::shared_ptr<Participant> &participant, bool isAdmin) override;
 	void setSubject(const std::string &subject) override;
@@ -203,12 +203,12 @@ public:
 
 #ifdef HAVE_DB_STORAGE
 	void updateSubjectInConferenceInfo(const std::string &subject) const;
-	void updateParticipantsInConferenceInfo(const IdentityAddress &participantAddress) const;
+	void updateParticipantsInConferenceInfo(const std::shared_ptr<Address> &participantAddress) const;
 #endif // HAVE_DB_STORAGE
 
 protected:
 	explicit Conference(const std::shared_ptr<Core> &core,
-	                    const IdentityAddress &myAddress,
+	                    const std::shared_ptr<Address> &myAddress,
 	                    CallSessionListener *listener,
 	                    const std::shared_ptr<ConferenceParams> params);
 
@@ -246,7 +246,8 @@ protected:
 
 	virtual std::shared_ptr<ConferenceInfo> createOrGetConferenceInfo() const;
 	virtual std::shared_ptr<ConferenceInfo>
-	createConferenceInfo(const IdentityAddress &organizer, const std::list<IdentityAddress> invitedParticipants) const;
+	createConferenceInfo(const std::shared_ptr<Address> &organizer,
+	                     const std::list<std::shared_ptr<Address>> invitedParticipants) const;
 
 private:
 	L_DISABLE_COPY(Conference);
diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp
index 43879ebfa332cd55aff63421e04490f1ec781c08..0fa2d7d7d8567ff8164da5586aa5dd8080a84b0f 100644
--- a/src/conference/handlers/local-conference-event-handler.cpp
+++ b/src/conference/handlers/local-conference-event-handler.cpp
@@ -101,7 +101,7 @@ Content LocalConferenceEventHandler::createNotifyFullState(const shared_ptr<Even
 		}
 	}
 
-	ConferenceAddress conferenceAddress = conf->getConferenceAddress();
+	std::shared_ptr<Address> conferenceAddress = conf->getConferenceAddress();
 	ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 	// Enquire whether this conference belongs to a server group chat room
 	shared_ptr<Core> core = conf->getCore();
@@ -109,7 +109,7 @@ Content LocalConferenceEventHandler::createNotifyFullState(const shared_ptr<Even
 	const bool oneToOne = chatRoom ? !!(chatRoom->getCapabilities() & AbstractChatRoom::Capabilities::OneToOne) : false;
 	const bool ephemerable =
 	    chatRoom ? !!(chatRoom->getCapabilities() & AbstractChatRoom::Capabilities::Ephemeral) : false;
-	string entity = conferenceAddress.asString();
+	string entity = conferenceAddress->asStringUriOnly();
 	string subject = conf->getUtf8Subject();
 	ConferenceType confInfo = ConferenceType(entity);
 	ConferenceDescriptionType confDescr = ConferenceDescriptionType();
@@ -178,12 +178,12 @@ Content LocalConferenceEventHandler::createNotifyFullState(const shared_ptr<Even
 		UserType::EndpointSequence endpoints;
 		user.setRoles(roles);
 		user.setEndpoint(endpoints);
-		user.setEntity(participant->getAddress().asString());
+		user.setEntity(participant->getAddress()->asStringUriOnly());
 		user.getRoles()->getEntry().push_back(participant->isAdmin() ? "admin" : "participant");
 		user.setState(StateType::full);
 
 		for (const auto &device : participant->getDevices()) {
-			const string &gruu = device->getAddress().asString();
+			const string &gruu = device->getAddress()->asStringUriOnly();
 			EndpointType endpoint = EndpointType();
 			endpoint.setEntity(gruu);
 			const string &displayName = device->getName();
@@ -396,52 +396,52 @@ Content LocalConferenceEventHandler::createNotifyMultipart(int notifyId) {
 			case EventLog::Type::ConferenceParticipantAdded: {
 				shared_ptr<ConferenceParticipantEvent> addedEvent =
 				    static_pointer_cast<ConferenceParticipantEvent>(eventLog);
-				const Address &participantAddress = addedEvent->getParticipantAddress().asAddress();
+				const std::shared_ptr<Address> &participantAddress = addedEvent->getParticipantAddress();
 				body = createNotifyParticipantAdded(participantAddress);
 			} break;
 
 			case EventLog::Type::ConferenceParticipantRemoved: {
 				shared_ptr<ConferenceParticipantEvent> removedEvent =
 				    static_pointer_cast<ConferenceParticipantEvent>(eventLog);
-				const Address &participantAddress = removedEvent->getParticipantAddress().asAddress();
+				const std::shared_ptr<Address> &participantAddress = removedEvent->getParticipantAddress();
 				body = createNotifyParticipantRemoved(participantAddress);
 			} break;
 
 			case EventLog::Type::ConferenceParticipantSetAdmin: {
 				shared_ptr<ConferenceParticipantEvent> setAdminEvent =
 				    static_pointer_cast<ConferenceParticipantEvent>(eventLog);
-				const Address &participantAddress = setAdminEvent->getParticipantAddress().asAddress();
+				const std::shared_ptr<Address> &participantAddress = setAdminEvent->getParticipantAddress();
 				body = createNotifyParticipantAdminStatusChanged(participantAddress, true);
 			} break;
 
 			case EventLog::Type::ConferenceParticipantUnsetAdmin: {
 				shared_ptr<ConferenceParticipantEvent> unsetAdminEvent =
 				    static_pointer_cast<ConferenceParticipantEvent>(eventLog);
-				const Address &participantAddress = unsetAdminEvent->getParticipantAddress().asAddress();
+				const std::shared_ptr<Address> &participantAddress = unsetAdminEvent->getParticipantAddress();
 				body = createNotifyParticipantAdminStatusChanged(participantAddress, false);
 			} break;
 
 			case EventLog::Type::ConferenceParticipantDeviceAdded: {
 				shared_ptr<ConferenceParticipantDeviceEvent> deviceAddedEvent =
 				    static_pointer_cast<ConferenceParticipantDeviceEvent>(eventLog);
-				const Address &participantAddress = deviceAddedEvent->getParticipantAddress().asAddress();
-				const Address &deviceAddress = deviceAddedEvent->getDeviceAddress().asAddress();
+				const std::shared_ptr<Address> &participantAddress = deviceAddedEvent->getParticipantAddress();
+				const std::shared_ptr<Address> &deviceAddress = deviceAddedEvent->getDeviceAddress();
 				body = createNotifyParticipantDeviceAdded(participantAddress, deviceAddress);
 			} break;
 
 			case EventLog::Type::ConferenceParticipantDeviceRemoved: {
 				shared_ptr<ConferenceParticipantDeviceEvent> deviceRemovedEvent =
 				    static_pointer_cast<ConferenceParticipantDeviceEvent>(eventLog);
-				const Address &participantAddress = deviceRemovedEvent->getParticipantAddress().asAddress();
-				const Address &deviceAddress = deviceRemovedEvent->getDeviceAddress().asAddress();
+				const std::shared_ptr<Address> &participantAddress = deviceRemovedEvent->getParticipantAddress();
+				const std::shared_ptr<Address> &deviceAddress = deviceRemovedEvent->getDeviceAddress();
 				body = createNotifyParticipantDeviceRemoved(participantAddress, deviceAddress);
 			} break;
 
 			case EventLog::Type::ConferenceParticipantDeviceStatusChanged: {
 				shared_ptr<ConferenceParticipantDeviceEvent> deviceStatusChangedEvent =
 				    static_pointer_cast<ConferenceParticipantDeviceEvent>(eventLog);
-				const Address &participantAddress = deviceStatusChangedEvent->getParticipantAddress().asAddress();
-				const Address &deviceAddress = deviceStatusChangedEvent->getDeviceAddress().asAddress();
+				const std::shared_ptr<Address> &participantAddress = deviceStatusChangedEvent->getParticipantAddress();
+				const std::shared_ptr<Address> &deviceAddress = deviceStatusChangedEvent->getDeviceAddress();
 				body = createNotifyParticipantDeviceDataChanged(participantAddress, deviceAddress);
 			} break;
 
@@ -449,9 +449,9 @@ Content LocalConferenceEventHandler::createNotifyMultipart(int notifyId) {
 			case EventLog::Type::ConferenceParticipantDeviceMediaCapabilityChanged: {
 				shared_ptr<ConferenceParticipantDeviceEvent> deviceMediaCapabilityChangedEvent =
 				    static_pointer_cast<ConferenceParticipantDeviceEvent>(eventLog);
-				const Address &participantAddress =
-				    deviceMediaCapabilityChangedEvent->getParticipantAddress().asAddress();
-				const Address &deviceAddress = deviceMediaCapabilityChangedEvent->getDeviceAddress().asAddress();
+				const std::shared_ptr<Address> &participantAddress =
+				    deviceMediaCapabilityChangedEvent->getParticipantAddress();
+				const std::shared_ptr<Address> &deviceAddress = deviceMediaCapabilityChangedEvent->getDeviceAddress();
 				body = createNotifyParticipantDeviceDataChanged(participantAddress, deviceAddress);
 			} break;
 
@@ -485,8 +485,9 @@ Content LocalConferenceEventHandler::createNotifyMultipart(int notifyId) {
 	return multipart;
 }
 
-string LocalConferenceEventHandler::createNotifyParticipantAdded(const Address &pAddress) {
-	string entity = conf->getConferenceAddress().asString();
+string LocalConferenceEventHandler::createNotifyParticipantAdded(const std::shared_ptr<Address> &pAddress) {
+	string entity = (conf->getConferenceAddress() ? conf->getConferenceAddress()->asStringUriOnly()
+	                                              : std::string("<unknown-conference-address>"));
 	ConferenceType confInfo = ConferenceType(entity);
 	UsersType users;
 	confInfo.setUsers(users);
@@ -497,7 +498,7 @@ string LocalConferenceEventHandler::createNotifyParticipantAdded(const Address &
 	shared_ptr<Participant> participant = conf->isMe(pAddress) ? conf->getMe() : conf->findParticipant(pAddress);
 	if (participant) {
 		for (const auto &device : participant->getDevices()) {
-			const string &gruu = device->getAddress().asString();
+			const string &gruu = device->getAddress()->asStringUriOnly();
 			EndpointType endpoint = EndpointType();
 			endpoint.setEntity(gruu);
 			const string &displayName = device->getName();
@@ -518,7 +519,7 @@ string LocalConferenceEventHandler::createNotifyParticipantAdded(const Address &
 	}
 
 	user.setRoles(roles);
-	user.setEntity(pAddress.asStringUriOnly());
+	user.setEntity(pAddress->asStringUriOnly());
 	user.getRoles()->getEntry().push_back((participant && participant->isAdmin()) ? "admin" : "participant");
 	user.setState(StateType::full);
 
@@ -527,8 +528,10 @@ string LocalConferenceEventHandler::createNotifyParticipantAdded(const Address &
 	return createNotify(confInfo);
 }
 
-string LocalConferenceEventHandler::createNotifyParticipantAdminStatusChanged(const Address &pAddress, bool isAdmin) {
-	string entity = conf->getConferenceAddress().asString();
+string LocalConferenceEventHandler::createNotifyParticipantAdminStatusChanged(const std::shared_ptr<Address> &pAddress,
+                                                                              bool isAdmin) {
+	string entity = (conf->getConferenceAddress() ? conf->getConferenceAddress()->asStringUriOnly()
+	                                              : std::string("<unknown-conference-address>"));
 	ConferenceType confInfo = ConferenceType(entity);
 	UsersType users;
 	confInfo.setUsers(users);
@@ -536,7 +539,7 @@ string LocalConferenceEventHandler::createNotifyParticipantAdminStatusChanged(co
 	UserType user = UserType();
 	UserRolesType roles;
 	user.setRoles(roles);
-	user.setEntity(pAddress.asStringUriOnly());
+	user.setEntity(pAddress->asStringUriOnly());
 	user.getRoles()->getEntry().push_back(isAdmin ? "admin" : "participant");
 	user.setState(StateType::partial);
 	confInfo.getUsers()->getUser().push_back(user);
@@ -544,14 +547,15 @@ string LocalConferenceEventHandler::createNotifyParticipantAdminStatusChanged(co
 	return createNotify(confInfo);
 }
 
-string LocalConferenceEventHandler::createNotifyParticipantRemoved(const Address &pAddress) {
-	string entity = conf->getConferenceAddress().asString();
+string LocalConferenceEventHandler::createNotifyParticipantRemoved(const std::shared_ptr<Address> &pAddress) {
+	string entity = (conf->getConferenceAddress() ? conf->getConferenceAddress()->asStringUriOnly()
+	                                              : std::string("<unknown-conference-address>"));
 	ConferenceType confInfo = ConferenceType(entity);
 	UsersType users;
 	confInfo.setUsers(users);
 
 	UserType user = UserType();
-	user.setEntity(pAddress.asStringUriOnly());
+	user.setEntity(pAddress->asStringUriOnly());
 	user.setState(StateType::deleted);
 	confInfo.getUsers()->getUser().push_back(user);
 
@@ -575,20 +579,21 @@ MediaStatusType LocalConferenceEventHandler::mediaDirectionToMediaStatus(Linphon
 	return MediaStatusType::sendrecv;
 }
 
-string LocalConferenceEventHandler::createNotifyParticipantDeviceAdded(const Address &pAddress,
-                                                                       const Address &dAddress) {
-	string entity = conf->getConferenceAddress().asString();
+string LocalConferenceEventHandler::createNotifyParticipantDeviceAdded(const std::shared_ptr<Address> &pAddress,
+                                                                       const std::shared_ptr<Address> &dAddress) {
+	string entity = (conf->getConferenceAddress() ? conf->getConferenceAddress()->asStringUriOnly()
+	                                              : std::string("<unknown-conference-address>"));
 	ConferenceType confInfo = ConferenceType(entity);
 	UsersType users;
 	confInfo.setUsers(users);
 
 	UserType user = UserType();
 	UserType::EndpointSequence endpoints;
-	user.setEntity(pAddress.asStringUriOnly());
+	user.setEntity(pAddress->asStringUriOnly());
 	user.setState(StateType::partial);
 
 	EndpointType endpoint = EndpointType();
-	endpoint.setEntity(dAddress.asStringUriOnly());
+	endpoint.setEntity(dAddress->asStringUriOnly());
 	shared_ptr<Participant> participant = conf->isMe(pAddress) ? conf->getMe() : conf->findParticipant(pAddress);
 	if (participant) {
 		shared_ptr<ParticipantDevice> participantDevice = participant->findDevice(dAddress);
@@ -627,20 +632,21 @@ string LocalConferenceEventHandler::createNotifyParticipantDeviceAdded(const Add
 	return createNotify(confInfo);
 }
 
-string LocalConferenceEventHandler::createNotifyParticipantDeviceRemoved(const Address &pAddress,
-                                                                         const Address &dAddress) {
-	string entity = conf->getConferenceAddress().asString();
+string LocalConferenceEventHandler::createNotifyParticipantDeviceRemoved(const std::shared_ptr<Address> &pAddress,
+                                                                         const std::shared_ptr<Address> &dAddress) {
+	string entity = (conf->getConferenceAddress() ? conf->getConferenceAddress()->asStringUriOnly()
+	                                              : std::string("<unknown-conference-address>"));
 	ConferenceType confInfo = ConferenceType(entity);
 	UsersType users;
 	confInfo.setUsers(users);
 
 	UserType user = UserType();
 	UserType::EndpointSequence endpoints;
-	user.setEntity(pAddress.asStringUriOnly());
+	user.setEntity(pAddress->asStringUriOnly());
 	user.setState(StateType::partial);
 
 	EndpointType endpoint = EndpointType();
-	endpoint.setEntity(dAddress.asStringUriOnly());
+	endpoint.setEntity(dAddress->asStringUriOnly());
 
 	endpoint.setState(StateType::deleted);
 
@@ -695,20 +701,21 @@ string LocalConferenceEventHandler::createNotifyParticipantDeviceRemoved(const A
 	return createNotify(confInfo);
 }
 
-string LocalConferenceEventHandler::createNotifyParticipantDeviceDataChanged(const Address &pAddress,
-                                                                             const Address &dAddress) {
-	string entity = conf->getConferenceAddress().asString();
+string LocalConferenceEventHandler::createNotifyParticipantDeviceDataChanged(const std::shared_ptr<Address> &pAddress,
+                                                                             const std::shared_ptr<Address> &dAddress) {
+	string entity = (conf->getConferenceAddress() ? conf->getConferenceAddress()->asStringUriOnly()
+	                                              : std::string("<unknown-conference-address>"));
 	ConferenceType confInfo = ConferenceType(entity);
 	UsersType users;
 	confInfo.setUsers(users);
 
 	UserType user = UserType();
 	UserType::EndpointSequence endpoints;
-	user.setEntity(pAddress.asStringUriOnly());
+	user.setEntity(pAddress->asStringUriOnly());
 	user.setState(StateType::partial);
 
 	EndpointType endpoint = EndpointType();
-	endpoint.setEntity(dAddress.asStringUriOnly());
+	endpoint.setEntity(dAddress->asStringUriOnly());
 	endpoint.setState(StateType::partial);
 	shared_ptr<Participant> participant = conf->isMe(pAddress) ? conf->getMe() : conf->findParticipant(pAddress);
 	if (participant) {
@@ -798,7 +805,8 @@ string LocalConferenceEventHandler::createNotify(ConferenceType confInfo, bool i
 }
 
 string LocalConferenceEventHandler::createNotifySubjectChanged(const string &subject) {
-	string entity = conf->getConferenceAddress().asString();
+	string entity = (conf->getConferenceAddress() ? conf->getConferenceAddress()->asStringUriOnly()
+	                                              : std::string("<unknown-conference-address>"));
 	ConferenceType confInfo = ConferenceType(entity);
 	ConferenceDescriptionType confDescr = ConferenceDescriptionType();
 	confDescr.setSubject(subject);
@@ -808,7 +816,8 @@ string LocalConferenceEventHandler::createNotifySubjectChanged(const string &sub
 }
 
 string LocalConferenceEventHandler::createNotifyEphemeralMode(const EventLog::Type &type) {
-	string entity = conf->getConferenceAddress().asString();
+	const auto &conferenceAddress = conf->getConferenceAddress();
+	const std::string entity = conferenceAddress ? conferenceAddress->asStringUriOnly() : std::string("<unknown>");
 	ConferenceType confInfo = ConferenceType(entity);
 	ConferenceDescriptionType confDescr = ConferenceDescriptionType();
 	std::string keywordList;
@@ -818,7 +827,6 @@ string LocalConferenceEventHandler::createNotifyEphemeralMode(const EventLog::Ty
 		confDescr.setKeywords(keywords);
 	}
 
-	ConferenceAddress conferenceAddress = conf->getConferenceAddress();
 	ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 	// Enquire whether this conference belongs to a server group chat room
 	shared_ptr<Core> core = conf->getCore();
@@ -847,7 +855,8 @@ string LocalConferenceEventHandler::createNotifyEphemeralMode(const EventLog::Ty
 }
 
 string LocalConferenceEventHandler::createNotifyEphemeralLifetime(const long &lifetime) {
-	string entity = conf->getConferenceAddress().asString();
+	const auto &conferenceAddress = conf->getConferenceAddress();
+	const std::string entity = conferenceAddress ? conferenceAddress->asStringUriOnly() : std::string("<unknown>");
 	ConferenceType confInfo = ConferenceType(entity);
 	ConferenceDescriptionType confDescr = ConferenceDescriptionType();
 	if (lifetime != 0) {
@@ -859,7 +868,6 @@ string LocalConferenceEventHandler::createNotifyEphemeralLifetime(const long &li
 		}
 	}
 
-	ConferenceAddress conferenceAddress = conf->getConferenceAddress();
 	ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 	// Enquire whether this conference belongs to a server group chat room
 	shared_ptr<Core> core = conf->getCore();
@@ -891,8 +899,8 @@ string LocalConferenceEventHandler::createNotifyEphemeralLifetime(const long &li
 
 string LocalConferenceEventHandler::createNotifyAvailableMediaChanged(
     const std::map<ConferenceMediaCapabilities, bool> mediaCapabilities) {
-	string entity = conf->getConferenceAddress().asString();
-
+	string entity = (conf->getConferenceAddress() ? conf->getConferenceAddress()->asStringUriOnly()
+	                                              : std::string("<unknown-conference-address>"));
 	ConferenceType confInfo = ConferenceType(entity);
 	ConferenceDescriptionType confDescr = ConferenceDescriptionType();
 	LinphoneMediaDirection audioDirection = LinphoneMediaDirectionInactive;
@@ -957,31 +965,28 @@ void LocalConferenceEventHandler::notifyParticipantDevice(const Content &notify,
 // -----------------------------------------------------------------------------
 
 LinphoneStatus LocalConferenceEventHandler::subscribeReceived(const shared_ptr<EventSubscribe> &ev) {
-	const LinphoneAddress *lAddr = ev->getFrom();
-	char *addrStr = linphone_address_as_string(lAddr);
-	Address participantAddress(addrStr);
-	bctbx_free(addrStr);
+	const auto &participantAddress = ev->getFrom();
 	unsigned int lastNotify = conf->getLastNotify();
 
+	const auto &conferenceAddress = conf->getConferenceAddress();
+	const std::string conferenceAddressString =
+	    conferenceAddress ? conferenceAddress->asStringUriOnly() : std::string("<unknown>");
+
 	shared_ptr<Participant> participant = getConferenceParticipant(participantAddress);
 	if (!participant) {
-		ConferenceAddress conferenceAddress = conf->getConferenceAddress();
-		lError() << "Received SUBSCRIBE corresponds to no participant of the conference [" << conferenceAddress
+		lError() << "Received SUBSCRIBE corresponds to no participant of the conference [" << conferenceAddressString
 		         << "], no NOTIFY sent";
 		ev->deny(LinphoneReasonDeclined);
 		return -1;
 	}
 
-	const LinphoneAddress *lContactAddr = ev->getRemoteContact();
-	char *contactAddrStr = linphone_address_as_string(lContactAddr);
-	IdentityAddress contactAddr(contactAddrStr);
-	bctbx_free(contactAddrStr);
+	const auto &contactAddr = ev->getRemoteContact();
 	shared_ptr<ParticipantDevice> device = participant->findDevice(contactAddr);
 	const auto deviceState = device ? device->getState() : ParticipantDevice::State::ScheduledForJoining;
 	if (!device ||
 	    ((deviceState != ParticipantDevice::State::Present) && (deviceState != ParticipantDevice::State::Joining))) {
-		lError() << "Received SUBSCRIBE for conference [" << conf->getConferenceAddress()
-		         << "], device sending subscribe [" << contactAddr << "] is not known, no NOTIFY sent";
+		lError() << "Received SUBSCRIBE for conference [" << conferenceAddressString << "], device sending subscribe ["
+		         << *contactAddr << "] is not known, no NOTIFY sent";
 		ev->deny(LinphoneReasonDeclined);
 		return -1;
 	}
@@ -1011,8 +1016,8 @@ LinphoneStatus LocalConferenceEventHandler::subscribeReceived(const shared_ptr<E
 			if (deviceState != ParticipantDevice::State::Present) {
 				// Notify everybody that a participant device has been added and its capabilities after receiving the
 				// SUBSCRIBE
-				const auto notify = createNotifyParticipantDeviceDataChanged(participant->getAddress().asAddress(),
-				                                                             device->getAddress().asAddress());
+				const auto notify =
+				    createNotifyParticipantDeviceDataChanged(participant->getAddress(), device->getAddress());
 				notifyAllExceptDevice(makeContent(notify), device);
 			}
 		} else if (evLastNotify < lastNotify) {
@@ -1042,16 +1047,10 @@ LinphoneStatus LocalConferenceEventHandler::subscribeReceived(const shared_ptr<E
 void LocalConferenceEventHandler::subscriptionStateChanged(const shared_ptr<EventSubscribe> &ev,
                                                            LinphoneSubscriptionState state) {
 	if (state == LinphoneSubscriptionTerminated && conf) {
-		const LinphoneAddress *lAddr = ev->getFrom();
-		char *addrStr = linphone_address_as_string(lAddr);
-		Address participantAddress(addrStr);
+		const auto &participantAddress = ev->getFrom();
 		shared_ptr<Participant> participant = getConferenceParticipant(participantAddress);
-		bctbx_free(addrStr);
 		if (!participant) return;
-		const LinphoneAddress *lContactAddr = ev->getRemoteContact();
-		char *contactAddrStr = linphone_address_as_string(lContactAddr);
-		IdentityAddress contactAddr(contactAddrStr);
-		bctbx_free(contactAddrStr);
+		const auto &contactAddr = ev->getRemoteContact();
 		shared_ptr<ParticipantDevice> device = participant->findDevice(contactAddr);
 		if (!device) return;
 		if (ev == device->getConferenceSubscribeEvent()) {
@@ -1093,12 +1092,12 @@ void LocalConferenceEventHandler::onParticipantAdded(const std::shared_ptr<Confe
                                                      const std::shared_ptr<Participant> &participant) {
 	// 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().asAddress())), participant);
+		notifyAllExcept(makeContent(createNotifyParticipantAdded(participant->getAddress())), participant);
 		conf->updateParticipantsInConferenceInfo(participant->getAddress());
 
 		if (conf) {
 			shared_ptr<Core> core = conf->getCore();
-			ConferenceAddress conferenceAddress = conf->getConferenceAddress();
+			std::shared_ptr<Address> conferenceAddress = conf->getConferenceAddress();
 			ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 
 			// Enquire whether this conference belongs to a server group chat room
@@ -1117,11 +1116,10 @@ void LocalConferenceEventHandler::onParticipantRemoved(const std::shared_ptr<Con
                                                        const std::shared_ptr<Participant> &participant) {
 	// Do not send notify if conference pointer is null. It may mean that the confernece has been terminated
 	if (conf) {
-		notifyAllExcept(makeContent(createNotifyParticipantRemoved(participant->getAddress().asAddress())),
-		                participant);
+		notifyAllExcept(makeContent(createNotifyParticipantRemoved(participant->getAddress())), participant);
 		if (conf) {
 			shared_ptr<Core> core = conf->getCore();
-			ConferenceAddress conferenceAddress = conf->getConferenceAddress();
+			std::shared_ptr<Address> conferenceAddress = conf->getConferenceAddress();
 			ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 
 			// Enquire whether this conference belongs to a server group chat room
@@ -1142,11 +1140,10 @@ void LocalConferenceEventHandler::onParticipantSetAdmin(const std::shared_ptr<Co
 	const bool isAdmin = (event->getType() == EventLog::Type::ConferenceParticipantSetAdmin);
 	// Do not send notify if conference pointer is null. It may mean that the confernece has been terminated
 	if (conf) {
-		notifyAll(
-		    makeContent(createNotifyParticipantAdminStatusChanged(participant->getAddress().asAddress(), isAdmin)));
+		notifyAll(makeContent(createNotifyParticipantAdminStatusChanged(participant->getAddress(), isAdmin)));
 		if (conf) {
 			shared_ptr<Core> core = conf->getCore();
-			ConferenceAddress conferenceAddress = conf->getConferenceAddress();
+			std::shared_ptr<Address> conferenceAddress = conf->getConferenceAddress();
 			ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 
 			// Enquire whether this conference belongs to a server group chat room
@@ -1168,7 +1165,7 @@ void LocalConferenceEventHandler::onSubjectChanged(const std::shared_ptr<Confere
 		notifyAll(makeContent(createNotifySubjectChanged(event->getSubject())));
 		if (conf) {
 			shared_ptr<Core> core = conf->getCore();
-			ConferenceAddress conferenceAddress = conf->getConferenceAddress();
+			std::shared_ptr<Address> conferenceAddress = conf->getConferenceAddress();
 			ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 
 			// Enquire whether this conference belongs to a server group chat room
@@ -1208,16 +1205,15 @@ void LocalConferenceEventHandler::onParticipantDeviceAdded(
 		auto participant = device->getParticipant();
 		// If the ssrc is not 0, send a NOTIFY to the participant being added in order to give him its own SSRC
 		if ((device->getSsrc(LinphoneStreamTypeAudio) != 0) || (device->getSsrc(LinphoneStreamTypeVideo) != 0)) {
-			notifyAll(makeContent(createNotifyParticipantDeviceAdded(participant->getAddress().asAddress(),
-			                                                         device->getAddress().asAddress())));
+			notifyAll(makeContent(createNotifyParticipantDeviceAdded(participant->getAddress(), device->getAddress())));
 		} else {
-			notifyAllExceptDevice(makeContent(createNotifyParticipantDeviceAdded(participant->getAddress().asAddress(),
-			                                                                     device->getAddress().asAddress())),
-			                      device);
+			notifyAllExceptDevice(
+			    makeContent(createNotifyParticipantDeviceAdded(participant->getAddress(), device->getAddress())),
+			    device);
 		}
 		if (conf) {
 			shared_ptr<Core> core = conf->getCore();
-			ConferenceAddress conferenceAddress = conf->getConferenceAddress();
+			std::shared_ptr<Address> conferenceAddress = conf->getConferenceAddress();
 			ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 
 			// Enquire whether this conference belongs to a server group chat room
@@ -1238,12 +1234,11 @@ void LocalConferenceEventHandler::onParticipantDeviceRemoved(
 	// Do not send notify if conference pointer is null. It may mean that the confernece has been terminated
 	if (conf) {
 		auto participant = device->getParticipant();
-		notifyAllExceptDevice(makeContent(createNotifyParticipantDeviceRemoved(participant->getAddress().asAddress(),
-		                                                                       device->getAddress().asAddress())),
-		                      device);
+		notifyAllExceptDevice(
+		    makeContent(createNotifyParticipantDeviceRemoved(participant->getAddress(), device->getAddress())), device);
 		if (conf) {
 			shared_ptr<Core> core = conf->getCore();
-			ConferenceAddress conferenceAddress = conf->getConferenceAddress();
+			std::shared_ptr<Address> conferenceAddress = conf->getConferenceAddress();
 			ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 
 			// Enquire whether this conference belongs to a server group chat room
@@ -1264,11 +1259,11 @@ void LocalConferenceEventHandler::onParticipantDeviceStateChanged(
 	// Do not send notify if conference pointer is null. It may mean that the confernece has been terminated
 	if (conf) {
 		auto participant = device->getParticipant();
-		notifyAll(makeContent(createNotifyParticipantDeviceDataChanged(participant->getAddress().asAddress(),
-		                                                               device->getAddress().asAddress())));
+		notifyAll(
+		    makeContent(createNotifyParticipantDeviceDataChanged(participant->getAddress(), device->getAddress())));
 		if (conf) {
 			shared_ptr<Core> core = conf->getCore();
-			ConferenceAddress conferenceAddress = conf->getConferenceAddress();
+			std::shared_ptr<Address> conferenceAddress = conf->getConferenceAddress();
 			ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 
 			// Enquire whether this conference belongs to a server group chat room
@@ -1291,8 +1286,8 @@ void LocalConferenceEventHandler::onParticipantDeviceMediaCapabilityChanged(
 	// Do not send notify if conference pointer is null. It may mean that the confernece has been terminated
 	if (conf) {
 		auto participant = device->getParticipant();
-		notifyAll(makeContent(createNotifyParticipantDeviceDataChanged(participant->getAddress().asAddress(),
-		                                                               device->getAddress().asAddress())));
+		notifyAll(
+		    makeContent(createNotifyParticipantDeviceDataChanged(participant->getAddress(), device->getAddress())));
 	} else {
 		lWarning() << __func__ << ": Not sending notification of participant device " << device->getAddress()
 		           << " being added because pointer to conference is null";
@@ -1327,9 +1322,10 @@ void LocalConferenceEventHandler::onActiveSpeakerParticipantDevice(
     BCTBX_UNUSED(const std::shared_ptr<ParticipantDevice> &device)) {
 }
 
-shared_ptr<Participant> LocalConferenceEventHandler::getConferenceParticipant(const Address &address) const {
+shared_ptr<Participant>
+LocalConferenceEventHandler::getConferenceParticipant(const std::shared_ptr<Address> &address) const {
 	shared_ptr<Core> core = conf->getCore();
-	ConferenceAddress conferenceAddress = conf->getConferenceAddress();
+	std::shared_ptr<Address> conferenceAddress = conf->getConferenceAddress();
 	ConferenceId conferenceId(conferenceAddress, conferenceAddress);
 
 	// Enquire whether this conference belongs to a server group chat room
diff --git a/src/conference/handlers/local-conference-event-handler.h b/src/conference/handlers/local-conference-event-handler.h
index 140dc1adb0e26d437c2f27df97fffa5eb7a52517..6603927d8645148feb452d1b3e42624032b5e51c 100644
--- a/src/conference/handlers/local-conference-event-handler.h
+++ b/src/conference/handlers/local-conference-event-handler.h
@@ -77,14 +77,17 @@ public:
 	std::string createNotifySubjectChanged();
 
 	// Participant
-	std::string createNotifyParticipantAdded(const Address &pAddress);
-	std::string createNotifyParticipantAdminStatusChanged(const Address &pAddress, bool isAdmin);
-	std::string createNotifyParticipantRemoved(const Address &pAddress);
+	std::string createNotifyParticipantAdded(const std::shared_ptr<Address> &pAddress);
+	std::string createNotifyParticipantAdminStatusChanged(const std::shared_ptr<Address> &pAddress, bool isAdmin);
+	std::string createNotifyParticipantRemoved(const std::shared_ptr<Address> &pAddress);
 
 	// Participant device
-	std::string createNotifyParticipantDeviceAdded(const Address &pAddress, const Address &dAddress);
-	std::string createNotifyParticipantDeviceRemoved(const Address &pAddress, const Address &dAddress);
-	std::string createNotifyParticipantDeviceDataChanged(const Address &pAddress, const Address &dAddress);
+	std::string createNotifyParticipantDeviceAdded(const std::shared_ptr<Address> &pAddress,
+	                                               const std::shared_ptr<Address> &dAddress);
+	std::string createNotifyParticipantDeviceRemoved(const std::shared_ptr<Address> &pAddress,
+	                                                 const std::shared_ptr<Address> &dAddress);
+	std::string createNotifyParticipantDeviceDataChanged(const std::shared_ptr<Address> &pAddress,
+	                                                     const std::shared_ptr<Address> &dAddress);
 
 	static void notifyResponseCb(const LinphoneEvent *lev);
 
@@ -214,7 +217,7 @@ private:
 	void notifyParticipant(const Content &notify, const std::shared_ptr<Participant> &participant);
 	void notifyParticipantDevice(const Content &notify, const std::shared_ptr<ParticipantDevice> &device);
 
-	std::shared_ptr<Participant> getConferenceParticipant(const Address &address) const;
+	std::shared_ptr<Participant> getConferenceParticipant(const std::shared_ptr<Address> &address) const;
 
 	void addMediaCapabilities(const std::shared_ptr<ParticipantDevice> &device,
 	                          Xsd::ConferenceInfo::EndpointType &endpoint);
diff --git a/src/conference/handlers/local-conference-list-event-handler.cpp b/src/conference/handlers/local-conference-list-event-handler.cpp
index 15a0c85422b302e84f90c32f734c45ecffff8221..9c2199e2df341d52e3eb39008253343280999b07 100644
--- a/src/conference/handlers/local-conference-list-event-handler.cpp
+++ b/src/conference/handlers/local-conference-list-event-handler.cpp
@@ -92,15 +92,8 @@ void LocalConferenceListEventHandler::subscribeReceived(const std::shared_ptr<Ev
 	    subscriptionState != LinphoneSubscriptionTerminated)
 		return;
 
-	const LinphoneAddress *lAddr = ev->getFrom();
-	char *addrStr = linphone_address_as_string(lAddr);
-	IdentityAddress participantAddr(addrStr);
-	bctbx_free(addrStr);
-
-	const LinphoneAddress *lDeviceAddr = ev->getRemoteContact();
-	char *deviceAddrStr = linphone_address_as_string(lDeviceAddr);
-	IdentityAddress deviceAddr(deviceAddrStr);
-	bctbx_free(deviceAddrStr);
+	const auto &participantAddr = ev->getFrom();
+	const auto &deviceAddr = ev->getRemoteContact();
 
 	// Create Rlmi body
 	Xsd::Rlmi::List::ResourceSequence resources;
@@ -119,9 +112,9 @@ void LocalConferenceListEventHandler::subscribeReceived(const std::shared_ptr<Ev
 
 	for (const auto &l : rl->getList()) {
 		for (const auto &entry : l.getEntry()) {
-			Address addr(entry.getUri());
-			string notifyIdStr = addr.getUriParamValue("Last-Notify");
-			addr.removeUriParam("Last-Notify");
+			std::shared_ptr<Address> addr = Address::create(entry.getUri());
+			string notifyIdStr = addr->getUriParamValue("Last-Notify");
+			addr->removeUriParam("Last-Notify");
 			ConferenceId conferenceId(addr, addr);
 			LocalConferenceEventHandler *handler = findHandler(conferenceId);
 			if (!handler) continue;
@@ -162,7 +155,7 @@ void LocalConferenceListEventHandler::subscribeReceived(const std::shared_ptr<Ev
 			contents.push_back(std::move(content));
 
 			// Add entry into the Rlmi content of the notify body
-			Xsd::Rlmi::Resource resource(addr.asStringUriOnly());
+			Xsd::Rlmi::Resource resource(addr->asStringUriOnly());
 			Xsd::Rlmi::Resource::InstanceSequence instances;
 			Xsd::Rlmi::Instance instance(token, Xsd::Rlmi::State::Value::active);
 			instances.push_back(instance);
diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp
index 141f2c25f86e4c63e4b171448e76cd9d011bec29..72c1bbd6c44806cd68f3f050ccba9199356d16f6 100644
--- a/src/conference/handlers/remote-conference-event-handler.cpp
+++ b/src/conference/handlers/remote-conference-event-handler.cpp
@@ -90,13 +90,18 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 	}
 
 	const auto &core = conf->getCore();
+	const auto &conferenceAddress = conf->getConferenceAddress();
+	const std::string conferenceAddressString =
+	    conferenceAddress ? conferenceAddress->toString() : std::string("<unknown>");
 	auto chatRoom = core->findChatRoom(getConferenceId());
 
-	ConferenceAddress entityAddress(confInfo->getEntity());
+	std::shared_ptr<Address> entityAddress = Address::create(confInfo->getEntity());
+	const auto &peerAddress = getConferenceId().getPeerAddress();
 
-	if (entityAddress != getConferenceId().getPeerAddress()) {
-		lError() << "Unable to process received NOTIFY because the entity address " << entityAddress
-		         << " doesn't match the peer address " << getConferenceId().getPeerAddress();
+	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()
+		         << " doesn't match the peer address " << peerAddressString;
 		return;
 	}
 
@@ -111,7 +116,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 	}
 
 	if (waitingFullState && !isFullState) {
-		lError() << "Unable to process received NOTIFY because conference " << conf->getConferenceAddress()
+		lError() << "Unable to process received NOTIFY because conference " << conferenceAddressString
 		         << " is waiting a full state";
 		return;
 	} else {
@@ -239,7 +244,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 
 	// 4. Notify changes on users.
 	for (auto &user : users->getUser()) {
-		Address address(core->interpretUrl(user.getEntity().get(), false));
+		std::shared_ptr<Address> address = core->interpretUrl(user.getEntity().get(), false);
 		StateType state = user.getState();
 
 		shared_ptr<Participant> participant = nullptr;
@@ -248,29 +253,28 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 
 		const auto &pIt =
 		    std::find_if(oldParticipants.cbegin(), oldParticipants.cend(), [&address](const auto &currentParticipant) {
-			    return (address == currentParticipant->getAddress().asAddress());
+			    return (*address == *currentParticipant->getAddress());
 		    });
 
 		if (state == StateType::deleted) {
 			if (conf->isMe(address)) {
-				lInfo() << "Participant " << address.asString() << " requested to be deleted is me.";
+				lInfo() << "Participant " << address->toString() << " requested to be deleted is me.";
 				continue;
 			} else if (participant) {
 				conf->participants.remove(participant);
 				lInfo() << "Participant " << *participant << " is successfully removed - conference "
-				        << conf->getConferenceAddress().asString() << " has " << conf->getParticipantCount()
-				        << " participants";
+				        << conferenceAddressString << " has " << conf->getParticipantCount() << " participants";
 				if (!isFullState) {
 					conf->notifyParticipantRemoved(creationTime, isFullState, participant);
 				}
 
 				continue;
 			} else {
-				lWarning() << "Participant " << address.asString() << " removed but not in the list of participants!";
+				lWarning() << "Participant " << address->toString() << " removed but not in the list of participants!";
 			}
 		} else if (state == StateType::full) {
 			if (conf->isMe(address)) {
-				lInfo() << "Participant " << address.asString() << " requested to be added is me.";
+				lInfo() << "Participant " << address->toString() << " requested to be added is me.";
 			} else if (participant) {
 				lWarning() << "Participant " << *participant << " added but already in the list of participants!";
 			} else {
@@ -278,8 +282,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 				conf->participants.push_back(participant);
 				conf->updateParticipantsInConferenceInfo(address);
 				lInfo() << "Participant " << *participant << " is successfully added - conference "
-				        << conf->getConferenceAddress().asString() << " has " << conf->getParticipantCount()
-				        << " participants";
+				        << conferenceAddressString << " has " << conf->getParticipantCount() << " participants";
 
 				if (!isFullState ||
 				    (!oldParticipants.empty() && (pIt == oldParticipants.cend()) && !conf->isMe(address))) {
@@ -295,10 +298,10 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 		}
 
 		if (!participant) {
-			lDebug() << "Participant " << address.asString()
+			lDebug() << "Participant " << address->toString()
 			         << " is not in the list of participants however it is trying to change the list of devices or "
 			            "change role! Resubscribing to conference "
-			         << conf->getConferenceAddress() << " to clear things up.";
+			         << conferenceAddressString << " to clear things up.";
 			requestFullState();
 		} else {
 
@@ -321,7 +324,7 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 			for (const auto &endpoint : user.getEndpoint()) {
 				if (!endpoint.getEntity().present()) continue;
 
-				Address gruu(endpoint.getEntity().get());
+				std::shared_ptr<Address> gruu = Address::create(endpoint.getEntity().get());
 				StateType state = endpoint.getState();
 
 				shared_ptr<ParticipantDevice> device = nullptr;
@@ -542,14 +545,14 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 					if (conf->isMe(address) && conf->getMainSession()) device->setSession(conf->getMainSession());
 
 					if (state == StateType::full) {
-						lInfo() << "Participant device " << gruu.asString() << " has been successfully added";
+						lInfo() << "Participant device " << gruu->toString() << " has been successfully added";
 						bool sendNotify =
 						    (!oldParticipants.empty() && (pIt == oldParticipants.cend())) && !conf->isMe(address);
 						if (pIt != oldParticipants.cend()) {
 							const auto &oldDevices = (*pIt)->getDevices();
 							const auto &dIt =
 							    std::find_if(oldDevices.cbegin(), oldDevices.cend(), [&gruu](const auto &oldDevice) {
-								    return (gruu == oldDevice->getAddress().asAddress());
+								    return (*gruu == *oldDevice->getAddress());
 							    });
 							sendNotify = (dIt == oldDevices.cend()) && !conf->isMe(address);
 						}
@@ -557,13 +560,12 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 							conf->notifyParticipantDeviceAdded(creationTime, isFullState, participant, device);
 						}
 					} else {
-						lInfo() << "Participant device " << gruu.asString() << " has been successfully updated";
+						lInfo() << "Participant device " << gruu->toString() << " has been successfully updated";
 					}
 				} else {
-					lDebug() << "Unable to update media direction of device " << gruu
-					         << " because it has not been found in conference " << conf->getConferenceAddress()
-					         << ". Resubscribing to conference " << conf->getConferenceAddress()
-					         << " to clear things up.";
+					lDebug() << "Unable to update media direction of device " << *gruu
+					         << " because it has not been found in conference " << conferenceAddressString
+					         << ". Resubscribing to conference " << conferenceAddressString << " to clear things up.";
 					requestFullState();
 				}
 			}
@@ -576,9 +578,10 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 		// Send participant and participant device removed notifys if the full state has less participants than the
 		// current chat room or conference
 		for (const auto &p : oldParticipants) {
-			const auto &pIt = std::find_if(
-			    currentParticipants.cbegin(), currentParticipants.cend(),
-			    [&p](const auto &currentParticipant) { return (p->getAddress() == currentParticipant->getAddress()); });
+			const auto &pIt = std::find_if(currentParticipants.cbegin(), currentParticipants.cend(),
+			                               [&p](const auto &currentParticipant) {
+				                               return (*p->getAddress() == *currentParticipant->getAddress());
+			                               });
 			for (const auto &d : p->getDevices()) {
 				bool deviceFound = false;
 				if (pIt == currentParticipants.cend()) {
@@ -587,31 +590,31 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 					const auto &currentDevices = (*pIt)->getDevices();
 					const auto &dIt =
 					    std::find_if(currentDevices.cbegin(), currentDevices.cend(), [&d](const auto &currentDevice) {
-						    return (d->getAddress() == currentDevice->getAddress());
+						    return (*d->getAddress() == *currentDevice->getAddress());
 					    });
 					deviceFound = (dIt != currentDevices.cend());
 				}
 				if (!deviceFound) {
-					lInfo() << "Device " << d->getAddress() << " is no longer a member of chatroom or conference "
-					        << conf->getConferenceAddress();
+					lInfo() << "Device " << *d->getAddress() << " is no longer a member of chatroom or conference "
+					        << conferenceAddressString;
 					conf->notifyParticipantDeviceRemoved(creationTime, isFullState, p, d);
 				}
 			}
 			if (pIt == currentParticipants.cend()) {
-				lInfo() << "Participant " << p->getAddress() << " is no longer a member of chatroom or conference "
-				        << conf->getConferenceAddress();
+				lInfo() << "Participant " << *p->getAddress() << " is no longer a member of chatroom or conference "
+				        << conferenceAddressString;
 				conf->notifyParticipantRemoved(creationTime, isFullState, p);
 			}
 		}
 		for (const auto &d : oldMeDevices) {
 			const auto &dIt =
 			    std::find_if(currentMeDevices.cbegin(), currentMeDevices.cend(), [&d](const auto &currentDevice) {
-				    return (d->getAddress() == currentDevice->getAddress());
+				    return (*d->getAddress() == *currentDevice->getAddress());
 			    });
 			bool deviceFound = (dIt != currentMeDevices.cend());
 			if (!deviceFound) {
-				lInfo() << "Device " << d->getAddress() << " is no longer a member of chatroom or conference "
-				        << conf->getConferenceAddress();
+				lInfo() << "Device " << *d->getAddress() << " is no longer a member of chatroom or conference "
+				        << conferenceAddressString;
 				conf->notifyParticipantDeviceRemoved(creationTime, isFullState, conf->getMe(), d);
 			}
 		}
@@ -623,7 +626,9 @@ void RemoteConferenceEventHandler::conferenceInfoNotifyReceived(const string &xm
 }
 
 void RemoteConferenceEventHandler::requestFullState() {
-	lInfo() << "Requesting full state for conference " << conf->getConferenceAddress();
+	lInfo() << "Requesting full state for conference "
+	        << (conf->getConferenceAddress() ? conf->getConferenceAddress()->toString()
+	                                         : std::string("<unknown conference address>"));
 	unsubscribe();
 	conf->setLastNotify(0);
 	subscribe(getConferenceId());
@@ -653,7 +658,7 @@ bool RemoteConferenceEventHandler::alreadySubscribed() const {
 void RemoteConferenceEventHandler::subscribe() {
 	if (!alreadySubscribed()) return; // Already subscribed or application did not request subscription
 
-	const string &localAddress = getConferenceId().getLocalAddress().asString();
+	const string &localAddress = getConferenceId().getLocalAddress()->toString();
 	LinphoneAddress *lAddr = linphone_address_new(localAddress.c_str());
 
 	LinphoneCore *lc = conf->getCore()->getCCore();
@@ -664,17 +669,14 @@ void RemoteConferenceEventHandler::subscribe() {
 		return;
 	}
 
-	const string &peerAddress = getConferenceId().getPeerAddress().asString();
-	LinphoneAddress *peerAddr = linphone_address_new(peerAddress.c_str());
-
+	const auto &peerAddress = getConferenceId().getPeerAddress();
 	ev = dynamic_pointer_cast<EventSubscribe>(
-	    (new EventSubscribe(conf->getCore(), peerAddr, cfg, "conference", 600))->toSharedPtr());
+	    (new EventSubscribe(conf->getCore(), peerAddress, cfg, "conference", 600))->toSharedPtr());
 	ev->getOp()->setFrom(localAddress);
 	setInitialSubscriptionUnderWayFlag((getLastNotify() == 0));
 	const string &lastNotifyStr = Utils::toString(getLastNotify());
 	ev->addCustomHeader("Last-Notify-Version", lastNotifyStr.c_str());
 	linphone_address_unref(lAddr);
-	linphone_address_unref(peerAddr);
 	ev->setInternal(true);
 	ev->setProperty("event-handler-private", this);
 	lInfo() << localAddress << " is subscribing to chat room or conference: " << peerAddress
diff --git a/src/conference/handlers/remote-conference-list-event-handler.cpp b/src/conference/handlers/remote-conference-list-event-handler.cpp
index 8f83aba4d48bd6e1f2beeb3414300e510e349d4c..655ba3c971926f0cedc128bca9291e886dffd049 100644
--- a/src/conference/handlers/remote-conference-list-event-handler.cpp
+++ b/src/conference/handlers/remote-conference-list-event-handler.cpp
@@ -72,12 +72,13 @@ void RemoteConferenceListEventHandler::subscribe() {
 	const bctbx_list_t *list = linphone_core_get_account_list(lc);
 
 	for (; list != NULL; list = list->next) {
-		subscribe((LinphoneAccount *)list->data);
+		const auto &account = Account::toCpp((LinphoneAccount *)list->data)->getSharedFromThis();
+		subscribe(account);
 	}
 }
 
-void RemoteConferenceListEventHandler::subscribe(LinphoneAccount *c_account) {
-	unsubscribe(c_account);
+void RemoteConferenceListEventHandler::subscribe(const shared_ptr<Account> &account) {
+	unsubscribe(account);
 
 	if (handlers.empty()) return;
 
@@ -87,24 +88,23 @@ void RemoteConferenceListEventHandler::subscribe(LinphoneAccount *c_account) {
 	Xsd::ResourceLists::ResourceLists rl = Xsd::ResourceLists::ResourceLists();
 	Xsd::ResourceLists::ListType l = Xsd::ResourceLists::ListType();
 
-	auto account = Account::toCpp(c_account);
 	const auto &accountParams = account->getAccountParams();
-	Address identityAddress = *L_GET_CPP_PTR_FROM_C_OBJECT(accountParams->getIdentityAddress());
+	std::shared_ptr<Address> identityAddress = accountParams->getIdentityAddress();
 
 	for (const auto &p : handlers) {
 		RemoteConferenceEventHandler *handler = p.second;
 		const ConferenceId &conferenceId = handler->getConferenceId();
-		if (identityAddress.weakEqual(conferenceId.getLocalAddress().asAddress())) {
+		if (identityAddress->weakEqual(*conferenceId.getLocalAddress())) {
 			shared_ptr<AbstractChatRoom> cr = getCore()->findChatRoom(conferenceId);
 			if (!cr) {
 				lError() << "Couldn't add chat room " << conferenceId
-				         << "in the chat room list subscription because chat room couldn't be found";
+				         << " in the chat room list subscription because chat room couldn't be found";
 				continue;
 			}
 
 			if (cr->hasBeenLeft()) continue;
 
-			Address addr = conferenceId.getPeerAddress().asAddress();
+			Address addr = conferenceId.getPeerAddress()->getUri();
 			const auto lastNotify = handler->getLastNotify();
 			addr.setUriParam("Last-Notify", Utils::toString(lastNotify));
 			handler->setInitialSubscriptionUnderWayFlag((lastNotify == 0));
@@ -128,19 +128,16 @@ void RemoteConferenceListEventHandler::subscribe(LinphoneAccount *c_account) {
 		return;
 	}
 
-	LinphoneAddress *rlsAddr = linphone_address_new(L_STRING_TO_C(factoryUri));
-
-	LinphoneCore *lc = getCore()->getCCore();
-	LinphoneEvent *lev = linphone_core_create_subscribe(lc, rlsAddr, "conference", 600);
-	shared_ptr<EventSubscribe> evSub = dynamic_pointer_cast<EventSubscribe>(Event::toCpp(lev)->getSharedFromThis());
-	char *from = linphone_address_as_string(account->getContactAddress());
+	auto rlsAddr = Address::create(factoryUri);
+	auto evSub = dynamic_pointer_cast<EventSubscribe>(
+	    (new EventSubscribe(getCore(), rlsAddr, "conference", 600))->toSharedPtr());
+	std::string from = account->getContactAddress()->toString();
 	evSub->getOp()->setFrom(from);
-	bctbx_free(from);
-	linphone_address_unref(rlsAddr);
 	evSub->setInternal(true);
 	evSub->addCustomHeader("Require", "recipient-list-subscribe");
 	evSub->addCustomHeader("Accept", "multipart/related, application/conference-info+xml, application/rlmi+xml");
 	evSub->addCustomHeader("Content-Disposition", "recipient-list");
+	LinphoneCore *lc = getCore()->getCCore();
 	if (linphone_core_content_encoding_supported(lc, "deflate")) {
 		content.setContentEncoding("deflate");
 		evSub->addCustomHeader("Accept-Encoding", "deflate");
@@ -155,24 +152,19 @@ void RemoteConferenceListEventHandler::subscribe(LinphoneAccount *c_account) {
 void RemoteConferenceListEventHandler::unsubscribe() {
 	for (auto &evSub : levs) {
 		evSub->terminate();
-		evSub->unref();
 	}
 	levs.clear();
 }
 
-void RemoteConferenceListEventHandler::unsubscribe(LinphoneAccount *c_account) {
-	auto account = Account::toCpp(c_account);
+void RemoteConferenceListEventHandler::unsubscribe(const std::shared_ptr<Account> &account) {
 	if (!account || !account->getContactAddress()) return;
-	char *from = linphone_address_as_string(account->getContactAddress());
-	auto it = std::find_if(levs.begin(), levs.end(),
-	                       [from](const auto &evSub) { return (evSub->getOp()->getFrom() == from); });
-	bctbx_free(from);
+	const auto &from = account->getContactAddress();
+	auto it = std::find_if(levs.begin(), levs.end(), [from](const auto &lev) { return (*lev->getFrom() == *from); });
 
 	if (it != levs.end()) {
 		shared_ptr<EventSubscribe> evSub = *it;
 		levs.erase(it);
 		evSub->terminate();
-		evSub->unref();
 	}
 }
 
@@ -186,7 +178,7 @@ bool RemoteConferenceListEventHandler::getInitialSubscriptionUnderWayFlag(const
 }
 
 void RemoteConferenceListEventHandler::notifyReceived(std::string from, const Content *notifyContent) {
-	const ConferenceAddress local(from);
+	const std::shared_ptr<Address> local = Address::create(from);
 
 	if (notifyContent->getContentType() == ContentType::ConferenceInfo) {
 		// Simple notify received directly from a chat-room
@@ -200,7 +192,7 @@ void RemoteConferenceListEventHandler::notifyReceived(std::string from, const Co
 			return;
 		}
 
-		ConferenceAddress entityAddress(confInfo->getEntity().c_str());
+		std::shared_ptr<Address> entityAddress = Address::create(confInfo->getEntity().c_str());
 		ConferenceId id(entityAddress, local);
 		RemoteConferenceEventHandler *handler = findHandler(id);
 		if (!handler) return;
@@ -210,7 +202,7 @@ void RemoteConferenceListEventHandler::notifyReceived(std::string from, const Co
 	}
 
 	list<Content> contents = ContentManager::multipartToContentList(*notifyContent);
-	map<string, IdentityAddress> addresses;
+	map<string, std::shared_ptr<Address>> addresses;
 	for (const auto &content : contents) {
 		const string &body = content.getBodyAsUtf8String();
 		const ContentType &contentType = content.getContentType();
@@ -222,10 +214,10 @@ void RemoteConferenceListEventHandler::notifyReceived(std::string from, const Co
 		const string &cid = content.getHeader("Content-Id").getValue();
 		if (cid.empty()) continue;
 
-		map<string, IdentityAddress>::const_iterator it = addresses.find(cid);
+		map<string, std::shared_ptr<Address>>::const_iterator it = addresses.find(cid);
 		if (it == addresses.cend()) continue;
 
-		IdentityAddress peer = it->second;
+		std::shared_ptr<Address> peer = it->second;
 		ConferenceId id(peer, local);
 		RemoteConferenceEventHandler *handler = findHandler(id);
 		if (!handler) continue;
@@ -272,13 +264,14 @@ void RemoteConferenceListEventHandler::addHandler(RemoteConferenceEventHandler *
 
 bool RemoteConferenceListEventHandler::isHandlerInSameDomainAsCore(const ConferenceId &conferenceId) const {
 	// Ensure that conference and conference factory are in the same domain
-	const ConferenceAddress &localAddress = conferenceId.getLocalAddress();
-	const ConferenceAddress &peerAddress = conferenceId.getPeerAddress();
-	IdentityAddress conferenceFactoryUri = IdentityAddress(Core::getConferenceFactoryUri(getCore(), localAddress));
-
-	if (peerAddress.getDomain() != conferenceFactoryUri.getDomain()) {
-		lWarning() << "Peer address " << peerAddress.asString()
-		           << " is not in the same domain as the conference factory URI " << conferenceFactoryUri.asString()
+	const std::shared_ptr<Address> &localAddress = conferenceId.getLocalAddress();
+	const std::shared_ptr<Address> &peerAddress = conferenceId.getPeerAddress();
+	std::shared_ptr<Address> conferenceFactoryUri =
+	    Address::create(Core::getConferenceFactoryUri(getCore(), localAddress));
+
+	if (peerAddress->getDomain() != conferenceFactoryUri->getDomain()) {
+		lWarning() << "Peer address " << peerAddress->toString()
+		           << " is not in the same domain as the conference factory URI " << conferenceFactoryUri->toString()
 		           << " hence not adding to the list of subscribes";
 		return false;
 	}
@@ -314,9 +307,9 @@ void RemoteConferenceListEventHandler::clearHandlers() {
 	handlers.clear();
 }
 
-map<string, IdentityAddress> RemoteConferenceListEventHandler::parseRlmi(const string &xmlBody) const {
+map<string, std::shared_ptr<Address>> RemoteConferenceListEventHandler::parseRlmi(const string &xmlBody) const {
 	istringstream data(xmlBody);
-	map<string, IdentityAddress> addresses;
+	map<string, std::shared_ptr<Address>> addresses;
 	unique_ptr<Xsd::Rlmi::List> rlmi;
 	try {
 		rlmi = Xsd::Rlmi::parseList(data, Xsd::XmlSchema::Flags::dont_validate);
@@ -330,7 +323,7 @@ map<string, IdentityAddress> RemoteConferenceListEventHandler::parseRlmi(const s
 		const string &uri = string(resource.getUri());
 		if (uri.empty()) continue;
 
-		IdentityAddress peer(uri);
+		std::shared_ptr<Address> peer = Address::create(uri);
 		for (const auto &instance : resource.getInstance()) {
 			const string &cid = string(instance.getId());
 			if (cid.empty()) continue;
@@ -355,16 +348,17 @@ void RemoteConferenceListEventHandler::onNetworkReachable(bool sipNetworkReachab
 void RemoteConferenceListEventHandler::onRegistrationStateChanged(LinphoneProxyConfig *cfg,
                                                                   LinphoneRegistrationState state,
                                                                   BCTBX_UNUSED(const std::string &message)) {
-	if (state == LinphoneRegistrationOk) subscribe(cfg->account);
+	const auto &account = Account::toCpp(cfg->account)->getSharedFromThis();
+	if (state == LinphoneRegistrationOk) subscribe(account);
 	else if (state == LinphoneRegistrationCleared) { // On cleared, restart subscription if the cleared proxy config is
 		                                             // the current subscription
 		const LinphoneAddress *cfgAddress = linphone_proxy_config_get_contact(cfg);
 		auto it = std::find_if(levs.begin(), levs.end(), [&cfgAddress](const auto &evSub) {
-			LinphoneAddress *currentAddress = linphone_address_new(evSub->getOp()->getFrom().c_str());
-			return linphone_address_weak_equal(currentAddress, cfgAddress);
+			const auto &currentAddress = evSub->getFrom();
+			return currentAddress->weakEqual(*Address::toCpp(cfgAddress));
 		});
 
-		if (it != levs.end()) unsubscribe(cfg->account);
+		if (it != levs.end()) unsubscribe(account);
 	}
 }
 
diff --git a/src/conference/handlers/remote-conference-list-event-handler.h b/src/conference/handlers/remote-conference-list-event-handler.h
index 54377860341a15a28e76d6eb63fe76ce0c01b65b..85c8eaa7b44c638be208cebdca2e76767d2585ad 100644
--- a/src/conference/handlers/remote-conference-list-event-handler.h
+++ b/src/conference/handlers/remote-conference-list-event-handler.h
@@ -49,9 +49,9 @@ public:
 	~RemoteConferenceListEventHandler();
 
 	void subscribe() override;
-	void subscribe(LinphoneAccount *c_account);
+	void subscribe(const std::shared_ptr<Account> &account);
 	void unsubscribe() override;
-	void unsubscribe(LinphoneAccount *c_account);
+	void unsubscribe(const std::shared_ptr<Account> &account);
 	void invalidateSubscription() override;
 	void notifyReceived(std::string from, const Content *notifyContent);
 	void addHandler(RemoteConferenceEventHandler *handler);
@@ -65,7 +65,7 @@ private:
 	std::unordered_map<ConferenceId, RemoteConferenceEventHandler *> handlers;
 	std::list<std::shared_ptr<EventSubscribe>> levs;
 
-	std::map<std::string, IdentityAddress> parseRlmi(const std::string &xmlBody) const;
+	std::map<std::string, std::shared_ptr<Address>> parseRlmi(const std::string &xmlBody) const;
 
 	// CoreListener
 	void onNetworkReachable(bool sipNetworkReachable, bool mediaNetworkReachable) override;
diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp
index a14b78e1963c32e18f4e926204b177a51918c485..52c3dfc412fb3132210aa36bca047dad359f6cc4 100644
--- a/src/conference/local-conference.cpp
+++ b/src/conference/local-conference.cpp
@@ -48,7 +48,7 @@ LINPHONE_BEGIN_NAMESPACE
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
 LocalConference::LocalConference(const shared_ptr<Core> &core,
-                                 const IdentityAddress &myAddress,
+                                 const std::shared_ptr<Address> &myAddress,
                                  CallSessionListener *listener,
                                  const std::shared_ptr<ConferenceParams> params,
                                  ConferenceListener *confListener)
@@ -87,18 +87,10 @@ std::shared_ptr<Call> LocalConference::getCall() const {
 void LocalConference::subscribeReceived(const shared_ptr<EventSubscribe> &event) {
 #ifdef HAVE_ADVANCED_IM
 	if (event) {
-		const LinphoneAddress *lAddr = event->getFrom();
-		char *addrStr = linphone_address_as_string(lAddr);
-		Address participantAddress(addrStr);
-		bctbx_free(addrStr);
-
+		const auto &participantAddress = event->getFrom();
 		shared_ptr<Participant> participant = findParticipant(participantAddress);
-
 		if (participant) {
-			const LinphoneAddress *lContactAddr = event->getRemoteContact();
-			char *contactAddrStr = linphone_address_as_string(lContactAddr);
-			IdentityAddress contactAddr(contactAddrStr);
-			bctbx_free(contactAddrStr);
+			const auto &contactAddr = event->getRemoteContact();
 			shared_ptr<ParticipantDevice> device = participant->findDevice(contactAddr);
 
 			if (device) {
diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h
index 95b44d9f74ccc0720a3b81e987bde4e7120646a6..44a8a768fea4f34e4ab6816cbba88eb56d67379e 100644
--- a/src/conference/local-conference.h
+++ b/src/conference/local-conference.h
@@ -38,7 +38,7 @@ class LINPHONE_PUBLIC LocalConference : public Conference {
 
 public:
 	LocalConference(const std::shared_ptr<Core> &core,
-	                const IdentityAddress &myAddress,
+	                const std::shared_ptr<Address> &myAddress,
 	                CallSessionListener *listener,
 	                const std::shared_ptr<ConferenceParams> params,
 	                ConferenceListener *confListener = nullptr);
diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp
index 43f7c1fa53abc0ca07e096955c5149e39cbc4463..e842005605c7ad323bcf04cedbfb1bb83d700e70 100644
--- a/src/conference/params/call-session-params.cpp
+++ b/src/conference/params/call-session-params.cpp
@@ -22,9 +22,7 @@
 
 #include "c-wrapper/c-wrapper.h"
 #include "call-session-params-p.h"
-#include "call-session-params.h"
 #include "core/core-p.h"
-
 #include "linphone/core.h"
 #include "linphone/proxy_config.h"
 
diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h
index 589252e479bb629549ba1af53e0eb9105ff531ef..f395ec5f555879d9f589dd4f81254d0e409f17cd 100644
--- a/src/conference/params/call-session-params.h
+++ b/src/conference/params/call-session-params.h
@@ -38,6 +38,10 @@ class Account;
 class CallSessionParamsPrivate;
 class Core;
 
+namespace MediaConference {
+class LocalConference;
+}
+
 class LINPHONE_PUBLIC CallSessionParams : public ClonableObject {
 	friend class Call;
 	friend class CallSession;
@@ -47,6 +51,7 @@ class LINPHONE_PUBLIC CallSessionParams : public ClonableObject {
 	friend class ToneManager;
 	friend class ConferenceScheduler;
 	friend class SalMediaDescriptionParams;
+	friend class MediaConference::LocalConference;
 
 public:
 	CallSessionParams();
diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp
index d526c323c49a160923a7085ed81c633775f94f49..fa746576cdfd59d359ce5b9877450dd6214648b8 100644
--- a/src/conference/participant-device.cpp
+++ b/src/conference/participant-device.cpp
@@ -49,18 +49,19 @@ ParticipantDevice::ParticipantDevice() {
 ParticipantDevice::ParticipantDevice(std::shared_ptr<Participant> participant,
                                      const std::shared_ptr<LinphonePrivate::CallSession> &session,
                                      const std::string &name)
-    : mParticipant(participant), mGruu(participant->getAddress()), mName(name), mSession(session) {
+    : mParticipant(participant), mGruu(Address::create(participant->getAddress()->getUri())), mName(name),
+      mSession(session) {
 	if (mSession && mSession->getRemoteContactAddress()) {
-		setAddress(*mSession->getRemoteContactAddress());
+		setAddress(mSession->getRemoteContactAddress());
 	}
 	updateMediaCapabilities();
 	updateStreamAvailabilities();
 }
 
 ParticipantDevice::ParticipantDevice(std::shared_ptr<Participant> participant,
-                                     const IdentityAddress &gruu,
+                                     const std::shared_ptr<Address> &gruu,
                                      const std::string &name)
-    : mParticipant(participant), mGruu(gruu), mName(name) {
+    : mParticipant(participant), mGruu(Address::create(gruu->getUri())), mName(name) {
 	setStreamCapability(LinphoneMediaDirectionInactive, LinphoneStreamTypeAudio);
 	setStreamCapability(LinphoneMediaDirectionInactive, LinphoneStreamTypeVideo);
 	setStreamCapability(LinphoneMediaDirectionInactive, LinphoneStreamTypeText);
@@ -71,7 +72,7 @@ ParticipantDevice::~ParticipantDevice() {
 }
 
 bool ParticipantDevice::operator==(const ParticipantDevice &device) const {
-	return (getAddress() == device.getAddress());
+	return (*getAddress() == *device.getAddress());
 }
 
 Conference *ParticipantDevice::getConference() const {
@@ -82,25 +83,21 @@ shared_ptr<Core> ParticipantDevice::getCore() const {
 	return getParticipant() ? getParticipant()->getCore() : nullptr;
 }
 
-const IdentityAddress &ParticipantDevice::getAddress() const {
+const std::shared_ptr<Address> &ParticipantDevice::getAddress() const {
 	return mGruu;
 }
 
-void ParticipantDevice::setAddress(const IdentityAddress &address) {
-	setAddress(address.asAddress());
-}
-
-void ParticipantDevice::setAddress(const Address &address) {
-	mGruu = address;
-	if (address.hasParam("+org.linphone.specs")) {
-		const auto &linphoneSpecs = address.getParamValue("+org.linphone.specs");
+void ParticipantDevice::setAddress(const std::shared_ptr<Address> &address) {
+	mGruu = Address::create(address->getUri());
+	if (address->hasParam("+org.linphone.specs")) {
+		const auto &linphoneSpecs = address->getParamValue("+org.linphone.specs");
 		setCapabilityDescriptor(linphoneSpecs.substr(1, linphoneSpecs.size() - 2));
 	}
 }
 
 std::shared_ptr<Participant> ParticipantDevice::getParticipant() const {
 	if (mParticipant.expired()) {
-		lWarning() << "The participant owning device " << getAddress().asString() << " has already been deleted";
+		lWarning() << "The participant owning device " << getAddress()->toString() << " has already been deleted";
 	}
 	shared_ptr<Participant> participant = mParticipant.lock();
 	if (!participant) {
@@ -121,7 +118,7 @@ void ParticipantDevice::setConferenceSubscribeEvent(const shared_ptr<EventSubscr
 
 AbstractChatRoom::SecurityLevel ParticipantDevice::getSecurityLevel() const {
 	auto encryptionEngine = getCore()->getEncryptionEngine();
-	if (encryptionEngine) return encryptionEngine->getSecurityLevel(getAddress().asString());
+	if (encryptionEngine) return encryptionEngine->getSecurityLevel(getAddress()->toString());
 	lWarning() << "Asking device security level but there is no encryption engine enabled";
 	return AbstractChatRoom::SecurityLevel::ClearText;
 }
@@ -175,10 +172,13 @@ bool ParticipantDevice::setSsrc(const LinphoneStreamType type, uint32_t newSsrc)
 	if (changed) {
 		if (conference) {
 			lInfo() << "Setting " << std::string(linphone_stream_type_to_string(type)) << " ssrc of participant device "
-			        << getAddress() << " in conference " << conference->getConferenceAddress() << " to " << newSsrc;
+			        << getAddress()->toString() << " in conference "
+			        << (conference->getConferenceAddress() ? conference->getConferenceAddress()->toString()
+			                                               : std::string("sip:unknown"))
+			        << " to " << newSsrc;
 		} else {
 			lInfo() << "Setting " << std::string(linphone_stream_type_to_string(type)) << " ssrc of participant device "
-			        << getAddress() << " to " << newSsrc;
+			        << *getAddress() << " to " << newSsrc;
 		}
 	}
 
@@ -265,7 +265,8 @@ void ParticipantDevice::setState(State newState, bool notify) {
 		if ((newState == ParticipantDevice::State::Present) && (mState != ParticipantDevice::State::OnHold)) {
 			setTimeOfJoining(time(nullptr));
 		}
-		lInfo() << "Moving participant device " << getAddress() << " from state " << mState << " to " << newState;
+		lInfo() << "Moving participant device " << getAddress()->toString() << " from state " << mState << " to "
+		        << newState;
 		mState = newState;
 		_linphone_participant_device_notify_state_changed(toC(), (LinphoneParticipantDeviceState)newState);
 		const auto &conference = getConference();
@@ -518,13 +519,8 @@ bool ParticipantDevice::updateStreamAvailabilities() {
 				} else {
 					std::shared_ptr<ParticipantDevice> meDev = nullptr;
 					if (conferenceParams.getAccount()) {
-						char *devAddrStr = linphone_account_get_contact_address(conferenceParams.getAccount())
-						                       ? linphone_address_as_string(linphone_account_get_contact_address(
-						                             conferenceParams.getAccount()))
-						                       : nullptr;
-						if (devAddrStr) {
-							Address devAddr(devAddrStr);
-							ms_free(devAddrStr);
+						const auto &devAddr = conferenceParams.getAccount()->getContactAddress();
+						if (devAddr) {
 							meDev = conference->getMe()->findDevice(devAddr);
 						}
 					}
@@ -613,7 +609,7 @@ void *ParticipantDevice::createWindowId() const {
 	if (!mLabel.empty() && session) {
 		windowId = static_pointer_cast<MediaSession>(session)->createNativeVideoWindowId(mLabel);
 	} else {
-		lError() << "Unable to create a window ID for device " << getAddress()
+		lError() << "Unable to create a window ID for device " << *getAddress()
 		         << " because either label is empty (actual " << (mLabel.empty() ? "<not-defined>" : mLabel)
 		         << ") or no session is linked to this device (actual " << session << ")";
 	}
@@ -637,7 +633,7 @@ void ParticipantDevice::setWindowId(void *newWindowId) const {
 			static_pointer_cast<MediaSession>(session)->setNativeVideoWindowId(mWindowId, mLabel);
 		}
 	} else {
-		lError() << "Unable to set window ID for device " << getAddress() << " because either label is empty (actual "
+		lError() << "Unable to set window ID for device " << *getAddress() << " because either label is empty (actual "
 		         << (mLabel.empty() ? "<not-defined>" : mLabel) << ") or no session is linked to this device (actual "
 		         << session << ")";
 	}
diff --git a/src/conference/participant-device.h b/src/conference/participant-device.h
index c838f211c1b1f5d7479da27d2ad482927bd5f6a1..9cdae965e13a3c5e5be0fd37eb2b845fd8e7607a 100644
--- a/src/conference/participant-device.h
+++ b/src/conference/participant-device.h
@@ -28,7 +28,7 @@
 
 #include "conference/conference-enums.h"
 
-#include "address/identity-address.h"
+#include "address/address.h"
 #include "chat/chat-room/abstract-chat-room.h"
 #include "chat/encryption/encryption-engine.h"
 #include "event/event-subscribe.h"
@@ -83,7 +83,7 @@ public:
 	                           const std::shared_ptr<LinphonePrivate::CallSession> &session,
 	                           const std::string &name = "");
 	explicit ParticipantDevice(std::shared_ptr<Participant> participant,
-	                           const IdentityAddress &gruu,
+	                           const std::shared_ptr<Address> &gruu,
 	                           const std::string &name = "");
 	virtual ~ParticipantDevice();
 	// non clonable object
@@ -95,9 +95,8 @@ public:
 
 	std::shared_ptr<Core> getCore() const;
 
-	const IdentityAddress &getAddress() const;
-	void setAddress(const IdentityAddress &address);
-	void setAddress(const Address &address);
+	const std::shared_ptr<Address> &getAddress() const;
+	void setAddress(const std::shared_ptr<Address> &address);
 	inline const std::string &getLabel() const {
 		return mLabel;
 	}
@@ -155,7 +154,7 @@ public:
 	void setConferenceSubscribeEvent(const std::shared_ptr<EventSubscribe> &ev);
 
 	bool isValid() const {
-		return getAddress().isValid();
+		return getAddress() && getAddress()->isValid();
 	}
 	bool isInConference() const;
 
@@ -208,7 +207,7 @@ protected:
 
 private:
 	std::weak_ptr<Participant> mParticipant;
-	IdentityAddress mGruu;
+	std::shared_ptr<Address> mGruu;
 	std::string mName;
 	std::string mLabel;
 	std::shared_ptr<CallSession> mSession;
diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp
index 98167b951b22e0c4062a04eb79d4947091827988..a9c0b33e593fa0e95e5968c3abdaccc1a8a6dff5 100644
--- a/src/conference/participant.cpp
+++ b/src/conference/participant.cpp
@@ -32,13 +32,13 @@ LINPHONE_BEGIN_NAMESPACE
 
 // =============================================================================
 
-Participant::Participant(Conference *conference, const IdentityAddress &address) {
+Participant::Participant(Conference *conference, const std::shared_ptr<Address> &address) {
 	configure(conference, address);
 	creationTime = time(nullptr);
 }
 
 Participant::Participant(Conference *conference,
-                         const IdentityAddress &address,
+                         const std::shared_ptr<Address> &address,
                          std::shared_ptr<CallSession> callSession)
     : Participant(conference, address) {
 	session = callSession;
@@ -47,9 +47,10 @@ Participant::Participant(Conference *conference,
 Participant::Participant() {
 }
 
-void Participant::configure(Conference *conference, const IdentityAddress &address) {
+void Participant::configure(Conference *conference, const std::shared_ptr<Address> &address) {
 	mConference = conference;
-	addr = address.getAddressWithoutGruu();
+	auto identityAddress = Address::create(address->getUriWithoutGruu());
+	addr = identityAddress;
 }
 
 Participant::~Participant() {
@@ -86,25 +87,25 @@ std::shared_ptr<ParticipantDevice> Participant::addDevice(const std::shared_ptr<
 	if (device) return device;
 	if (getCore() && (linphone_core_get_global_state(getCore()->getCCore()) == LinphoneGlobalOn)) {
 		lInfo() << "Add device " << (name.empty() ? "<no-name>" : name) << " with session " << session
-		        << " to participant " << getAddress().asString();
+		        << " to participant " << getAddress()->toString();
 	} else {
 		lDebug() << "Add device " << (name.empty() ? "<no-name>" : name) << " with session " << session
-		         << " to participant " << getAddress().asString();
+		         << " to participant " << getAddress()->toString();
 	}
 	device = ParticipantDevice::create(getSharedFromThis(), session, name);
 	devices.push_back(device);
 	return device;
 }
 
-std::shared_ptr<ParticipantDevice> Participant::addDevice(const IdentityAddress &gruu, const string &name) {
+std::shared_ptr<ParticipantDevice> Participant::addDevice(const std::shared_ptr<Address> &gruu, const string &name) {
 	shared_ptr<ParticipantDevice> device = findDevice(gruu, false);
 	if (device) return device;
 	if (getCore() && (linphone_core_get_global_state(getCore()->getCCore()) == LinphoneGlobalOn)) {
-		lInfo() << "Add device " << (name.empty() ? "<no-name>" : name) << " with address " << gruu.asString()
-		        << " to participant " << getAddress().asString();
+		lInfo() << "Add device " << (name.empty() ? "<no-name>" : name) << " with address " << gruu->toString()
+		        << " to participant " << getAddress()->toString();
 	} else {
-		lDebug() << "Add device " << (name.empty() ? "<no-name>" : name) << " with address " << gruu.asString()
-		         << " to participant " << getAddress().asString();
+		lDebug() << "Add device " << (name.empty() ? "<no-name>" : name) << " with address " << gruu->toString()
+		         << " to participant " << getAddress()->toString();
 	}
 	device = ParticipantDevice::create(getSharedFromThis(), gruu, name);
 	devices.push_back(device);
@@ -121,7 +122,8 @@ shared_ptr<ParticipantDevice> Participant::findDevice(const std::string &label,
 		if (!label.empty() && !deviceLabel.empty() && (deviceLabel.compare(label) == 0)) return device;
 	}
 	if (logFailure) {
-		lInfo() << "Unable to find device with label " << label;
+		lInfo() << "Unable to find device with label " << label << " among those belonging to participant "
+		        << getAddress()->toString();
 	}
 	return nullptr;
 }
@@ -131,26 +133,38 @@ shared_ptr<ParticipantDevice> Participant::findDeviceByCallId(const std::string
 		if (device->getCallId() == callId) return device;
 	}
 	if (logFailure) {
-		lInfo() << "Unable to find device with call id " << callId;
+		lInfo() << "Unable to find device with call id " << callId << " among those belonging to participant "
+		        << getAddress()->toString();
 	}
 	return nullptr;
 }
 
-shared_ptr<ParticipantDevice> Participant::findDevice(const IdentityAddress &gruu, const bool logFailure) const {
-	for (const auto &device : devices) {
-		if (device->getAddress() == gruu) return device;
+shared_ptr<ParticipantDevice> Participant::findDevice(const std::shared_ptr<Address> &gruu,
+                                                      const bool logFailure) const {
+	const auto &it = std::find_if(devices.cbegin(), devices.cend(), [&gruu](const auto &device) {
+		return (device->getAddress()->getUri() == gruu->getUri());
+	});
+
+	if (it != devices.cend()) {
+		return *it;
 	}
+
 	if (logFailure) {
-		lInfo() << "Unable to find device with address " << gruu;
+		lInfo() << "Unable to find device with address " << *gruu << " among those belonging to participant "
+		        << *getAddress();
 	}
 	return nullptr;
 }
 
 shared_ptr<ParticipantDevice> Participant::findDevice(const shared_ptr<const CallSession> &session,
                                                       const bool logFailure) const {
-	for (const auto &device : devices) {
-		if (device->getSession() == session) return device;
+	const auto &it = std::find_if(devices.cbegin(), devices.cend(),
+	                              [&session](const auto &device) { return (device->getSession() == session); });
+
+	if (it != devices.cend()) {
+		return *it;
 	}
+
 	if (logFailure) {
 		lInfo() << "Unable to find device with call session " << session;
 	}
@@ -162,26 +176,18 @@ const list<shared_ptr<ParticipantDevice>> &Participant::getDevices() const {
 }
 
 void Participant::removeDevice(const shared_ptr<const CallSession> &session) {
-	for (auto it = devices.begin(); it != devices.end(); it++) {
-		if ((*it)->getSession() == session) {
-			devices.erase(it);
-			return;
-		}
-	}
+	devices.erase(std::remove_if(devices.begin(), devices.end(),
+	                             [&session](auto &device) { return (device->getSession() == session); }));
 }
 
-void Participant::removeDevice(const IdentityAddress &gruu) {
-	for (auto it = devices.begin(); it != devices.end(); it++) {
-		if ((*it)->getAddress() == gruu) {
-			devices.erase(it);
-			return;
-		}
-	}
+void Participant::removeDevice(const std::shared_ptr<Address> &gruu) {
+	devices.erase(std::remove_if(devices.begin(), devices.end(),
+	                             [&gruu](auto &device) { return (device->getAddress()->getUri() == gruu->getUri()); }));
 }
 
 // -----------------------------------------------------------------------------
 
-const IdentityAddress &Participant::getAddress() const {
+const std::shared_ptr<Address> &Participant::getAddress() const {
 	return addr;
 }
 
@@ -200,10 +206,10 @@ Participant::getSecurityLevelExcept(const std::shared_ptr<ParticipantDevice> &ig
 	std::list<std::string> participantDevices{};
 	// build a list of participants devices address
 	for (const auto &device : getDevices()) {
-		participantDevices.push_back(device->getAddress().asString());
+		participantDevices.push_back(device->getAddress()->toString());
 	}
 	if (ignoredDevice != nullptr) {
-		participantDevices.remove(ignoredDevice->getAddress().asString());
+		participantDevices.remove(ignoredDevice->getAddress()->toString());
 	}
 	if (participantDevices.empty()) {
 		return AbstractChatRoom::SecurityLevel::Safe; // There is no device to query status on, return safe
diff --git a/src/conference/participant.h b/src/conference/participant.h
index f20060ba3b7b631adc46ae366f2472ea62201285..21cf4df75efe067ce22f184db06db3f547627310 100644
--- a/src/conference/participant.h
+++ b/src/conference/participant.h
@@ -26,7 +26,7 @@
 
 #include <belle-sip/object++.hh>
 
-#include "address/identity-address.h"
+#include "address/address.h"
 #include "chat/chat-room/abstract-chat-room.h"
 #include "conference/params/call-session-params.h"
 
@@ -83,9 +83,9 @@ class LINPHONE_PUBLIC Participant : public bellesip::HybridObject<LinphonePartic
 
 public:
 	explicit Participant(Conference *conference,
-	                     const IdentityAddress &address,
+	                     const std::shared_ptr<Address> &address,
 	                     std::shared_ptr<CallSession> callSession);
-	explicit Participant(Conference *conference, const IdentityAddress &address);
+	explicit Participant(Conference *conference, const std::shared_ptr<Address> &address);
 	Participant();
 	virtual ~Participant();
 	// non clonable object
@@ -93,15 +93,16 @@ public:
 		return nullptr;
 	}
 
-	void configure(Conference *conference, const IdentityAddress &address);
+	void configure(Conference *conference, const std::shared_ptr<Address> &address);
 
-	const IdentityAddress &getAddress() const;
+	const std::shared_ptr<Address> &getAddress() const;
 	AbstractChatRoom::SecurityLevel getSecurityLevel() const;
 	AbstractChatRoom::SecurityLevel
 	getSecurityLevelExcept(const std::shared_ptr<ParticipantDevice> &ignoredDevice) const;
 
 	const std::list<std::shared_ptr<ParticipantDevice>> &getDevices() const;
-	std::shared_ptr<ParticipantDevice> findDevice(const IdentityAddress &gruu, const bool logFailure = true) const;
+	std::shared_ptr<ParticipantDevice> findDevice(const std::shared_ptr<Address> &address,
+	                                              const bool logFailure = true) const;
 	std::shared_ptr<ParticipantDevice> findDevice(const std::shared_ptr<const CallSession> &session,
 	                                              const bool logFailure = true) const;
 	std::shared_ptr<ParticipantDevice> findDevice(const std::string &label, const bool logFailure = true) const;
@@ -159,20 +160,20 @@ protected:
 	inline void removeSession() {
 		session.reset();
 	}
-	inline void setAddress(const IdentityAddress &addr) {
+	inline void setAddress(const std::shared_ptr<Address> &addr) {
 		this->addr = addr;
 	}
 
 	std::shared_ptr<ParticipantDevice> addDevice(const std::shared_ptr<LinphonePrivate::CallSession> &session,
 	                                             const std::string &name = "");
-	std::shared_ptr<ParticipantDevice> addDevice(const IdentityAddress &gruu, const std::string &name = "");
+	std::shared_ptr<ParticipantDevice> addDevice(const std::shared_ptr<Address> &address, const std::string &name = "");
 	void clearDevices();
-	void removeDevice(const IdentityAddress &gruu);
+	void removeDevice(const std::shared_ptr<Address> &gruu);
 	void removeDevice(const std::shared_ptr<const CallSession> &session);
 
 private:
 	Conference *mConference = nullptr;
-	IdentityAddress addr;
+	std::shared_ptr<Address> addr;
 	bool isThisAdmin = false;
 	bool isThisFocus = false;
 	std::shared_ptr<CallSession> session;
@@ -186,7 +187,7 @@ private:
 };
 
 inline std::ostream &operator<<(std::ostream &os, const Participant &participant) {
-	return os << participant.getAddress().asString();
+	return os << participant.getAddress()->toString();
 	return os;
 }
 
diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp
index 399ffd7bc7664aa66006e5a1867f6aaf571bab19..c55547f2ac4c2f5d5e1db02136a385d30329d325 100644
--- a/src/conference/remote-conference.cpp
+++ b/src/conference/remote-conference.cpp
@@ -39,7 +39,7 @@ using namespace std;
 LINPHONE_BEGIN_NAMESPACE
 
 RemoteConference::RemoteConference(const shared_ptr<Core> &core,
-                                   const IdentityAddress &myAddress,
+                                   const std::shared_ptr<Address> &myAddress,
                                    CallSessionListener *listener,
                                    const std::shared_ptr<ConferenceParams> params)
     : Conference(core, myAddress, listener, params) {
@@ -69,23 +69,23 @@ bool RemoteConference::isIn() const {
 std::shared_ptr<Call> RemoteConference::getCall() const {
 	auto session = getMainSession();
 	if (session) {
-		return getCore()->getCallByRemoteAddress(*session->getRemoteAddress());
+		return getCore()->getCallByRemoteAddress(session->getRemoteAddress());
 	}
 	return nullptr;
 }
 
 // -----------------------------------------------------------------------------
 
-void RemoteConference::onConferenceCreated(const ConferenceAddress &) {
+void RemoteConference::onConferenceCreated(const std::shared_ptr<Address> &) {
 }
 
-void RemoteConference::onConferenceTerminated(const IdentityAddress &) {
+void RemoteConference::onConferenceTerminated(const std::shared_ptr<Address> &) {
 #ifdef HAVE_ADVANCED_IM
 	eventHandler->unsubscribe();
 #endif
 }
 
-void RemoteConference::onFirstNotifyReceived(const IdentityAddress &) {
+void RemoteConference::onFirstNotifyReceived(const std::shared_ptr<Address> &) {
 }
 
 void RemoteConference::onParticipantAdded(BCTBX_UNUSED(const std::shared_ptr<ConferenceParticipantEvent> &event),
diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h
index 44d20b1fbbf3e0daddb672a0a64d49311e4b018d..74f5a6864ee510d92bd9404c41925fe10fc57435 100644
--- a/src/conference/remote-conference.h
+++ b/src/conference/remote-conference.h
@@ -37,7 +37,7 @@ class LINPHONE_PUBLIC RemoteConference : public Conference, public ConferenceLis
 
 public:
 	RemoteConference(const std::shared_ptr<Core> &core,
-	                 const IdentityAddress &myAddress,
+	                 const std::shared_ptr<Address> &myAddress,
 	                 CallSessionListener *listener,
 	                 const std::shared_ptr<ConferenceParams> params);
 	virtual ~RemoteConference();
@@ -51,9 +51,9 @@ protected:
 #endif // HAVE_ADVANCED_IM
 
 	/* ConferenceListener */
-	void onConferenceCreated(const ConferenceAddress &addr) override;
-	void onConferenceTerminated(const IdentityAddress &addr) override;
-	void onFirstNotifyReceived(const IdentityAddress &addr) override;
+	void onConferenceCreated(const std::shared_ptr<Address> &addr) override;
+	void onConferenceTerminated(const std::shared_ptr<Address> &addr) override;
+	void onFirstNotifyReceived(const std::shared_ptr<Address> &addr) override;
 	void onParticipantAdded(const std::shared_ptr<ConferenceParticipantEvent> &event,
 	                        const std::shared_ptr<Participant> &participant) override;
 	void onParticipantRemoved(const std::shared_ptr<ConferenceParticipantEvent> &event,
diff --git a/src/conference/session/audio-mixer.cpp b/src/conference/session/audio-mixer.cpp
index e9f8c5bbe46388103a344f1b811f3047af44d8cc..3cebd21846da801b2ca504d36c7b9b89d32c4c72 100644
--- a/src/conference/session/audio-mixer.cpp
+++ b/src/conference/session/audio-mixer.cpp
@@ -20,13 +20,12 @@
 
 #include <bctoolbox/defs.h>
 
-#include "mixers.h"
-#include "streams.h"
+#include "mediastreamer2/msvolume.h"
 
 #include "linphone/core.h"
+#include "mixers.h"
 #include "private.h"
-
-#include "mediastreamer2/msvolume.h"
+#include "streams.h"
 
 LINPHONE_BEGIN_NAMESPACE
 
diff --git a/src/conference/session/audio-stream.cpp b/src/conference/session/audio-stream.cpp
index 185ddc1154fc851dcb22bff75da2a30bc937f16b..fde6be816619de87e963ef374b65eaf9ac54105c 100644
--- a/src/conference/session/audio-stream.cpp
+++ b/src/conference/session/audio-stream.cpp
@@ -98,12 +98,12 @@ void MS2AudioStream::configure(BCTBX_UNUSED(const OfferAnswerContext &params)) {
 }
 
 void MS2AudioStream::initZrtp() {
-	auto peerAddr = *(getMediaSession().getRemoteAddress());
-	auto selfAddr = getMediaSession().getLocalAddress();
-	peerAddr.clean();
-	selfAddr.clean();
-	char *peerUri = bctbx_strdup(peerAddr.asStringUriOnly().c_str());
-	char *selfUri = bctbx_strdup(selfAddr.asStringUriOnly().c_str());
+	auto peerAddr = getMediaSession().getRemoteAddress()->clone()->toSharedPtr();
+	auto selfAddr = getMediaSession().getLocalAddress()->clone()->toSharedPtr();
+	peerAddr->clean();
+	selfAddr->clean();
+	char *peerUri = bctbx_strdup(peerAddr->asStringUriOnly().c_str());
+	char *selfUri = bctbx_strdup(selfAddr->asStringUriOnly().c_str());
 
 	MSZrtpParams zrtpParams;
 	zrtpCacheAccess zrtpCacheInfo = linphone_core_get_zrtp_cache_access(getCCore());
diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h
index c9673ef82c485d48e13412d4ec639d21b8a94b76..af0ff22585253d477ff6f528f083345b50679c4c 100644
--- a/src/conference/session/call-session-p.h
+++ b/src/conference/session/call-session-p.h
@@ -52,8 +52,8 @@ public:
 	CallSessionParams *getCurrentParams() const {
 		return currentParams;
 	}
-	LinphoneProxyConfig *getDestProxy() const {
-		return destProxy;
+	const std::shared_ptr<Account> &getDestAccount() const {
+		return account;
 	}
 	SalCallOp *getOp() const {
 		return op;
@@ -80,7 +80,7 @@ public:
 	virtual bool failure();
 	void infoReceived(SalBodyHandler *bodyHandler);
 	void pingReply();
-	void referred(const Address &referToAddr);
+	void referred(const std::shared_ptr<Address> &referToAddr);
 	virtual void remoteRinging();
 	virtual void replaceOp(SalCallOp *newOp);
 	virtual void terminated();
@@ -114,7 +114,8 @@ public:
 	                                   const std::string &subject = "");
 	virtual void terminate();
 	virtual void updateCurrentParams() const;
-	virtual void setDestProxy(LinphoneProxyConfig *proxy); // Set destProxy and update the proxy of currentParams
+	virtual void
+	setDestAccount(const std::shared_ptr<Account> &account); // Set destProxy and update the proxy of currentParams
 
 	void setBroken();
 	void setContactOp();
@@ -134,8 +135,7 @@ protected:
 	CallSessionParams *params = nullptr;
 	mutable CallSessionParams *currentParams = nullptr;
 	CallSessionParams *remoteParams = nullptr;
-	mutable Address diversionAddress;
-	mutable Address remoteContactAddress;
+	mutable std::shared_ptr<Address> diversionAddress;
 
 	std::string subject;
 	LinphoneCallDir direction = LinphoneCallOutgoing;
@@ -146,12 +146,10 @@ protected:
 	CallSession::State lastStableState = CallSession::State::Idle;
 	std::string lastStableMessageState;
 	CallSession::State transferState = CallSession::State::Idle;
-	LinphoneProxyConfig *destProxy = nullptr;
+	std::shared_ptr<Account> account = nullptr;
 	LinphoneErrorInfo *ei = nullptr;
 	std::shared_ptr<CallLog> log = nullptr;
-	std::string referTo;
-	mutable Address referToAddress;
-	mutable Address requestAddress; // cached from the op because we have to return a const reference.
+	std::shared_ptr<Address> referToAddress;
 	// This counter is used to keep active track of reINVITEs and UPDATEs under processing at any given time.
 	// In fact Linphone can have multiple active transaction at the same time on the same dialog as the transaction
 	// queue is popped after receiving the 100 Trying and not the 200 Ok
@@ -179,10 +177,10 @@ protected:
 
 private:
 	void completeLog();
-	void createOpTo(const LinphoneAddress *to);
+	void createOpTo(const std::shared_ptr<Address> &to);
 	void executePendingActions();
 
-	LinphoneAddress *getFixedContact() const;
+	std::shared_ptr<Address> getFixedContact() const;
 
 	void repairIfBroken();
 
diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp
index d3b515858d14730f9517336485fe0cc3053079e5..c863b4d617b57a93b40dcec8a939ba25ba35a544 100644
--- a/src/conference/session/call-session.cpp
+++ b/src/conference/session/call-session.cpp
@@ -122,33 +122,35 @@ void CallSessionPrivate::setState(CallSession::State newState, const string &mes
 					// If there is an active call with the same call ID as the session, then this session may belong to
 					// a conference
 					if (call) {
-						const Address to(op->getTo());
+						const std::shared_ptr<Address> to = Address::create(op->getTo());
 						// Local conference
-						if (to.hasUriParam("conf-id")) {
+						if (to->hasUriParam("conf-id")) {
 							shared_ptr<MediaConference::Conference> conference =
-							    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(
-							        ConferenceId(ConferenceAddress(to), ConferenceAddress(to)));
+							    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findAudioVideoConference(ConferenceId(to, to));
 
 							std::shared_ptr<ConferenceInfo> confInfo = nullptr;
 #ifdef HAVE_DB_STORAGE
 							auto &mainDb = q->getCore()->getPrivate()->mainDb;
 							if (mainDb) {
-								confInfo = mainDb->getConferenceInfoFromURI(ConferenceAddress(to));
+								confInfo = mainDb->getConferenceInfoFromURI(to);
 							}
 #endif
 
 							// If the call is for a conference stored in the core, then accept it automatically without
 							// video
 							if (conference || confInfo) {
-								const auto & resourceList = op->getContentInRemote(ContentType::ResourceLists);
-								const auto dialout = conference && (conference->getCurrentParams().getJoiningMode() == ConferenceParams::JoiningMode::DialOut);
-								if (conference && (resourceList.isEmpty() || ((conference->getOrganizer().asAddress().weakEqual(*(q->getRemoteAddress()))) && dialout))) {
+								const auto &resourceList = op->getContentInRemote(ContentType::ResourceLists);
+								const auto dialout = conference && (conference->getCurrentParams().getJoiningMode() ==
+								                                    ConferenceParams::JoiningMode::DialOut);
+								if (conference &&
+								    (resourceList.isEmpty() ||
+								     ((conference->getOrganizer()->weakEqual(*(q->getRemoteAddress()))) && dialout))) {
 									conference->addParticipant(call);
 								} else {
 									const_cast<LinphonePrivate::CallSessionParamsPrivate *>(
 									    q->getParams()->getPrivate())
 									    ->setInConference(true);
-									setConferenceId(to.getUriParamValue("conf-id"));
+									setConferenceId(to->getUriParamValue("conf-id"));
 								}
 								auto params = linphone_core_create_call_params(lc, call->toC());
 								linphone_call_params_enable_audio(params, TRUE);
@@ -171,17 +173,16 @@ void CallSessionPrivate::setState(CallSession::State newState, const string &mes
 								linphone_call_params_unref(params);
 							}
 						} else if (op->getRemoteContactAddress()) {
-							char *remoteContactAddressStr = sal_address_as_string(op->getRemoteContactAddress());
-							Address remoteContactAddress(remoteContactAddressStr);
-							ms_free(remoteContactAddressStr);
-							if (remoteContactAddress.hasParam("isfocus")) {
+							std::shared_ptr<Address> remoteContactAddress = Address::create();
+							remoteContactAddress->setImpl(op->getRemoteContactAddress());
+							if (remoteContactAddress->hasParam("isfocus")) {
 								const auto &conferenceInfo = Utils::createConferenceInfoFromOp(op, true);
-								if (conferenceInfo->getUri().isValid()) {
+								if (conferenceInfo->getUri()->isValid()) {
 #ifdef HAVE_DB_STORAGE
 									auto &mainDb = q->getCore()->getPrivate()->mainDb;
 									if (mainDb) {
 										lInfo() << "Inserting conference information to database related to conference "
-										        << conferenceInfo->getUri();
+										        << *conferenceInfo->getUri();
 										mainDb->insertConferenceInfo(conferenceInfo);
 									}
 #endif // HAVE_DB_STORAGE
@@ -339,12 +340,12 @@ bool CallSessionPrivate::startPing() {
 		if (direction == LinphoneCallIncoming) {
 			string from = pingOp->getFrom();
 			string to = pingOp->getTo();
-			linphone_configure_op(q->getCore()->getCCore(), pingOp, log->getFromAddress(), nullptr, false);
+			linphone_configure_op(q->getCore()->getCCore(), pingOp, log->getFromAddress()->toC(), nullptr, false);
 			pingOp->setRoute(op->getNetworkOrigin());
 			pingOp->ping(from.c_str(), to.c_str());
 		} else if (direction == LinphoneCallOutgoing) {
-			char *from = linphone_address_as_string(log->getFromAddress());
-			char *to = linphone_address_as_string(log->getToAddress());
+			char *from = ms_strdup(L_STRING_TO_C(log->getFromAddress()->toString()));
+			char *to = ms_strdup(L_STRING_TO_C(log->getToAddress()->toString()));
 			pingOp->ping(from, to);
 			ms_free(from);
 			ms_free(to);
@@ -427,10 +428,10 @@ bool CallSessionPrivate::failure() {
 			    (state == CallSession::State::OutgoingEarlyMedia)) {
 				const SalAddress *redirectionTo = op->getRemoteContactAddress();
 				if (redirectionTo) {
-					char *url = sal_address_as_string(redirectionTo);
-					lWarning() << "Redirecting CallSession [" << q << "] to " << url;
-					log->setToAddress(linphone_address_new(url));
-					ms_free(url);
+					std::shared_ptr<Address> redirectAddress = Address::create();
+					redirectAddress->setImpl(redirectionTo);
+					lWarning() << "Redirecting CallSession [" << q << "] to " << redirectAddress->toString();
+					log->setToAddress(redirectAddress);
 					restartInvite();
 					return true;
 				}
@@ -506,10 +507,9 @@ void CallSessionPrivate::pingReply() {
 	}
 }
 
-void CallSessionPrivate::referred(const Address &referToAddr) {
+void CallSessionPrivate::referred(const std::shared_ptr<Address> &referToAddr) {
 	L_Q();
 	referToAddress = referToAddr;
-	referTo = referToAddr.asString();
 	referPending = true;
 	setState(CallSession::State::Referred, "Referred");
 	if (referPending && listener) listener->onCallSessionStartReferred(q->getSharedFromThis());
@@ -872,29 +872,11 @@ LinphoneStatus CallSessionPrivate::startUpdate(const CallSession::UpdateMethod m
 			else newSubject = CallSession::predefinedSubject.at(CallSession::PredefinedSubjectType::MediaChange);
 		}
 	}
-	char *contactAddressStr = NULL;
-	if (destProxy) {
-		if (linphone_proxy_config_get_op(destProxy)) {
-			/* Give a chance to update the contact address if connectivity has changed */
-			contactAddressStr = sal_address_as_string(linphone_proxy_config_get_op(destProxy)->getContactAddress());
-
-		} else if (linphone_core_conference_server_enabled(q->getCore()->getCCore()) &&
-		           linphone_proxy_config_get_contact(destProxy)) {
-			contactAddressStr = linphone_address_as_string(linphone_proxy_config_get_contact(destProxy));
-		}
-	} else {
-		op->setContactAddress(nullptr);
-	}
 
 	// Update custom headers
 	op->setSentCustomHeaders(params->getPrivate()->getCustomHeaders());
 
-	if (contactAddressStr) {
-		Address contactAddress(contactAddressStr);
-		ms_free(contactAddressStr);
-		q->updateContactAddress(contactAddress);
-		op->setContactAddress(contactAddress.getInternalAddress());
-	} else op->setContactAddress(nullptr);
+	q->updateContactAddressInOp();
 
 	bool noUserConsent = q->getParams()->getPrivate()->getNoUserConsent();
 	if (method != CallSession::UpdateMethod::Default) {
@@ -925,9 +907,9 @@ void CallSessionPrivate::terminate() {
 void CallSessionPrivate::updateCurrentParams() const {
 }
 
-void CallSessionPrivate::setDestProxy(LinphoneProxyConfig *proxy) {
-	destProxy = proxy;
-	currentParams->setAccount(proxy ? Account::toCpp(proxy->account)->getSharedFromThis() : nullptr);
+void CallSessionPrivate::setDestAccount(const shared_ptr<Account> &destAccount) {
+	account = destAccount;
+	params->setAccount(account);
 }
 
 // -----------------------------------------------------------------------------
@@ -963,34 +945,29 @@ void CallSessionPrivate::setBroken() {
 
 void CallSessionPrivate::setContactOp() {
 	L_Q();
-	LinphoneAddress *contact = getFixedContact();
-	if (contact) {
+	auto contactAddress = getFixedContact();
+	// Do not try to set contact address if it is not valid
+	if (contactAddress && contactAddress->isValid()) {
 		auto contactParams = q->getParams()->getPrivate()->getCustomContactParameters();
 		for (auto it = contactParams.begin(); it != contactParams.end(); it++)
-			linphone_address_set_param(contact, it->first.c_str(), it->second.empty() ? nullptr : it->second.c_str());
-		char *contactAddressStr = linphone_address_as_string(contact);
-		Address contactAddress(contactAddressStr);
-		ms_free(contactAddressStr);
-		// Do not try to set contact address if it is not valid
-		if (contactAddress.isValid()) {
-			q->updateContactAddress(contactAddress);
-			if (isInConference()) {
-				std::shared_ptr<MediaConference::Conference> conference =
-				    q->getCore()->findAudioVideoConference(ConferenceId(contactAddress, contactAddress));
-				if (conference) {
-					// Try to change conference address in order to add GRUU to it
-					// Note that this operation may fail if the conference was previously created on the server
-					conference->setConferenceAddress(contactAddress);
-				}
+			contactAddress->setParam(it->first, it->second);
+		q->updateContactAddress(*contactAddress);
+		if (isInConference()) {
+			std::shared_ptr<MediaConference::Conference> conference =
+			    q->getCore()->findAudioVideoConference(ConferenceId(contactAddress, contactAddress));
+			if (conference) {
+				// Try to change conference address in order to add GRUU to it
+				// Note that this operation may fail if the conference was previously created on the server
+				conference->setConferenceAddress(contactAddress);
 			}
-
-			lInfo() << "Setting contact address for session " << this << " to " << contactAddress.asString();
-			op->setContactAddress(contactAddress.getInternalAddress());
-		} else {
-			lWarning() << "Unable to set contact address for session " << this << " to " << contactAddress.asString()
-			           << " as it is not valid";
 		}
-		linphone_address_unref(contact);
+
+		lInfo() << "Setting contact address for session " << this << " to " << *contactAddress;
+		op->setContactAddress(contactAddress->getImpl());
+	} else {
+		lWarning() << "Unable to set contact address for session " << this << " to "
+		           << ((contactAddress) ? contactAddress->toString() : std::string("<unknown>"))
+		           << " as it is not valid";
 	}
 }
 
@@ -1006,7 +983,8 @@ void CallSessionPrivate::onRegistrationStateChanged(LinphoneProxyConfig *cfg,
                                                     BCTBX_UNUSED(const std::string &message)) {
 	// might be better to add callbacks on Account, but due to the lake of internal listener, it is dangerous to expose
 	// internal listeners to public object.
-	if (cfg == destProxy && cstate == LinphoneRegistrationOk) repairIfBroken();
+	const auto registeredChangedAccount = cfg ? Account::toCpp(cfg->account)->getSharedFromThis() : nullptr;
+	if (registeredChangedAccount == getDestAccount() && cstate == LinphoneRegistrationOk) repairIfBroken();
 	/*else
 	    only repair call when the right proxy is in state connected*/
 }
@@ -1022,7 +1000,7 @@ void CallSessionPrivate::completeLog() {
 	q->getCore()->reportConferenceCallEvent(EventLog::Type::ConferenceCallEnded, log, nullptr);
 }
 
-void CallSessionPrivate::createOpTo(const LinphoneAddress *to) {
+void CallSessionPrivate::createOpTo(const std::shared_ptr<Address> &to) {
 	L_Q();
 	if (op) op->release();
 
@@ -1031,7 +1009,7 @@ void CallSessionPrivate::createOpTo(const LinphoneAddress *to) {
 	op = new SalCallOp(core->sal.get(), q->isCapabilityNegotiationEnabled());
 	op->setUserPointer(q);
 	if (params->getPrivate()->getReferer()) op->setReferrer(params->getPrivate()->getReferer()->getPrivate()->getOp());
-	linphone_configure_op(core, op, to, q->getParams()->getPrivate()->getCustomHeaders(), false);
+	linphone_configure_op(core, op, to->toC(), q->getParams()->getPrivate()->getCustomHeaders(), false);
 	if (q->getParams()->getPrivacy() != LinphonePrivacyDefault)
 		op->setPrivacy((SalPrivacyMask)q->getParams()->getPrivacy());
 	/* else privacy might be set by proxy */
@@ -1039,42 +1017,42 @@ void CallSessionPrivate::createOpTo(const LinphoneAddress *to) {
 
 // -----------------------------------------------------------------------------
 
-LinphoneAddress *CallSessionPrivate::getFixedContact() const {
+std::shared_ptr<Address> CallSessionPrivate::getFixedContact() const {
 	L_Q();
-	LinphoneAddress *result = nullptr;
+	std::shared_ptr<Address> result = nullptr;
+	const auto &account = getDestAccount();
 	if (op && op->getContactAddress()) {
 		/* If already choosed, don't change it */
 		return nullptr;
 	} else if (pingOp && pingOp->getContactAddress()) {
 		/* If the ping OPTIONS request succeeded use the contact guessed from the received, rport */
 		lInfo() << "Contact has been fixed using OPTIONS";
-		char *addr = sal_address_as_string(pingOp->getContactAddress());
-		result = linphone_address_new(addr);
-		ms_free(addr);
+		result = Address::create();
+		result->setImpl(pingOp->getContactAddress());
 		return result;
-	} else if (destProxy) {
-		const LinphoneAddress *addr = NULL;
-		if (linphone_proxy_config_get_contact(destProxy)) {
-			addr = linphone_proxy_config_get_contact(destProxy);
+	} else if (account) {
+		shared_ptr<Address> addr = nullptr;
+		const auto &accountContactAddress = account->getContactAddress();
+		if (accountContactAddress) {
+			addr = accountContactAddress;
 		} else {
 			lError() << "Unable to retrieve contact address from proxy confguration for call session " << q
-			         << " (local address " << q->getLocalAddress().asString() << " remote address "
-			         << (q->getRemoteAddress() ? q->getRemoteAddress()->asString() : "Unknown") << ").";
+			         << " (local address " << q->getLocalAddress()->toString() << " remote address "
+			         << (q->getRemoteAddress() ? q->getRemoteAddress()->toString() : "Unknown") << ").";
 		}
-		if (addr &&
-		    (linphone_proxy_config_get_op(destProxy) || (linphone_proxy_config_get_dependency(destProxy) != nullptr) ||
-		     linphone_core_conference_server_enabled(q->getCore()->getCCore()))) {
+		if (addr && (account->getOp() || (account->getDependency() != nullptr) ||
+		             linphone_core_conference_server_enabled(q->getCore()->getCCore()))) {
 			/* If using a proxy, use the contact address as guessed with the REGISTERs */
 			lInfo() << "Contact has been fixed using proxy";
-			result = linphone_address_clone(addr);
+			result = addr->clone()->toSharedPtr();
 			return result;
 		}
 	}
-	result = linphone_core_get_primary_contact_parsed(q->getCore()->getCCore());
+	result = Address::toCpp(linphone_core_get_primary_contact_parsed(q->getCore()->getCCore()))->toSharedPtr();
 	if (result) {
 		/* Otherwise use supplied localip */
-		linphone_address_set_domain(result, nullptr /* localip */);
-		linphone_address_set_port(result, -1 /* linphone_core_get_sip_port(core) */);
+		result->setDomain(std::string() /* localip */);
+		result->setPort(-1 /* linphone_core_get_sip_port(core) */);
 		lInfo() << "Contact has not been fixed, stack will do";
 	}
 	return result;
@@ -1122,12 +1100,12 @@ void CallSessionPrivate::repairIfBroken() {
 	// attempt to repair it
 
 	// Make sure that the proxy from which we received this call, or to which we routed this call is registered first
-	if (destProxy) {
+	const auto &account = getDestAccount();
+	if (account) {
 		// In all other cases, ie no proxy config, or a proxy config for which no registration was requested,
 		// we can start the call session repair immediately.
-		if (linphone_proxy_config_register_enabled(destProxy) &&
-		    (linphone_proxy_config_get_state(destProxy) != LinphoneRegistrationOk))
-			return;
+		const auto accountParams = account->getAccountParams();
+		if (accountParams->getRegisterEnabled() && (account->getState() != LinphoneRegistrationOk)) return;
 	}
 
 	SalErrorInfo sei;
@@ -1254,28 +1232,16 @@ LinphoneStatus CallSession::acceptUpdate(const CallSessionParams *csp) {
 	return d->acceptUpdate(csp, d->prevState, Utils::toString(d->prevState));
 }
 
-LinphoneProxyConfig *CallSession::getDestProxy() {
-	L_D();
-	return d->destProxy;
-}
-
-void CallSession::configure(
-    LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) {
+void CallSession::configure(LinphoneCallDir direction,
+                            LinphoneProxyConfig *cfg,
+                            SalCallOp *op,
+                            const std::shared_ptr<Address> &from,
+                            const std::shared_ptr<Address> &to) {
 	L_D();
 	d->direction = direction;
-	d->setDestProxy(cfg);
-	LinphoneAddress *fromAddr = linphone_address_new(from.asString().c_str());
-	LinphoneAddress *toAddr = linphone_address_new(to.asString().c_str());
+	d->log = CallLog::create(getCore(), direction, from, to);
 
 	const auto &core = getCore()->getCCore();
-	if (!d->destProxy) {
-		/* Try to define the destination proxy if it has not already been done to have a correct contact field in the
-		 * SIP messages */
-		d->setDestProxy(linphone_core_lookup_known_proxy(core, toAddr));
-	}
-
-	d->log = CallLog::create(getCore(), direction, fromAddr, toAddr);
-
 	if (op) {
 		/* We already have an op for incoming calls */
 		d->op = op;
@@ -1294,6 +1260,18 @@ void CallSession::configure(
 		d->setParams(new CallSessionParams());
 		d->params->initDefault(getCore(), LinphoneCallIncoming);
 	}
+
+	d->setDestAccount(cfg ? Account::toCpp(cfg->account)->getSharedFromThis() : nullptr);
+	if (!d->getDestAccount()) {
+		/* Try to define the destination proxy if it has not already been done to have a correct contact field in the
+		 * SIP messages */
+		LinphoneAddress *toAddr = to->toC();
+		const auto cAccount = linphone_core_lookup_account_by_identity(core, toAddr);
+		if (cAccount) {
+			const auto account = cAccount ? Account::toCpp(cAccount)->getSharedFromThis() : nullptr;
+			d->setDestAccount(account);
+		}
+	}
 }
 
 void CallSession::configure(LinphoneCallDir direction, const string &callid) {
@@ -1301,8 +1279,8 @@ void CallSession::configure(LinphoneCallDir direction, const string &callid) {
 	d->direction = direction;
 
 	// Keeping a valid address while following https://www.ietf.org/rfc/rfc3323.txt guidelines.
-	d->log = CallLog::create(getCore(), direction, linphone_address_new("Anonymous <sip:anonymous@anonymous.invalid>"),
-	                         linphone_address_new("Anonymous <sip:anonymous@anonymous.invalid>"));
+	const auto anonymous = Address::create("Anonymous <sip:anonymous@anonymous.invalid>");
+	d->log = CallLog::create(getCore(), direction, anonymous, anonymous);
 	d->log->setCallId(callid);
 }
 
@@ -1419,7 +1397,7 @@ bool CallSession::initiateOutgoing(BCTBX_UNUSED(const string &subject), BCTBX_UN
 	L_D();
 	bool defer = false;
 	d->setState(CallSession::State::OutgoingInit, "Starting outgoing call");
-	if (!d->destProxy) defer = d->startPing();
+	if (!d->getDestAccount()) defer = d->startPing();
 	return defer;
 }
 
@@ -1447,13 +1425,13 @@ void CallSession::iterate(time_t currentRealTime, bool oneSecondElapsed) {
 }
 
 LinphoneStatus CallSession::redirect(const string &redirectUri) {
-	Address address(getCore()->interpretUrl(redirectUri, true));
-	if (!address.isValid()) {
+	auto address = getCore()->interpretUrl(redirectUri, true);
+	if (!address || !address->isValid()) {
 		/* Bad url */
 		lError() << "Bad redirect URI: " << redirectUri;
 		return -1;
 	}
-	return redirect(address);
+	return redirect(*address);
 }
 
 LinphoneStatus CallSession::redirect(const Address &redirectAddr) {
@@ -1466,7 +1444,7 @@ LinphoneStatus CallSession::redirect(const Address &redirectAddr) {
 	memset(&sei, 0, sizeof(sei));
 	sal_error_info_set(&sei, SalReasonRedirect, "SIP", 0, nullptr, nullptr);
 	d->op->declineWithErrorInfo(
-	    &sei, redirectAddr.getInternalAddress(),
+	    &sei, redirectAddr.getImpl(),
 	    ((getParams()->getPrivate()->getEndTime() < 0) ? 0 : getParams()->getPrivate()->getEndTime()));
 	linphone_error_info_set(d->ei, nullptr, LinphoneReasonMovedPermanently, 302, "Call redirected", nullptr);
 	d->nonOpError = true;
@@ -1509,20 +1487,18 @@ void CallSession::startPushIncomingNotification() {
 	d->setState(CallSession::State::PushIncomingReceived, "Push notification received");
 }
 
-int CallSession::startInvite(const Address *destination, const string &subject, const Content *content) {
+int CallSession::startInvite(const std::shared_ptr<Address> &destination,
+                             const string &subject,
+                             const Content *content) {
 	L_D();
 	d->subject = subject;
 	/* Try to be best-effort in giving real local or routable contact address */
 	d->setContactOp();
 	string destinationStr;
-	char *realUrl = nullptr;
-	if (destination) destinationStr = destination->asString();
+	if (destination) destinationStr = destination->toString();
 	else {
-		realUrl = linphone_address_as_string(d->log->getToAddress());
-		destinationStr = realUrl;
-		ms_free(realUrl);
+		destinationStr = d->log->getToAddress()->toString();
 	}
-	char *from = linphone_address_as_string(d->log->getFromAddress());
 	/* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */
 	shared_ptr<CallSession> ref = getSharedFromThis();
 	if (content) {
@@ -1534,8 +1510,7 @@ int CallSession::startInvite(const Address *destination, const string &subject,
 		d->op->addAdditionalLocalBody(content);
 	}
 
-	int result = d->op->call(from, destinationStr, subject);
-	ms_free(from);
+	int result = d->op->call(d->log->getFromAddress()->toString().c_str(), destinationStr, subject);
 	if (result < 0) {
 		if ((d->state != CallSession::State::Error) && (d->state != CallSession::State::Released)) {
 			// sal_call() may invoke call_failure() and call_released() SAL callbacks synchronously,
@@ -1595,19 +1570,19 @@ LinphoneStatus CallSession::transfer(const shared_ptr<CallSession> &dest) {
 	return result;
 }
 
-LinphoneStatus CallSession::transfer(const Address &address) {
+LinphoneStatus CallSession::transfer(const std::shared_ptr<Address> &address) {
 	L_D();
-	if (!address.isValid()) {
-		lError() << "Received invalid address " << address.asString() << " to transfer the call to";
+	if (!address || !address->isValid()) {
+		lError() << "Received invalid address " << address->toString() << " to transfer the call to";
 		return -1;
 	}
-	d->op->refer(address.asString().c_str());
+	d->op->refer(address->toString().c_str());
 	d->setTransferState(CallSession::State::OutgoingInit);
 	return 0;
 }
 
 LinphoneStatus CallSession::transfer(const string &dest) {
-	Address address(getCore()->interpretUrl(dest, true));
+	std::shared_ptr<Address> address(getCore()->interpretUrl(dest, true));
 	return transfer(address);
 }
 
@@ -1640,16 +1615,14 @@ LinphoneCallDir CallSession::getDirection() const {
 	return d->direction;
 }
 
-const Address &CallSession::getDiversionAddress() const {
+const std::shared_ptr<Address> CallSession::getDiversionAddress() const {
 	L_D();
+
+	std::shared_ptr<Address> diversionAddress = Address::create();
 	if (d->op && d->op->getDiversionAddress()) {
-		char *addrStr = sal_address_as_string(d->op->getDiversionAddress());
-		d->diversionAddress = Address(addrStr);
-		bctbx_free(addrStr);
-	} else {
-		d->diversionAddress = Address();
+		diversionAddress->setImpl(d->op->getDiversionAddress());
 	}
-	return d->diversionAddress;
+	return diversionAddress;
 }
 
 int CallSession::getDuration() const {
@@ -1670,13 +1643,19 @@ const LinphoneErrorInfo *CallSession::getErrorInfo() const {
 	return d->ei;
 }
 
-const Address &CallSession::getLocalAddress() const {
+const std::shared_ptr<Address> CallSession::getLocalAddress() const {
 	L_D();
-	return (d->direction == LinphoneCallIncoming)
-	           ? (d->log->getToAddress() ? *L_GET_CPP_PTR_FROM_C_OBJECT(d->log->getToAddress())
-	                                     : Utils::getEmptyConstRefObject<Address>())
-	           : (d->log->getFromAddress() ? *L_GET_CPP_PTR_FROM_C_OBJECT(d->log->getFromAddress())
-	                                       : Utils::getEmptyConstRefObject<Address>());
+	std::shared_ptr<Address> addr = nullptr;
+	if (d->direction == LinphoneCallIncoming) {
+		if (d->log->getToAddress()) {
+			addr = d->log->getToAddress();
+		}
+	} else {
+		if (d->log->getFromAddress()) {
+			addr = d->log->getFromAddress();
+		}
+	}
+	return addr;
 }
 
 shared_ptr<CallLog> CallSession::getLog() const {
@@ -1684,28 +1663,24 @@ shared_ptr<CallLog> CallSession::getLog() const {
 	return d->log;
 }
 
-Address CallSession::getContactAddress() const {
+const std::shared_ptr<Address> CallSession::getContactAddress() const {
 	L_D();
 	const auto op = d->getOp();
-	const auto destProxy = d->getDestProxy();
-	char *contactAddressStr = NULL;
-	if (op->getContactAddress()) {
-		contactAddressStr = sal_address_as_string(op->getContactAddress());
-	} else if (linphone_core_conference_server_enabled(getCore()->getCCore()) && destProxy &&
-	           linphone_proxy_config_get_contact(destProxy)) {
-		contactAddressStr = linphone_address_as_string(linphone_proxy_config_get_contact(destProxy));
+	const auto &account = d->getDestAccount();
+	const auto &accountContactAddress = (account) ? account->getContactAddress() : nullptr;
+	std::shared_ptr<Address> contactAddress = nullptr;
+	if (op && op->getContactAddress()) {
+		contactAddress = Address::create();
+		contactAddress->setImpl(op->getContactAddress());
+	} else if (linphone_core_conference_server_enabled(getCore()->getCCore()) && account && accountContactAddress) {
+		contactAddress = Address::create();
+		contactAddress = accountContactAddress->clone()->toSharedPtr();
 	} else {
 		lError() << "Unable to retrieve contact address from proxy confguration for call session " << this
-		         << " (local address " << getLocalAddress().asString() << " remote address "
-		         << (getRemoteAddress() ? getRemoteAddress()->asString() : "Unknown") << ").";
-	}
-	if (contactAddressStr) {
-		Address contactAddress(contactAddressStr);
-		updateContactAddress(contactAddress);
-		ms_free(contactAddressStr);
-		return contactAddress;
+		         << " (local address " << *getLocalAddress() << " remote address "
+		         << (getRemoteAddress() ? getRemoteAddress()->toString() : "Unknown") << ").";
 	}
-	return Address();
+	return contactAddress;
 }
 
 LinphoneReason CallSession::getReason() const {
@@ -1717,21 +1692,22 @@ shared_ptr<CallSession> CallSession::getReferer() const {
 	return d->referer;
 }
 
-const string &CallSession::getReferTo() const {
+const string CallSession::getReferTo() const {
 	L_D();
-	return d->referTo;
+	if (d->referToAddress) {
+		return d->referToAddress->toString();
+	}
+	return std::string();
 }
 
-const Address &CallSession::getReferToAddress() const {
+const std::shared_ptr<Address> &CallSession::getReferToAddress() const {
 	L_D();
 	return d->referToAddress;
 }
 
-const Address *CallSession::getRemoteAddress() const {
+const std::shared_ptr<Address> CallSession::getRemoteAddress() const {
 	L_D();
-	const LinphoneAddress *address =
-	    (d->direction == LinphoneCallIncoming) ? d->log->getFromAddress() : d->log->getToAddress();
-	return address ? L_GET_CPP_PTR_FROM_C_OBJECT(address) : nullptr;
+	return (d->direction == LinphoneCallIncoming) ? d->log->getFromAddress() : d->log->getToAddress();
 }
 
 const string &CallSession::getRemoteContact() const {
@@ -1743,18 +1719,19 @@ const string &CallSession::getRemoteContact() const {
 	return Utils::getEmptyConstRefObject<string>();
 }
 
-const Address *CallSession::getRemoteContactAddress() const {
+const std::shared_ptr<Address> CallSession::getRemoteContactAddress() const {
 	L_D();
-	if (!d->op) {
+	auto op = d->op;
+	if (!op) {
 		return nullptr;
 	}
-	if (!d->op->getRemoteContactAddress()) {
+	auto salRemoteContactAddress = op->getRemoteContactAddress();
+	if (!salRemoteContactAddress) {
 		return nullptr;
 	}
-	char *addrStr = sal_address_as_string(d->op->getRemoteContactAddress());
-	d->remoteContactAddress = Address(addrStr);
-	bctbx_free(addrStr);
-	return &d->remoteContactAddress;
+	std::shared_ptr<Address> remoteContactAddress = Address::create();
+	remoteContactAddress->setImpl(salRemoteContactAddress);
+	return remoteContactAddress;
 }
 
 const CallSessionParams *CallSession::getRemoteParams() {
@@ -1790,17 +1767,19 @@ CallSession::State CallSession::getLastStableState() const {
 	return d->lastStableState;
 }
 
-const Address &CallSession::getToAddress() const {
+const std::shared_ptr<Address> CallSession::getToAddress() const {
 	L_D();
-	return *L_GET_CPP_PTR_FROM_C_OBJECT(d->log->getToAddress());
+	return d->log->getToAddress();
 }
 
-const Address &CallSession::getRequestAddress() const {
+const std::shared_ptr<Address> CallSession::getRequestAddress() const {
 	L_D();
 	if (d->op) {
-		d->requestAddress = d->op->getRequestAddress();
-	} else d->requestAddress = Address();
-	return d->requestAddress;
+		std::shared_ptr<Address> addr = Address::create();
+		addr->setImpl(d->op->getRequestAddress());
+		return addr;
+	}
+	return nullptr;
 }
 
 CallSession::State CallSession::getTransferState() const {
@@ -1910,29 +1889,26 @@ void CallSession::updateContactAddress(Address &contactAddress) const {
 		isAdmin = me->isAdmin();
 		contactAddress.setParam("admin", Utils::toString(isAdmin));
 	} else {
-		IdentityAddress organizer = IdentityAddress();
+		std::shared_ptr<Address> organizer;
 		const auto sipfrag = d->op ? d->op->getContentInRemote(ContentType::SipFrag) : Content();
 		const auto &remoteContactSalAddress = d->op ? d->op->getRemoteContactAddress() : nullptr;
 
-		auto guessedConferenceAddress = ConferenceAddress();
+		std::shared_ptr<Address> guessedConferenceAddress = Address::create();
 
 		// If remote contact address is not yet available, try with remote address
 		if (remoteContactSalAddress) {
-			auto remoteContactAddressStr = sal_address_as_string(remoteContactSalAddress);
-			Address remoteContactAddress(remoteContactAddressStr);
-			ms_free(remoteContactAddressStr);
-			if ((!sipfrag.isEmpty()) && remoteContactAddress.hasParam("isfocus")) {
+			guessedConferenceAddress->setImpl(remoteContactSalAddress);
+			if ((!sipfrag.isEmpty()) && guessedConferenceAddress->hasParam("isfocus")) {
 				auto organizerId = Utils::getSipFragAddress(sipfrag);
-				organizer = IdentityAddress(organizerId);
+				organizer = Address::create(organizerId);
 			}
-			guessedConferenceAddress = ConferenceAddress(remoteContactAddress);
 		} else {
-			guessedConferenceAddress = ConferenceAddress(*getRemoteAddress());
+			guessedConferenceAddress = getRemoteAddress();
 		}
 
 #ifdef HAVE_DB_STORAGE
 		auto &mainDb = getCore()->getPrivate()->mainDb;
-		if (mainDb && (guessedConferenceAddress != ConferenceAddress())) {
+		if (mainDb && guessedConferenceAddress) {
 			const auto &confInfo = mainDb->getConferenceInfoFromURI(guessedConferenceAddress);
 			if (confInfo) {
 				organizer = confInfo->getOrganizerAddress();
@@ -1940,13 +1916,39 @@ void CallSession::updateContactAddress(Address &contactAddress) const {
 		}
 #endif
 
-		if (organizer != IdentityAddress()) {
-			isAdmin = (organizer == getLocalAddress());
+		if (organizer) {
+			const auto localAddress = getLocalAddress();
+			isAdmin = (organizer->weakEqual(*localAddress));
 			contactAddress.setParam("admin", Utils::toString(isAdmin));
 		}
 	}
 }
 
+void CallSession::updateContactAddressInOp() {
+	L_D();
+	Address contactAddress;
+	const auto &account = d->getDestAccount();
+	if (account) {
+		const auto &accountOp = account->getOp();
+		const auto &accountContactAddress = account->getContactAddress();
+		if (accountOp) {
+			/* Give a chance to update the contact address if connectivity has changed */
+			contactAddress.setImpl(accountOp->getContactAddress());
+
+		} else if (linphone_core_conference_server_enabled(getCore()->getCCore()) && accountContactAddress) {
+			contactAddress = *accountContactAddress;
+		}
+
+	} else if (d->op && d->op->getContactAddress()) {
+		contactAddress.setImpl(d->op->getContactAddress());
+	} else {
+		contactAddress = Address(linphone_core_get_identity(getCore()->getCCore()));
+	}
+
+	updateContactAddress(contactAddress);
+	d->op->setContactAddress(contactAddress.getImpl());
+}
+
 void CallSession::addPendingAction(std::function<LinphoneStatus()> f) {
 	L_D();
 	d->pendingActions.push(f);
diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h
index 65c49c7223f0e0208216219be1f8b025a7f0da96..ff9f31d6450b2951b8eae48bb835d02ec82ab37b 100644
--- a/src/conference/session/call-session.h
+++ b/src/conference/session/call-session.h
@@ -111,9 +111,11 @@ public:
 	virtual void acceptDefault();
 	LinphoneStatus accept(const CallSessionParams *csp = nullptr);
 	LinphoneStatus acceptUpdate(const CallSessionParams *csp = nullptr);
-	virtual void configure(
-	    LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to);
-	LinphoneProxyConfig *getDestProxy();
+	virtual void configure(LinphoneCallDir direction,
+	                       LinphoneProxyConfig *cfg,
+	                       SalCallOp *op,
+	                       const std::shared_ptr<Address> &from,
+	                       const std::shared_ptr<Address> &to);
 	void configure(LinphoneCallDir direction, const std::string &callid);
 	bool isOpConfigured();
 	LinphoneStatus decline(LinphoneReason reason);
@@ -131,11 +133,12 @@ public:
 	virtual void startIncomingNotification(bool notifyRinging = true);
 	void startBasicIncomingNotification(bool notifyRinging = true);
 	void startPushIncomingNotification();
-	virtual int
-	startInvite(const Address *destination, const std::string &subject = "", const Content *content = nullptr);
+	virtual int startInvite(const std::shared_ptr<Address> &destination,
+	                        const std::string &subject = "",
+	                        const Content *content = nullptr);
 	LinphoneStatus terminate(const LinphoneErrorInfo *ei = nullptr);
 	LinphoneStatus transfer(const std::shared_ptr<CallSession> &dest);
-	LinphoneStatus transfer(const Address &dest);
+	LinphoneStatus transfer(const std::shared_ptr<Address> &dest);
 	LinphoneStatus transfer(const std::string &dest);
 	LinphoneStatus update(const CallSessionParams *csp,
 	                      const UpdateMethod method = UpdateMethod::Default,
@@ -144,26 +147,26 @@ public:
 
 	CallSessionParams *getCurrentParams() const;
 	LinphoneCallDir getDirection() const;
-	const Address &getDiversionAddress() const;
+	const std::shared_ptr<Address> getDiversionAddress() const;
 	int getDuration() const;
 	const LinphoneErrorInfo *getErrorInfo() const;
-	const Address &getLocalAddress() const;
-	Address getContactAddress() const;
+	const std::shared_ptr<Address> getLocalAddress() const;
+	const std::shared_ptr<Address> getContactAddress() const;
 	std::shared_ptr<CallLog> getLog() const;
 	virtual const CallSessionParams *getParams() const;
 	LinphoneReason getReason() const;
 	std::shared_ptr<CallSession> getReferer() const;
-	const std::string &getReferTo() const;
-	const Address &getReferToAddress() const;
-	const Address *getRemoteAddress() const;
+	const std::string getReferTo() const;
+	const std::shared_ptr<Address> &getReferToAddress() const;
+	const std::shared_ptr<Address> getRemoteAddress() const;
 	const std::string &getRemoteContact() const;
-	const Address *getRemoteContactAddress() const;
+	const std::shared_ptr<Address> getRemoteContactAddress() const;
 	const CallSessionParams *getRemoteParams();
 	const std::string &getRemoteUserAgent() const;
 	std::shared_ptr<CallSession> getReplacedCallSession() const;
 	CallSession::State getState() const;
-	const Address &getToAddress() const;
-	const Address &getRequestAddress() const;
+	const std::shared_ptr<Address> getToAddress() const;
+	const std::shared_ptr<Address> getRequestAddress() const;
 	CallSession::State getTransferState() const;
 	std::shared_ptr<CallSession> getTransferTarget() const;
 	const char *getToHeader(const std::string &name) const;
@@ -171,7 +174,7 @@ public:
 	const std::string getFromTag() const;
 	const std::string getToTag() const;
 
-	void updateContactAddress(Address &contactAddress) const;
+	void updateContactAddressInOp();
 
 	static bool isEarlyState(CallSession::State state);
 	void accepting();
@@ -186,6 +189,7 @@ protected:
 	explicit CallSession(CallSessionPrivate &p, const std::shared_ptr<Core> &core);
 	CallSession::State getPreviousState() const;
 	CallSession::State getLastStableState() const;
+	void updateContactAddress(Address &contactAddress) const;
 
 private:
 	// bool mIsDeclining = false;
diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h
index d46063629665bcb10e6158c30739b4587aab1ce4..a543ba573d1f594df02f33f93a611455f870f2a6 100644
--- a/src/conference/session/media-session-p.h
+++ b/src/conference/session/media-session-p.h
@@ -215,8 +215,8 @@ private:
 	void updateBiggestDesc(std::shared_ptr<SalMediaDescription> &md);
 	void updateRemoteSessionIdAndVer();
 
-	void discoverMtu(const Address &remoteAddr);
-	void getLocalIp(const Address &remoteAddr);
+	void discoverMtu(const std::shared_ptr<Address> &remoteAddr);
+	void getLocalIp(const std::shared_ptr<Address> &remoteAddr);
 	void runStunTestsIfNeeded();
 	void selectIncomingIpVersion();
 	void selectOutgoingIpVersion();
@@ -276,7 +276,7 @@ private:
 	bool atLeastOneStreamStarted() const;
 	uint16_t getAvpfRrInterval() const;
 	unsigned int getNbActiveStreams() const;
-	void addSecurityEventInChatrooms(const IdentityAddress &faultyDevice,
+	void addSecurityEventInChatrooms(const std::shared_ptr<Address> &faultyDevice,
 	                                 ConferenceSecurityEvent::SecurityEventType securityEventType);
 	void propagateEncryptionChanged();
 
diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp
index a111c58e2a94f07a2e88739f0b69fa9767138e0d..fdc1f275fc1574a09172f39f6c3b80b05507a7ca 100644
--- a/src/conference/session/media-session.cpp
+++ b/src/conference/session/media-session.cpp
@@ -151,13 +151,12 @@ bool MediaSessionPrivate::tryEnterConference() {
 	L_Q();
 
 	if (getOp() && getOp()->getContactAddress()) {
-		char *contactAddressStr = sal_address_as_string(getOp()->getContactAddress());
-		Address contactAddress(contactAddressStr);
-		ms_free(contactAddressStr);
+		const auto contactAddress = q->getContactAddress();
 		const auto &confId = getConferenceId();
-		if (!confId.empty() && isInConference() && !contactAddress.hasParam("isfocus")) {
-			q->updateContactAddress(contactAddress);
-			ConferenceId localConferenceId = ConferenceId(contactAddress, contactAddress);
+		if (!confId.empty() && isInConference() && !contactAddress->hasParam("isfocus")) {
+			q->updateContactAddressInOp();
+			const auto updatedContactAddress = q->getContactAddress();
+			ConferenceId localConferenceId = ConferenceId(updatedContactAddress, updatedContactAddress);
 			shared_ptr<MediaConference::Conference> conference =
 			    q->getCore()->findAudioVideoConference(localConferenceId, false);
 			// If the call conference ID is not an empty string but no conference is linked to the call means that it
@@ -165,8 +164,8 @@ bool MediaSessionPrivate::tryEnterConference() {
 			if (conference) {
 				if (state == CallSession::State::Paused) {
 					// Resume call as it was added to conference
-					lInfo() << "Media session (local address " << q->getLocalAddress().asString() << " remote address "
-					        << q->getRemoteAddress()->asString() << ") was added to conference "
+					lInfo() << "Media session (local address " << q->getLocalAddress()->toString() << " remote address "
+					        << q->getRemoteAddress()->toString() << ") was added to conference "
 					        << conference->getConferenceAddress()
 					        << " while the call was being paused. Resuming the session.";
 					q->resume();
@@ -177,8 +176,8 @@ bool MediaSessionPrivate::tryEnterConference() {
 					if (videoEnabled) {
 						newParams->enableRtpBundle(true);
 					}
-					lInfo() << "Media session (local address " << q->getLocalAddress().asString() << " remote address "
-					        << q->getRemoteAddress()->asString() << ") was added to conference "
+					lInfo() << "Media session (local address " << q->getLocalAddress()->toString() << " remote address "
+					        << q->getRemoteAddress()->toString() << ") was added to conference "
 					        << conference->getConferenceAddress()
 					        << " while the call was establishing. Sending update to notify remote participant.";
 					q->update(newParams, CallSession::UpdateMethod::Default, q->isCapabilityNegotiationEnabled());
@@ -206,15 +205,14 @@ bool MediaSessionPrivate::rejectMediaSession(const std::shared_ptr<SalMediaDescr
 		const auto ownerIndexes = finalMd->getTransportOwnerIndexes();
 		bool isThereAnActiveOwner = false;
 		if (!ownerIndexes.empty()) {
-			for (const auto & idx : ownerIndexes) {
-				const auto & sd = finalMd->getStreamIdx(static_cast<unsigned int>(idx));
+			for (const auto &idx : ownerIndexes) {
+				const auto &sd = finalMd->getStreamIdx(static_cast<unsigned int>(idx));
 				isThereAnActiveOwner |= sd.enabled();
 			}
 			bundleOwnerRejected = !isThereAnActiveOwner;
 		}
 	}
 	return (finalMd->isEmpty() || incompatibleSecurity(finalMd) || bundleOwnerRejected);
-
 }
 
 void MediaSessionPrivate::accepted() {
@@ -292,10 +290,11 @@ void MediaSessionPrivate::accepted() {
 					nextState = CallSession::State::Paused;
 					nextStateMsg = "Call paused";
 				} else {
-					// The call always enters state PausedByRemote if all streams are rejected. This is done to support some clients who accept to stop the streams by setting the RTP port to 0
-					// If the call is part of a conference, then it shouldn't be paused if it is just trying to update the conference
-					if (!updatingConference && !localDesc->hasDir(SalStreamInactive)
-						&& (md->hasDir(SalStreamRecvOnly) || md->hasDir(SalStreamInactive) || md->isEmpty())) {
+					// The call always enters state PausedByRemote if all streams are rejected. This is done to support
+					// some clients who accept to stop the streams by setting the RTP port to 0 If the call is part of a
+					// conference, then it shouldn't be paused if it is just trying to update the conference
+					if (!updatingConference && !localDesc->hasDir(SalStreamInactive) &&
+					    (md->hasDir(SalStreamRecvOnly) || md->hasDir(SalStreamInactive) || md->isEmpty())) {
 						nextState = CallSession::State::PausedByRemote;
 						nextStateMsg = "Call paused by remote";
 					} else {
@@ -326,7 +325,7 @@ void MediaSessionPrivate::accepted() {
 		// to analyze what leads to this scenario
 		if (nbProcessingUpdates < 0) {
 			lFatal() << "The number of updates under processing for media session (local address "
-			         << q->getLocalAddress().asString() << " remote address " << q->getRemoteAddress()->asString()
+			         << q->getLocalAddress()->toString() << " remote address " << q->getRemoteAddress()->toString()
 			         << ") should be greater than or equal to 0. Currently it is " << nbProcessingUpdates;
 		}
 
@@ -631,9 +630,8 @@ void MediaSessionPrivate::updated(bool isUpdate) {
 	L_Q();
 
 	const std::shared_ptr<SalMediaDescription> &rmd = op->getRemoteMediaDescription();
-	char *remoteContactAddressStr = sal_address_as_string(op->getRemoteContactAddress());
-	Address remoteContactAddress(remoteContactAddressStr);
-	ms_free(remoteContactAddressStr);
+	std::shared_ptr<Address> remoteContactAddress = Address::create();
+	remoteContactAddress->setImpl(op->getRemoteContactAddress());
 
 	switch (state) {
 		case CallSession::State::PausedByRemote:
@@ -1046,10 +1044,13 @@ void MediaSessionPrivate::setCompatibleIncomingCallParams(std::shared_ptr<SalMed
 	/* Handle AVPF, SRTP and DTLS */
 
 	getParams()->enableAvpf(hasAvpf(md));
-	if (destProxy)
-		getParams()->setAvpfRrInterval(
-		    static_cast<uint16_t>(linphone_proxy_config_get_avpf_rr_interval(destProxy) * 1000));
-	else getParams()->setAvpfRrInterval(static_cast<uint16_t>(linphone_core_get_avpf_rr_interval(lc) * 1000));
+	const auto &account = getDestAccount();
+	uint16_t avpfRrInterval;
+	if (account) {
+		const auto accountParams = account->getAccountParams();
+		avpfRrInterval = static_cast<uint16_t>(accountParams->getAvpfRrInterval() * 1000);
+	} else avpfRrInterval = static_cast<uint16_t>(linphone_core_get_avpf_rr_interval(lc) * 1000);
+	getParams()->setAvpfRrInterval(avpfRrInterval);
 	bool_t mandatory = linphone_core_is_media_encryption_mandatory(lc);
 	bool_t acceptAllEncryptions = !!linphone_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "rtp",
 	                                                        "accept_any_encryption", 0);
@@ -1124,11 +1125,11 @@ const LinphoneStreamInternalStats *MediaSessionPrivate::getStreamInternalStats(L
 
 // -----------------------------------------------------------------------------
 
-void MediaSessionPrivate::discoverMtu(const Address &remoteAddr) {
+void MediaSessionPrivate::discoverMtu(const std::shared_ptr<Address> &remoteAddr) {
 	L_Q();
 	if (q->getCore()->getCCore()->net_conf.mtu == 0) {
 		/* Attempt to discover mtu */
-		int mtu = ms_discover_mtu(remoteAddr.getDomain().c_str());
+		int mtu = ms_discover_mtu(remoteAddr->getDomain().c_str());
 		if (mtu > 0) {
 			ms_factory_set_mtu(q->getCore()->getCCore()->factory, mtu);
 			lInfo() << "Discovered mtu is " << mtu << ", RTP payload max size is "
@@ -1140,7 +1141,7 @@ void MediaSessionPrivate::discoverMtu(const Address &remoteAddr) {
 /**
  * Fill the local ip that routes to the internet according to the destination, or guess it by other special means.
  */
-void MediaSessionPrivate::getLocalIp(const Address &remoteAddr) {
+void MediaSessionPrivate::getLocalIp(const std::shared_ptr<Address> &remoteAddr) {
 	L_Q();
 	// Next, sometime, override from config
 	const char *ip =
@@ -1151,10 +1152,12 @@ void MediaSessionPrivate::getLocalIp(const Address &remoteAddr) {
 		return;
 	}
 
+	const auto &account = getDestAccount();
+	const auto &accountOp = account ? account->getOp() : nullptr;
 	// If a known proxy was identified for this call, then we may have a chance to take the local ip address
 	// from the socket that connects to this proxy
-	if (destProxy && linphone_proxy_config_get_op(destProxy)) {
-		ip = linphone_proxy_config_get_op(destProxy)->getLocalAddress(nullptr);
+	if (accountOp) {
+		ip = accountOp->getLocalAddress(nullptr);
 		if (ip) {
 			if (needLocalIpRefresh) {
 				af = strchr(ip, ':') ? AF_INET6 : AF_INET;
@@ -1174,10 +1177,10 @@ void MediaSessionPrivate::getLocalIp(const Address &remoteAddr) {
 	// In last resort, attempt to find the local ip that routes to destination if given as an IP address,
 	// or the default route (dest is empty)
 	string dest;
-	if (!destProxy) {
+	if (!account) {
 		struct addrinfo hints;
 		struct addrinfo *res = nullptr;
-		string host(remoteAddr.getDomain());
+		string host(remoteAddr->getDomain());
 		int err;
 
 		if (host[0] == '[') host = host.substr(1, host.size() - 2);
@@ -1249,8 +1252,9 @@ void MediaSessionPrivate::runStunTestsIfNeeded() {
 void MediaSessionPrivate::selectIncomingIpVersion() {
 	L_Q();
 	if (linphone_core_ipv6_enabled(q->getCore()->getCCore())) {
-		if (destProxy && linphone_proxy_config_get_op(destProxy))
-			af = linphone_proxy_config_get_op(destProxy)->getAddressFamily();
+		const auto &account = getDestAccount();
+		const auto &accountOp = account ? account->getOp() : nullptr;
+		if (accountOp) af = accountOp->getAddressFamily();
 		else af = op->getAddressFamily();
 	} else af = AF_INET;
 }
@@ -1273,13 +1277,16 @@ void MediaSessionPrivate::selectOutgoingIpVersion() {
 	af = AF_UNSPEC;
 	if (linphone_core_get_local_ip_for(AF_INET, nullptr, ipv4) == 0) haveIpv4 = true;
 	if (linphone_core_ipv6_enabled(q->getCore()->getCCore())) {
-		const LinphoneAddress *to = log->getToAddress();
+		const auto &toAddr = log->getToAddress();
 
 		if (linphone_core_get_local_ip_for(AF_INET6, nullptr, ipv6) == 0) haveIpv6 = true;
-		if (destProxy && linphone_proxy_config_get_op(destProxy)) {
+
+		const auto &account = getDestAccount();
+		const auto &accountOp = account ? account->getOp() : nullptr;
+		if (accountOp) {
 			// We can determine from the proxy connection whether IPv6 works - this is the most reliable
-			af = linphone_proxy_config_get_op(destProxy)->getAddressFamily();
-		} else if (sal_address_is_ipv6(L_GET_CPP_PTR_FROM_C_OBJECT(to)->getInternalAddress())) {
+			af = accountOp->getAddressFamily();
+		} else if (sal_address_is_ipv6(toAddr->getImpl())) {
 			af = AF_INET6;
 		}
 
@@ -1397,8 +1404,9 @@ bool MediaSessionPrivate::generateB64CryptoKey(size_t keyLength, std::string &ke
 
 bool MediaSessionPrivate::mandatoryRtpBundleEnabled() const {
 	if (!getParams()->rtpBundleEnabled()) return false;
-	if (destProxy) {
-		return Account::toCpp(destProxy->account)->getAccountParams()->rtpBundleAssumptionEnabled();
+	const auto &account = getDestAccount();
+	if (account) {
+		return account->getAccountParams()->rtpBundleAssumptionEnabled();
 	}
 	return false;
 }
@@ -1418,9 +1426,9 @@ void MediaSessionPrivate::addStreamToBundle(const std::shared_ptr<SalMediaDescri
 		cfg.mid_rtp_ext_header_id = rtpExtHeaderMidNumber;
 		/* rtcp-mux must be enabled when bundle mode is proposed.*/
 		cfg.rtcp_mux = TRUE;
-		if (mandatoryRtpBundleEnabled() || bundleModeAccepted){
+		if (mandatoryRtpBundleEnabled() || bundleModeAccepted) {
 			// Bundle is offered inconditionally
-			if (bundle.getMidOfTransportOwner() != mid){
+			if (bundle.getMidOfTransportOwner() != mid) {
 				cfg.bundle_only = true;
 				sd.rtp_port = 0;
 			}
@@ -1487,7 +1495,7 @@ void MediaSessionPrivate::fillRtpParameters(SalStreamDescription &stream) const
 		/* rtcp-mux must be enabled when bundle mode is proposed or we're using DTLS-SRTP.*/
 		cfg.rtcp_mux = rtcpMux || getParams()->rtpBundleEnabled() ||
 		               (getNegotiatedMediaEncryption() == LinphoneMediaEncryptionDTLS);
-		cfg.rtcp_cname = getMe()->getAddress().asString();
+		cfg.rtcp_cname = getMe()->getAddress()->toString();
 
 		if (stream.rtp_port == 0 && !cfg.isBundleOnly()) {
 			stream.rtp_port = SAL_STREAM_DESCRIPTION_PORT_TO_BE_DETERMINED;
@@ -1540,7 +1548,7 @@ void MediaSessionPrivate::fillConferenceParticipantVideoStream(SalStreamDescript
 		std::list<OrtpPayloadType *> l = pth.makeCodecsList(SalVideo, 0, -1, alreadyAssignedPayloads, bundle_enabled);
 		if (!l.empty()) {
 			newStream.setLabel(label);
-			newStream.name = "Video " + dev->getAddress().asString();
+			newStream.name = "Video " + dev->getAddress()->toString();
 			const auto &content = newStream.getContent();
 			const bool isInLocalConference = getParams()->getPrivate()->getInConference();
 
@@ -1594,7 +1602,7 @@ void MediaSessionPrivate::fillConferenceParticipantVideoStream(SalStreamDescript
 
 	if (!success) {
 		lInfo() << "Don't put video stream for device in conference with address "
-		        << (dev ? dev->getAddress().asString() : "<unknown>") << " on local offer for CallSession [" << q
+		        << (dev ? dev->getAddress()->toString() : "<unknown>") << " on local offer for CallSession [" << q
 		        << "] because no valid payload has been found or device is not valid (pointer " << dev << ")";
 		cfg.dir = SalStreamInactive;
 		newStream.disable();
@@ -1631,7 +1639,7 @@ void MediaSessionPrivate::fillLocalStreamDescription(SalStreamDescription &strea
 		stream.rtp_port = SAL_STREAM_DESCRIPTION_PORT_TO_BE_DETERMINED;
 
 		cfg.replacePayloads(codecs);
-		cfg.rtcp_cname = getMe()->getAddress().asString();
+		cfg.rtcp_cname = getMe()->getAddress()->toString();
 
 		LinphoneConference *conference =
 		    listener ? listener->getCallSessionConference(q->getSharedFromThis()) : nullptr;
@@ -1748,7 +1756,9 @@ void MediaSessionPrivate::addConferenceParticipantVideostreams(std::shared_ptr<S
 				                                             : getParams()->getConferenceVideoLayout();
 
 				bool isConferenceLayoutActiveSpeaker = (confLayout == ConferenceLayout::ActiveSpeaker);
-				const auto &participantDeviceAddress =
+				const auto remoteContactAddress = q->getRemoteContactAddress();
+				q->updateContactAddressInOp();
+				const auto participantDeviceAddress =
 				    (isInLocalConference) ? remoteContactAddress : q->getContactAddress();
 
 				const auto &participantDevice = isInLocalConference
@@ -1764,7 +1774,7 @@ void MediaSessionPrivate::addConferenceParticipantVideostreams(std::shared_ptr<S
 
 				for (const auto &p : cppConference->getParticipants()) {
 					for (const auto &dev : p->getDevices()) {
-						const auto &devAddress = dev->getAddress().asAddress();
+						const auto &devAddress = dev->getAddress();
 						const auto &devState = dev->getState();
 						// Do not add stream for device matching the remote contact address if the chosen layout is
 						// active speaker
@@ -1792,7 +1802,7 @@ void MediaSessionPrivate::addConferenceParticipantVideostreams(std::shared_ptr<S
 						std::vector<std::pair<std::string, std::string>> attributes;
 						const auto &foundStreamIdx = devLabel.empty()
 						                                 ? -1
-						                                 : ((participantDeviceAddress == dev->getAddress().asAddress())
+						                                 : ((*participantDeviceAddress == *(dev->getAddress()))
 						                                        ? oldMd->findIdxStreamWithContent(content, devLabel)
 						                                        : md->findIdxStreamWithLabel(devLabel));
 						SalStreamDescription &newMeStream = addStreamToMd(md, foundStreamIdx, oldMd);
@@ -1996,26 +2006,25 @@ void MediaSessionPrivate::makeLocalMediaDescription(bool localIsOfferer,
 
 	/* Re-check local ip address each time we make a new offer, because it may change in case of network reconnection */
 	{
-		const LinphoneAddress *address =
-		    (direction == LinphoneCallOutgoing ? log->getToAddress() : log->getFromAddress());
-		getLocalIp(*L_GET_CPP_PTR_FROM_C_OBJECT(address));
+		const auto &address = (direction == LinphoneCallOutgoing ? log->getToAddress() : log->getFromAddress());
+		getLocalIp(address);
 	}
 
 	md->origin_addr = mediaLocalIp;
 	md->addr = mediaLocalIp;
 
-	LinphoneAddress *addr = nullptr;
-	if (destProxy) {
-		addr = linphone_address_clone(linphone_proxy_config_get_identity_address(destProxy));
+	Address addr;
+	const auto &account = getDestAccount();
+	if (account) {
+		const auto accountParams = account->getAccountParams();
+		addr = *accountParams->getIdentityAddress();
 	} else {
-		addr = linphone_address_new(linphone_core_get_identity(core));
+		addr = Address(linphone_core_get_identity(core));
 	}
-	if (linphone_address_get_username(addr)) { /* Might be null in case of identity without userinfo */
-		md->username = linphone_address_get_username(addr);
+	if (!addr.getUsername().empty()) { /* Might be null in case of identity without userinfo */
+		md->username = addr.getUsername();
 	}
 
-	linphone_address_unref(addr);
-
 	int bandwidth = getParams()->getPrivate()->getDownBandwidth();
 	if (bandwidth) md->bandwidth = bandwidth;
 	else md->bandwidth = linphone_core_get_download_bandwidth(core);
@@ -2297,7 +2306,8 @@ void MediaSessionPrivate::makeLocalMediaDescription(bool localIsOfferer,
 	const auto &mdForMainStream = localIsOfferer ? md : refMd;
 	const auto audioStreamIndex = mdForMainStream->findIdxBestStream(SalAudio);
 	if (audioStreamIndex != -1) getStreamsGroup().setStreamMain(static_cast<size_t>(audioStreamIndex));
-	const auto videoStreamIndex = (conference || remoteContactAddress.hasParam("isfocus"))
+	const auto remoteContactAddress = q->getRemoteContactAddress();
+	const auto videoStreamIndex = (conference || (remoteContactAddress && remoteContactAddress->hasParam("isfocus")))
 	                                  ? mdForMainStream->findIdxStreamWithContent(mainStreamAttrValue)
 	                                  : mdForMainStream->findIdxBestStream(SalVideo);
 	if (videoStreamIndex != -1) getStreamsGroup().setStreamMain(static_cast<size_t>(videoStreamIndex));
@@ -3047,69 +3057,57 @@ bool MediaSessionPrivate::canSoundResourcesBeFreed() const {
 LinphoneStatus MediaSessionPrivate::pause() {
 	L_Q();
 	if (state == CallSession::State::Paused) {
-		lWarning() << "Media session (local address " << q->getLocalAddress().asString() << " remote address "
-		           << q->getRemoteAddress()->asString() << ") is in state " << Utils::toString(state)
+		lWarning() << "Media session (local address " << q->getLocalAddress()->toString() << " remote address "
+		           << q->getRemoteAddress()->toString() << ") is in state " << Utils::toString(state)
 		           << " is already paused";
 		return 0;
 	} else if (state == CallSession::State::Pausing) {
-		lWarning() << "Media session (local address " << q->getLocalAddress().asString() << " remote address "
-		           << q->getRemoteAddress()->asString() << ") is in state " << Utils::toString(state)
+		lWarning() << "Media session (local address " << q->getLocalAddress()->toString() << " remote address "
+		           << q->getRemoteAddress()->toString() << ") is in state " << Utils::toString(state)
 		           << " is already in the process of being paused";
 		return 0;
 	} else if (!canSoundResourcesBeFreed()) {
-		lWarning() << "Media session (local address " << q->getLocalAddress().asString() << " remote address "
-		           << q->getRemoteAddress()->asString() << ") is in state " << Utils::toString(state)
+		lWarning() << "Media session (local address " << q->getLocalAddress()->toString() << " remote address "
+		           << q->getRemoteAddress()->toString() << ") is in state " << Utils::toString(state)
 		           << " hence it cannot be paused";
 		return -1;
 	}
 
 	bool isInLocalConference = getParams()->getPrivate()->getInConference();
 	if (isInLocalConference) {
-		char *contactAddressStr = NULL;
-		const auto account =
-		    linphone_core_lookup_known_account(q->getCore()->getCCore(), L_GET_C_BACK_PTR(&(q->getLocalAddress())));
-		if (op && op->getContactAddress()) {
-			contactAddressStr = sal_address_as_string(op->getContactAddress());
-		} else if (account && Account::toCpp(account)->getOp()) {
-			contactAddressStr = sal_address_as_string(Account::toCpp(account)->getOp()->getContactAddress());
-		} else {
-			contactAddressStr = ms_strdup(linphone_core_get_identity(q->getCore()->getCCore()));
-		}
-		Address contactAddress(contactAddressStr);
-		ms_free(contactAddressStr);
-
+		const auto contactAddress = q->getContactAddress();
 		if (!!linphone_config_get_bool(linphone_core_get_config(q->getCore()->getCCore()), "misc",
 		                               "conference_event_log_enabled", TRUE) &&
-		    contactAddress.hasParam("isfocus")) {
+		    contactAddress && contactAddress->hasParam("isfocus")) {
 			if (listener) {
 				auto callConference = listener->getCallSessionConference(q->getSharedFromThis());
 				if (callConference) {
 					auto conference = MediaConference::Conference::toCpp(callConference)->getSharedFromThis();
 					if (conference->findParticipantDevice(q->getSharedFromThis())) {
-						lWarning() << "Unable to pause media session (local address " << q->getLocalAddress().asString()
-						           << " remote address " << q->getRemoteAddress()->asString()
+						lWarning() << "Unable to pause media session (local address "
+						           << q->getLocalAddress()->toString() << " remote address "
+						           << q->getRemoteAddress()->toString()
 						           << ") because it is part of a conference. Please use the dedicated conference API "
 						              "to execute the desired actions";
 						return -1;
 					}
 				} else {
 					lWarning()
-					    << "The contact address " << contactAddress
+					    << "The contact address " << *contactAddress
 					    << " of the call has isfocus attribute however it doesn't seems to be part of a conference.";
 				}
 			}
 		}
 
 		params->getPrivate()->setInConference(false);
-		q->updateContactAddress(contactAddress);
-		op->setContactAddress(contactAddress.getInternalAddress());
+		q->updateContactAddressInOp();
 
 		if (listener) {
 			auto callConference = listener->getCallSessionConference(q->getSharedFromThis());
 			if (callConference) {
 				auto conference = MediaConference::Conference::toCpp(callConference)->getSharedFromThis();
 				lInfo() << "Removing participant with session " << q << " (local addres "
-				        << q->getLocalAddress().asString() << " remote address " << q->getRemoteAddress()->asString()
+				        << q->getLocalAddress()->toString() << " remote address " << q->getRemoteAddress()->toString()
 				        << ")  from conference " << conference->getConferenceAddress();
 				// Do not preserve conference after removing the participant
 				conference->removeParticipant(q->getSharedFromThis(), false);
@@ -3508,7 +3506,7 @@ LinphoneStatus MediaSessionPrivate::startAccept() {
 		if ((linphone_core_get_media_resource_mode(q->getCore()->getCCore()) == LinphoneExclusiveMediaResources) &&
 		    linphone_core_preempt_sound_resources(q->getCore()->getCCore()) != 0) {
 			lInfo() << "Delaying call to " << __func__ << " for media session (local addres "
-			        << q->getLocalAddress().asString() << " remote address " << q->getRemoteAddress()->asString()
+			        << q->getLocalAddress()->toString() << " remote address " << q->getRemoteAddress()->toString()
 			        << ") in state " << Utils::toString(state) << " because sound resources cannot be preempted";
 			q->addPendingAction([this] {
 				this->startAccept();
@@ -3520,15 +3518,10 @@ LinphoneStatus MediaSessionPrivate::startAccept() {
 
 	// It occurs if the remote participant calls the core hosting the conference and the call is added to the conference
 	// when it is in state IncomingReceived
-	if (getOp() && getOp()->getContactAddress()) {
-		char *contactAddressStr = sal_address_as_string(getOp()->getContactAddress());
-		Address contactAddress(contactAddressStr);
-		ms_free(contactAddressStr);
-		const auto &confId = getConferenceId();
-		if (!confId.empty() && isInConference() && !contactAddress.hasUriParam("conf-id")) {
-			q->updateContactAddress(contactAddress);
-			op->setContactAddress(contactAddress.getInternalAddress());
-		}
+	// Do not do anything if the contact address is not yet known
+	const auto &confId = getConferenceId();
+	if (getOp() && getOp()->getContactAddress() && !confId.empty() && isInConference()) {
+		q->updateContactAddressInOp();
 	}
 
 	/* Give a chance a set card prefered sampling frequency */
@@ -3738,20 +3731,27 @@ void MediaSessionPrivate::stunAuthRequestedCb(const char *realm,
                                               const char **ha1) {
 	L_Q();
 	/* Get the username from the nat policy or the proxy config */
-	LinphoneProxyConfig *proxy = nullptr;
-	if (destProxy) proxy = destProxy;
-	else proxy = linphone_core_get_default_proxy_config(q->getCore()->getCCore());
-	if (!proxy) return;
+	std::shared_ptr<Account> stunAccount = nullptr;
+	const auto &account = getDestAccount();
+	if (account) stunAccount = account;
+	else {
+		auto defaultAccount = linphone_core_get_default_account(q->getCore()->getCCore());
+		if (defaultAccount) {
+			stunAccount = Account::toCpp(defaultAccount)->getSharedFromThis();
+		}
+	}
+	if (!stunAccount) return;
 	const char *user = nullptr;
-	LinphoneNatPolicy *proxyNatPolicy = linphone_proxy_config_get_nat_policy(proxy);
-	if (proxyNatPolicy) user = linphone_nat_policy_get_stun_server_username(proxyNatPolicy);
+	const auto &accountParams = stunAccount->getAccountParams();
+	const auto &proxyNatPolicy = accountParams->getNatPolicy();
+	if (proxyNatPolicy) user = L_STRING_TO_C(proxyNatPolicy->getStunServerUsername());
 	else if (natPolicy) user = linphone_nat_policy_get_stun_server_username(natPolicy);
 	if (!user) {
 		/* If the username has not been found in the nat_policy, take the username from the currently used proxy config
 		 */
-		const LinphoneAddress *addr = linphone_proxy_config_get_identity_address(proxy);
-		if (!addr) return;
-		user = linphone_address_get_username(addr);
+		const auto identityAddress = accountParams->getIdentityAddress();
+		if (!identityAddress) return;
+		user = L_STRING_TO_C(identityAddress->getUsername());
 	}
 	if (!user) return;
 
@@ -3838,11 +3838,11 @@ LinphoneStatus MediaSession::accept(const MediaSessionParams *msp) {
 
 	auto ret = d->accept(msp, wasRinging);
 	if (ret == 0) {
-		lInfo() << "MediaSession (local address " << getLocalAddress().asString() << " remote address "
-		        << getRemoteAddress()->asString() << ") has been accepted";
+		lInfo() << "MediaSession (local address " << getLocalAddress()->toString() << " remote address "
+		        << getRemoteAddress()->toString() << ") has been accepted";
 	} else {
-		lInfo() << "Unable to immediately accept session " << this << " (local address " << getLocalAddress().asString()
-		        << " remote address " << getRemoteAddress()->asString() << ")";
+		lInfo() << "Unable to immediately accept session " << this << " (local address "
+		        << getLocalAddress()->toString() << " remote address " << getRemoteAddress()->toString() << ")";
 	}
 	return ret;
 }
@@ -3903,17 +3903,27 @@ bool MediaSession::toneIndicationsEnabled() const {
 	return getMediaParams()->getPrivate()->toneIndicationsEnabled();
 }
 
-void MediaSession::configure(
-    LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) {
+void MediaSession::configure(LinphoneCallDir direction,
+                             LinphoneProxyConfig *cfg,
+                             SalCallOp *op,
+                             const std::shared_ptr<Address> &from,
+                             const std::shared_ptr<Address> &to) {
 	L_D();
 	bool makeLocalDescription = true;
 	bool isOfferer = true;
-	Address remote;
+	std::shared_ptr<Address> remote;
 
 	CallSession::configure(direction, cfg, op, from, to);
 
+	const auto &account = d->getDestAccount();
+	const auto &accountParams = account ? account->getAccountParams() : nullptr;
 	if (!d->natPolicy) {
-		if (d->destProxy) d->natPolicy = linphone_proxy_config_get_nat_policy(d->destProxy);
+		if (accountParams) {
+			const auto accountNatPolicy = accountParams->getNatPolicy();
+			if (accountNatPolicy) {
+				d->natPolicy = accountNatPolicy->toC();
+			}
+		}
 		if (!d->natPolicy) d->natPolicy = linphone_core_get_nat_policy(getCore()->getCCore());
 		linphone_nat_policy_ref(d->natPolicy);
 	}
@@ -3925,8 +3935,8 @@ void MediaSession::configure(
 		/* The enablement of rtp bundle is controlled at first by the Account, then the Core.
 		 * Then the value is stored and later updated into MediaSessionParams. */
 		bool rtpBundleEnabled = false;
-		if (d->destProxy) {
-			rtpBundleEnabled = Account::toCpp(d->destProxy->account)->getAccountParams()->rtpBundleEnabled();
+		if (accountParams) {
+			rtpBundleEnabled = accountParams->rtpBundleEnabled();
 		} else {
 			lInfo() << "No account set for this call, using rtp bundle enablement from LinphoneCore.";
 			rtpBundleEnabled = linphone_core_rtp_bundle_enabled(getCore()->getCCore());
@@ -3938,7 +3948,7 @@ void MediaSession::configure(
 		 * examining the remote offer, if any. If the remote offer contains IPv4 addresses, we should propose IPv4 as
 		 * well. */
 		remote = from;
-		remote.clean();
+		remote->clean();
 		d->setParams(new MediaSessionParams());
 		d->params->initDefault(getCore(), LinphoneCallIncoming);
 		d->initializeParamsAccordingToIncomingCallParams();
@@ -4019,10 +4029,9 @@ bool MediaSession::initiateOutgoing(const string &subject, const Content *conten
 				 */
 				d->updateLocalMediaDescriptionFromIce(d->localIsOfferer);
 			} else {
-				auto toAddr = linphone_address_as_string(d->log->getToAddress());
-				lInfo() << "Unable to initiate call to " << std::string(toAddr)
+				auto toAddr = d->log->getToAddress();
+				lInfo() << "Unable to initiate call to " << toAddr->toString()
 				        << " because ICE candidates must be gathered first";
-				ms_free(toAddr);
 				d->queueIceGatheringTask([this, subject, content]() {
 					L_D();
 					if (d->state != CallSession::State::End) // Call has been terminated while gathering: avoid to
@@ -4044,25 +4053,7 @@ void MediaSession::iterate(time_t currentRealTime, bool oneSecondElapsed) {
 
 LinphoneStatus MediaSession::pauseFromConference() {
 	L_D();
-	char *contactAddressStr = nullptr;
-	if (d->destProxy) {
-		if (linphone_proxy_config_get_op(d->destProxy)) {
-			/* Give a chance to update the contact address if connectivity has changed */
-			contactAddressStr = sal_address_as_string(linphone_proxy_config_get_op(d->destProxy)->getContactAddress());
-		} else if (linphone_core_conference_server_enabled(getCore()->getCCore()) &&
-		           linphone_proxy_config_get_contact(d->getDestProxy())) {
-			contactAddressStr = linphone_address_as_string(linphone_proxy_config_get_contact(d->getDestProxy()));
-		}
-	} else if (d->op && d->op->getContactAddress()) {
-		contactAddressStr = sal_address_as_string(d->op->getContactAddress());
-	}
-
-	if (contactAddressStr) {
-		Address contactAddress(contactAddressStr);
-		ms_free(contactAddressStr);
-		updateContactAddress(contactAddress);
-		d->op->setContactAddress(contactAddress.getInternalAddress());
-	}
+	updateContactAddressInOp();
 
 	int ret = 0;
 
@@ -4126,18 +4117,8 @@ LinphoneStatus MediaSession::resume() {
 	if (d->getParams()->getPrivate()->getInConference() && !getCurrentParams()->getPrivate()->getInConference()) {
 		subject = "Conference";
 	}
-	char *contactAddressStr = nullptr;
-	if (d->destProxy && linphone_proxy_config_get_op(d->destProxy)) {
-		contactAddressStr = sal_address_as_string(linphone_proxy_config_get_op(d->destProxy)->getContactAddress());
-	} else if (d->op && d->op->getContactAddress()) {
-		contactAddressStr = sal_address_as_string(d->op->getContactAddress());
-	}
-	if (contactAddressStr) {
-		Address contactAddress(contactAddressStr);
-		ms_free(contactAddressStr);
-		updateContactAddress(contactAddress);
-		d->op->setContactAddress(contactAddress.getInternalAddress());
-	}
+
+	updateContactAddressInOp();
 
 	const auto isIceRunning = getStreamsGroup().getIceService().isRunning();
 
@@ -4178,15 +4159,15 @@ LinphoneStatus MediaSession::resume() {
 
 		const auto preparingStreams = d->getStreamsGroup().prepare();
 		if (linphone_nat_policy_ice_enabled(d->natPolicy) && preparingStreams) {
-			lInfo() << "Defer CallSession " << this << " (local address " << getLocalAddress().asString()
-			        << " remote address " << getRemoteAddress()->asString() << ") resume to gather ICE candidates";
+			lInfo() << "Defer CallSession " << this << " (local address " << getLocalAddress()->toString()
+			        << " remote address " << getRemoteAddress()->toString() << ") resume to gather ICE candidates";
 			d->queueIceGatheringTask(updateCompletionTask);
 			return 0;
 		} else if (isIceRunning) {
 			// ICE negotiations are ongoing hence the update cannot be send right now
 			lInfo() << "Ice negotiations are ongoing and resume once they complete, therefore defer CallSession "
-			        << this << " (local address " << getLocalAddress().asString() << " remote address "
-			        << getRemoteAddress()->asString() << ") resume until Ice negotiations are completed.";
+			        << this << " (local address " << getLocalAddress()->toString() << " remote address "
+			        << getRemoteAddress()->toString() << ") resume until Ice negotiations are completed.";
 			d->queueIceCompletionTask(updateCompletionTask);
 			return 0;
 		}
@@ -4257,9 +4238,10 @@ void MediaSession::sendVfuRequest() {
 	} else lInfo() << "vfu request using sip disabled from config [sip,vfu_with_info]";
 }
 
-// Try to search the local conference by first looking at the contact address and if it is unsuccesfull to the to address as a client may try to be calling a conference URI directly
-// Typically, the seach using the contact address will succeed when a client creates a conference.
-const std::shared_ptr<Conference> MediaSession::getLocalConference() const {
+// Try to search the local conference by first looking at the contact address and if it is unsuccesfull to the to
+// address as a client may try to be calling a conference URI directly Typically, the seach using the contact address
+// will succeed when a client creates a conference.
+std::shared_ptr<Conference> MediaSession::getLocalConference() const {
 	L_D();
 
 	ConferenceId localConferenceId;
@@ -4274,14 +4256,17 @@ const std::shared_ptr<Conference> MediaSession::getLocalConference() const {
 	}
 	if (!conference) {
 		auto contactAddress = getContactAddress();
+		if (contactAddress) {
+			updateContactAddress(*contactAddress);
+		}
 		localConferenceId = ConferenceId(contactAddress, contactAddress);
 		conference = getCore()->findAudioVideoConference(localConferenceId, false);
 	}
 	if (!conference) {
-		const Address to(d->op->getTo());
+		const auto to = Address::create(d->op->getTo());
 		// Local conference
-		if (to.hasUriParam("conf-id")) {
-			localConferenceId = ConferenceId(ConferenceAddress(to), ConferenceAddress(to));
+		if (to->hasUriParam("conf-id")) {
+			localConferenceId = ConferenceId(to, to);
 			conference = getCore()->findAudioVideoConference(localConferenceId, false);
 		}
 	}
@@ -4289,23 +4274,31 @@ const std::shared_ptr<Conference> MediaSession::getLocalConference() const {
 	return conference;
 }
 
-void MediaSession::startIncomingNotification (bool notifyRinging) {
+void MediaSession::startIncomingNotification(bool notifyRinging) {
 	L_D();
 
 	std::shared_ptr<SalMediaDescription> &md = d->op->getFinalMediaDescription();
 
-	const auto conference = getLocalConference();
+	auto conference = getLocalConference();
 	bool isLocalDialOutConferenceCreationPending = false;
 
 	if (conference) {
 		// Get state here as it may be changed if the conference dials participants out
 		const auto conferenceState = conference->getState();
-		const auto dialout = (conference->getCurrentParams().getJoiningMode() == ConferenceParams::JoiningMode::DialIn);
-		isLocalDialOutConferenceCreationPending = dialout && ((conferenceState == ConferenceInterface::State::Instantiated) || (conferenceState == ConferenceInterface::State::CreationPending));
-	}
-
-	if (md && (md->isEmpty() || d->incompatibleSecurity(md)) && !isLocalDialOutConferenceCreationPending) {
-		if (d->state != CallSession::State::PushIncomingReceived &&  d->listener) {
+		const auto dialout =
+		    (conference->getCurrentParams().getJoiningMode() == ConferenceParams::JoiningMode::DialOut);
+		isLocalDialOutConferenceCreationPending =
+		    dialout && ((conferenceState == ConferenceInterface::State::Instantiated) ||
+		                (conferenceState == ConferenceInterface::State::CreationPending));
+	}
+
+	// Do not send a 488 Not Acceptable here if the call is part of a local conference where the server will call out
+	// participant This scenario occurs when a client tries to create a dial out conference but there are not common
+	// codecs between the client and the server. In such a case, the conference is not created at all since the
+	// organizer will not be able to take part to it
+	if (md && (md->isEmpty() || d->incompatibleSecurity(md)) &&
+	    ((conference && isLocalDialOutConferenceCreationPending) || !conference)) {
+		if (d->state != CallSession::State::PushIncomingReceived && d->listener) {
 			LinphoneErrorInfo *ei = linphone_error_info_new();
 			linphone_error_info_set(ei, nullptr, LinphoneReasonNotAcceptable, 488, "Not acceptable here", nullptr);
 			/* When call state is PushIncomingReceived, not notify early failed.
@@ -4313,6 +4306,9 @@ void MediaSession::startIncomingNotification (bool notifyRinging) {
 			d->listener->onCallSessionEarlyFailed(getSharedFromThis(), ei);
 		}
 		d->op->decline(SalReasonNotAcceptable);
+		if (conference) {
+			conference->setState(ConferenceInterface::State::CreationFailed);
+		}
 		return;
 	}
 
@@ -4350,7 +4346,9 @@ int MediaSession::getRandomRtpPort(const SalStreamDescription &stream) const {
 	return rtp_port;
 }
 
-int MediaSession::startInvite(const Address *destination, const string &subject, const Content *content) {
+int MediaSession::startInvite(const std::shared_ptr<Address> &destination,
+                              const string &subject,
+                              const Content *content) {
 	L_D();
 
 	if (d->getOp() == nullptr) d->createOp();
@@ -4472,7 +4470,7 @@ LinphoneStatus MediaSession::update(const MediaSessionParams *msp,
 			    (conferenceState != ConferenceInterface::State::CreationPending) &&
 			    (!d->getParams()->rtpBundleEnabled())) {
 				lInfo() << "Forcing RTP bundle in Media session (local address " << getLocalAddress()
-				        << " remote address " << getRemoteAddress()->asString() << ") was added to conference "
+				        << " remote address " << getRemoteAddress()->toString() << ") was added to conference "
 				        << cppConference->getConferenceAddress();
 				d->getParams()->enableRtpBundle(true);
 			}
@@ -4536,15 +4534,15 @@ LinphoneStatus MediaSession::update(const MediaSessionParams *msp,
 		const auto preparingStreams = d->getStreamsGroup().prepare();
 		// reINVITE sent after full state must be sent after ICE negotiations are completed if ICE is enabled
 		if (linphone_nat_policy_ice_enabled(d->natPolicy) && preparingStreams) {
-			lInfo() << "Defer CallSession " << this << " (local address " << getLocalAddress().asString()
-			        << " remote address " << getRemoteAddress()->asString() << ") update to gather ICE candidates";
+			lInfo() << "Defer CallSession " << this << " (local address " << getLocalAddress()->toString()
+			        << " remote address " << getRemoteAddress()->toString() << ") update to gather ICE candidates";
 			d->queueIceGatheringTask(updateCompletionTask);
 			return 0;
 		} else if (isIceRunning) {
 			// ICE negotiations are ongoing hence the update cannot be send right now
 			lInfo() << "Ice negotiations are ongoing and update once they complete, therefore defer CallSession "
-			        << this << " (local address " << getLocalAddress().asString() << " remote address "
-			        << getRemoteAddress()->asString() << ") update until Ice negotiations are completed.";
+			        << this << " (local address " << getLocalAddress()->toString() << " remote address "
+			        << getRemoteAddress()->toString() << ") update until Ice negotiations are completed.";
 			d->queueIceCompletionTask(updateCompletionTask);
 			return 0;
 		}
@@ -5231,5 +5229,4 @@ uint32_t MediaSession::getSsrc(LinphoneStreamType type) const {
 void MediaSession::setEkt(const MSEKTParametersSet *ekt_params) const {
 	getStreamsGroup().setEkt(ekt_params);
 }
-
 LINPHONE_END_NAMESPACE
diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h
index d4d646aea1bc679749dc016f8728ea179dee04ef..c8da2153085f67af8e4d06003109906a0a4e59b6 100644
--- a/src/conference/session/media-session.h
+++ b/src/conference/session/media-session.h
@@ -72,8 +72,8 @@ public:
 	void configure(LinphoneCallDir direction,
 	               LinphoneProxyConfig *cfg,
 	               SalCallOp *op,
-	               const Address &from,
-	               const Address &to) override;
+	               const std::shared_ptr<Address> &from,
+	               const std::shared_ptr<Address> &to) override;
 	LinphoneStatus deferUpdate() override;
 	void initiateIncoming() override;
 	bool initiateOutgoing(const std::string &subject = "", const Content *content = nullptr) override;
@@ -86,8 +86,9 @@ public:
 	LinphoneStatus sendDtmfs(const std::string &dtmfs);
 	void sendVfuRequest();
 	void startIncomingNotification(bool notifyRinging = true) override;
-	int
-	startInvite(const Address *destination, const std::string &subject = "", const Content *content = nullptr) override;
+	int startInvite(const std::shared_ptr<Address> &destination,
+	                const std::string &subject = "",
+	                const Content *content = nullptr) override;
 	bool startRecording();
 	void stopRecording();
 	bool isRecording();
@@ -178,8 +179,8 @@ private:
 	L_DECLARE_PRIVATE(MediaSession);
 	L_DISABLE_COPY(MediaSession);
 
-	int getRandomRtpPort (const SalStreamDescription & stream) const;
-	const std::shared_ptr<Conference> getLocalConference() const;
+	int getRandomRtpPort(const SalStreamDescription &stream) const;
+	std::shared_ptr<Conference> getLocalConference() const;
 };
 
 /**
diff --git a/src/conference/session/ms2-stream.cpp b/src/conference/session/ms2-stream.cpp
index 39eda34744fcb16f006cb3522371b7ed7d1be217..595d5892320e5b9c0a4274707cf345e956982bc4 100644
--- a/src/conference/session/ms2-stream.cpp
+++ b/src/conference/session/ms2-stream.cpp
@@ -130,7 +130,7 @@ void MS2Stream::initRtpBundle(const OfferAnswerContext &params) {
 		// item
 		string userAgent = linphone_core_get_user_agent(getCCore());
 		rtp_session_set_source_description(mSessions.rtp_session,
-		                                   getMediaSessionPrivate().getMe()->getAddress().asString().c_str(), NULL,
+		                                   getMediaSessionPrivate().getMe()->getAddress()->toString().c_str(), NULL,
 		                                   NULL, NULL, NULL, userAgent.c_str(), NULL);
 	} catch (std::bad_weak_ptr &) {
 		lWarning() << "Unable to set source description for bundle mode";
@@ -248,13 +248,12 @@ void MS2Stream::fillLocalMediaDescription(OfferAnswerContext &ctx) {
 	localDesc.cfgs[localDesc.getChosenConfigurationIndex()].rtp_ssrc =
 	    mSessions.rtp_session ? rtp_session_get_send_ssrc(mSessions.rtp_session) : 0;
 
-	Address address = Address();
+	std::shared_ptr<Address> address = nullptr;
 	if (getMediaSessionPrivate().getOp()) {
 		const auto remoteContactAddress = getMediaSessionPrivate().getOp()->getRemoteContactAddress();
 		if (remoteContactAddress) {
-			char *c_address = sal_address_as_string(remoteContactAddress);
-			address = Address(c_address);
-			ms_free(c_address);
+			address = Address::create();
+			address->setImpl(remoteContactAddress);
 		}
 	}
 	std::shared_ptr<LinphonePrivate::ConferenceInfo> confInfo = nullptr;
@@ -262,10 +261,10 @@ void MS2Stream::fillLocalMediaDescription(OfferAnswerContext &ctx) {
 	// Search in the DB if this is a call toward a conference URI
 	auto &mainDb = getCore().getPrivate()->mainDb;
 	if (mainDb) {
-		confInfo = mainDb->getConferenceInfoFromURI(ConferenceAddress(*(getMediaSession().getRemoteAddress())));
+		confInfo = mainDb->getConferenceInfoFromURI(getMediaSession().getRemoteAddress());
 	}
 #endif // HAVE_DB_STORAGE
-	if (address.hasParam("isfocus") || confInfo)
+	if ((address && address->hasParam("isfocus")) || confInfo)
 		localDesc.cfgs[localDesc.getChosenConfigurationIndex()].conference_ssrc =
 		    mSessions.rtp_session ? rtp_session_get_send_ssrc(mSessions.rtp_session) : 0;
 
@@ -774,8 +773,8 @@ void MS2Stream::configureRtpSession(RtpSession *session) {
 	rtp_session_enable_network_simulation(session, &getCCore()->net_conf.netsim_params);
 	applyJitterBufferParams(session);
 	string userAgent = linphone_core_get_user_agent(getCCore());
-	rtp_session_set_source_description(session, getMediaSessionPrivate().getMe()->getAddress().asString().c_str(), NULL,
-	                                   NULL, NULL, NULL, userAgent.c_str(), NULL);
+	rtp_session_set_source_description(session, getMediaSessionPrivate().getMe()->getAddress()->toString().c_str(),
+	                                   NULL, NULL, NULL, NULL, userAgent.c_str(), NULL);
 	rtp_session_set_symmetric_rtp(session, linphone_core_symmetric_rtp_enabled(getCCore()));
 
 	if (getType() == SalVideo) {
diff --git a/src/conference/session/streams.h b/src/conference/session/streams.h
index d14eb34f4d5855540a24aedbeeb39815952bfe8b..7a80e089a2bac54a25721b01f33c14bfa48b3460 100644
--- a/src/conference/session/streams.h
+++ b/src/conference/session/streams.h
@@ -18,8 +18,8 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef STREAMS_Hstreams_h
-#define STREAMS_Hstreams_h
+#ifndef STREAMS_H
+#define STREAMS_H
 
 #include <iostream>
 #include <map>
@@ -28,10 +28,11 @@
 
 #include <bctoolbox/defs.h>
 
+#include "mediastreamer2/msmire.h"
+
 #include "call-session.h"
 #include "call/audio-device/audio-device.h"
 #include "media-description-renderer.h"
-#include "mediastreamer2/msmire.h"
 #include "port-config.h"
 #include "tester_utils.h"
 
@@ -206,16 +207,6 @@ private:
 	bool mIsMain = false;
 };
 
-inline std::ostream &operator<<(std::ostream &ostr, SalStreamType type) {
-	ostr << sal_stream_type_to_string(type);
-	return ostr;
-}
-
-inline std::ostream &operator<<(std::ostream &ostr, SalMediaProto proto) {
-	ostr << sal_media_proto_to_string(proto);
-	return ostr;
-}
-
 inline std::ostream &operator<<(std::ostream &ostr, const Stream &stream) {
 	ostr << "stream#" << stream.getIndex() << " [" << stream.getType() << "] in state ["
 	     << Stream::stateToString(stream.getState()) << "]";
diff --git a/src/conference/session/tone-manager.h b/src/conference/session/tone-manager.h
index 3ff626f725210739c14fe8aa3ae9854a77598892..79a7242793b626c35fc32147ccc0f56be5d3dd58 100644
--- a/src/conference/session/tone-manager.h
+++ b/src/conference/session/tone-manager.h
@@ -61,6 +61,7 @@ public:
 	/* Used to temporarily override the audio output device. */
 	void setOutputDevice(const std::shared_ptr<CallSession> &session, const std::shared_ptr<AudioDevice> &audioDevice);
 	std::shared_ptr<AudioDevice> getOutputDevice(const std::shared_ptr<CallSession> &session) const;
+
 	/* Request the tone manager to immediately abandon any sound card usage. All running rings or tones are dropped. */
 	void freeAudioResources();
 
diff --git a/src/conference/session/video-mixer.cpp b/src/conference/session/video-mixer.cpp
index 24b4d5615dcf161f36d209ed56eca7ac9965691f..b8de90a7a4e70c67b6cb143b68cd6b293ecb03a3 100644
--- a/src/conference/session/video-mixer.cpp
+++ b/src/conference/session/video-mixer.cpp
@@ -20,14 +20,13 @@
 
 #include <bctoolbox/defs.h>
 
-#include "mixers.h"
-#include "streams.h"
+#include "mediastreamer2/msitc.h"
 
+#include "c-wrapper/internal/c-tools.h"
 #include "linphone/core.h"
+#include "mixers.h"
 #include "private.h"
-
-#include "c-wrapper/internal/c-tools.h"
-#include "mediastreamer2/msitc.h"
+#include "streams.h"
 
 LINPHONE_BEGIN_NAMESPACE
 
diff --git a/src/core/core-accessor.h b/src/core/core-accessor.h
index 49209deb3236d3e7077b52776a72aadb186ace92..3caa74e1f33d600e08f44adcb591b80515e722c9 100644
--- a/src/core/core-accessor.h
+++ b/src/core/core-accessor.h
@@ -38,7 +38,6 @@ public:
 
 	// Returns a valid core instance. Or throw one std::bad_weak_ptr exception if core is destroyed.
 	std::shared_ptr<Core> getCore() const;
-
 	void setCore(std::shared_ptr<Core> core);
 
 private:
diff --git a/src/core/core-call.cpp b/src/core/core-call.cpp
index ba0a402f28d2f2ab45d47328f5a4294bf3c26a8f..800b12f3a474e64fbd16e15d8a2b6beb98cbb9cc 100644
--- a/src/core/core-call.cpp
+++ b/src/core/core-call.cpp
@@ -92,9 +92,9 @@ bool CorePrivate::inviteReplacesABrokenCall(SalCallOp *op) {
 	return false;
 }
 
-bool CorePrivate::isAlreadyInCallWithAddress(const Address &addr) const {
+bool CorePrivate::isAlreadyInCallWithAddress(const std::shared_ptr<Address> &addr) const {
 	for (const auto &call : calls) {
-		if (call->isOpConfigured() && call->getRemoteAddress()->weakEqual(addr)) return true;
+		if (call->isOpConfigured() && call->getRemoteAddress()->weakEqual(*addr)) return true;
 	}
 	return false;
 }
@@ -133,12 +133,12 @@ int CorePrivate::removeCall(const shared_ptr<Call> &call) {
 	L_ASSERT(call);
 	auto iter = find(calls.begin(), calls.end(), call);
 	if (iter == calls.end()) {
-		lWarning() << "Could not find the call (local address " << call->getLocalAddress().asString()
-		           << " remote address " << call->getRemoteAddress()->asString() << ") to remove";
+		lWarning() << "Could not find the call (local address " << call->getLocalAddress()->toString()
+		           << " remote address " << call->getRemoteAddress()->toString() << ") to remove";
 		return -1;
 	}
-	lInfo() << "Removing the call (local address " << call->getLocalAddress().asString() << " remote address "
-	        << (call->getRemoteAddress() ? call->getRemoteAddress()->asString() : "Unknown")
+	lInfo() << "Removing the call (local address " << call->getLocalAddress()->toString() << " remote address "
+	        << (call->getRemoteAddress() ? call->getRemoteAddress()->toString() : "Unknown")
 	        << ") from the list attached to the core";
 
 	calls.erase(iter);
@@ -221,8 +221,8 @@ bool Core::areSoundResourcesLocked() const {
 				case CallSession::State::Referred:
 				case CallSession::State::IncomingEarlyMedia:
 				case CallSession::State::Updating:
-					lInfo() << "Call " << call << " (local address " << call->getLocalAddress().asString()
-					        << " remote address " << call->getRemoteAddress()->asString()
+					lInfo() << "Call " << call << " (local address " << call->getLocalAddress()->toString()
+					        << " remote address " << call->getRemoteAddress()->toString()
 					        << ") is locking sound resources because it is state " << call->getState();
 					return true;
 				case CallSession::State::Connected:
@@ -230,8 +230,8 @@ bool Core::areSoundResourcesLocked() const {
 					return !call->getConference();
 				case CallSession::State::StreamsRunning:
 					if (call->mediaInProgress()) {
-						lInfo() << "Call " << call << " (local address " << call->getLocalAddress().asString()
-						        << " remote address " << call->getRemoteAddress()->asString()
+						lInfo() << "Call " << call << " (local address " << call->getLocalAddress()->toString()
+						        << " remote address " << call->getRemoteAddress()->toString()
 						        << ") is locking sound resources because it is state " << call->getState()
 						        << " and media is in progress";
 						return true;
@@ -245,10 +245,10 @@ bool Core::areSoundResourcesLocked() const {
 	return false;
 }
 
-shared_ptr<Call> Core::getCallByRemoteAddress(const Address &addr) const {
+shared_ptr<Call> Core::getCallByRemoteAddress(const std::shared_ptr<Address> &addr) const {
 	L_D();
 	for (const auto &call : d->calls) {
-		if (call->getRemoteAddress()->weakEqual(addr)) return call;
+		if (call->getRemoteAddress()->weakEqual(*addr)) return call;
 	}
 	return nullptr;
 }
@@ -340,6 +340,7 @@ LinphoneStatus Core::terminateAllCalls() {
 void Core::reportConferenceCallEvent(EventLog::Type type,
                                      std::shared_ptr<CallLog> &callLog,
                                      std::shared_ptr<ConferenceInfo> confInfo) {
+	std::shared_ptr<Address> to = callLog->getToAddress() ? callLog->getToAddress() : nullptr;
 	// TODO: This is a workaround that has to be removed ASAP
 #ifdef HAVE_DB_STORAGE
 	L_D();
@@ -348,9 +349,7 @@ void Core::reportConferenceCallEvent(EventLog::Type type,
 
 	if (confInfo == nullptr) {
 		// Let's see if we have a conference info in db with the corresponding URI
-		confInfo = callLog->wasConference() ? callLog->getConferenceInfo()
-		                                    : d->mainDb->getConferenceInfoFromURI(ConferenceAddress(
-		                                          *L_GET_CPP_PTR_FROM_C_OBJECT(callLog->getToAddress())));
+		confInfo = callLog->wasConference() ? callLog->getConferenceInfo() : d->mainDb->getConferenceInfoFromURI(to);
 	}
 #endif
 
@@ -358,38 +357,33 @@ void Core::reportConferenceCallEvent(EventLog::Type type,
 	// that have been merged in a conference. In fact, in such a scenario, the client that merges calls to put them in a
 	// conference will call the conference factory or the audio video conference factory directly but still its call
 	// must be added to the call logs
-	if (!confInfo) {
+	if (!confInfo && to) {
 		// Do not add calls made to the conference factory in the history
-		LinphoneAccount *account = linphone_core_lookup_known_account(getCCore(), callLog->getToAddress());
+		LinphoneAccount *account = linphone_core_lookup_known_account(getCCore(), to->toC());
+		std::shared_ptr<Address> from = callLog->getFromAddress() ? callLog->getFromAddress() : nullptr;
 		if (account) {
 			string conferenceFactoryUri = Account::toCpp(account)->getAccountParams()->getConferenceFactoryUri();
 			if (!conferenceFactoryUri.empty()) {
-				LinphoneAddress *conference_factory_addr = linphone_address_new(conferenceFactoryUri.c_str());
-				if (conference_factory_addr) {
-					if (linphone_address_weak_equal(callLog->getToAddress(), conference_factory_addr)) {
-						linphone_address_unref(conference_factory_addr);
-						return;
-					}
-					linphone_address_unref(conference_factory_addr);
+				std::shared_ptr<Address> conferenceFactory = Address::create(conferenceFactoryUri);
+				if (to->weakEqual(*conferenceFactory)) {
+					return;
 				}
 			}
 			// Do not add calls made to the audio/video conference factory in the history either
-			const LinphoneAddress *audioVideoConferenceFactoryAddress =
+			const auto &audioVideoConferenceFactoryAddress =
 			    Account::toCpp(account)->getAccountParams()->getAudioVideoConferenceFactoryAddress();
 			if (audioVideoConferenceFactoryAddress != nullptr) {
-				if (linphone_address_weak_equal(callLog->getToAddress(), audioVideoConferenceFactoryAddress)) {
+				if (to->weakEqual(*audioVideoConferenceFactoryAddress)) {
 					return;
 				}
 			}
 		}
 
 		// For PushIncomingState call, from and to address are unknow.
-		const char *usernameFrom =
-		    callLog->getFromAddress() ? linphone_address_get_username(callLog->getFromAddress()) : nullptr;
-		const char *usernameTo =
-		    callLog->getToAddress() ? linphone_address_get_username(callLog->getToAddress()) : nullptr;
-		if ((usernameFrom && (strstr(usernameFrom, "chatroom-") == usernameFrom)) ||
-		    (usernameTo && (strstr(usernameTo, "chatroom-") == usernameTo)))
+		const std::string usernameFrom = from ? from->getUsername() : std::string();
+		const std::string usernameTo = to ? to->getUsername() : std::string();
+		if ((!usernameFrom.empty() && (usernameFrom.find("chatroom-") != std::string::npos)) ||
+		    (!usernameTo.empty() && (usernameTo.find("chatroom-") != std::string::npos)))
 			return;
 	}
 	// End of workaround
@@ -436,8 +430,11 @@ void Core::reportConferenceCallEvent(EventLog::Type type,
 #pragma GCC diagnostic pop
 #endif // _MSC_VER
 
-void Core::reportEarlyCallFailed(
-    LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress *to, LinphoneErrorInfo *ei, const std::string callId) {
+void Core::reportEarlyCallFailed(LinphoneCallDir dir,
+                                 const std::shared_ptr<Address> &from,
+                                 const std::shared_ptr<Address> &to,
+                                 LinphoneErrorInfo *ei,
+                                 const std::string callId) {
 	auto callLog = CallLog::create(getSharedFromThis(), dir, from, to);
 	callLog->setErrorInfo(ei);
 	callLog->setStatus(LinphoneCallEarlyAborted);
diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp
index baee214c80553ff471cf834425334d8cee24b938..daed5bacf871fae79397f300fb90efab3f09619f 100644
--- a/src/core/core-chat-room.cpp
+++ b/src/core/core-chat-room.cpp
@@ -24,7 +24,7 @@
 
 #include "linphone/utils/algorithm.h"
 
-#include "address/identity-address.h"
+#include "address/address.h"
 #include "chat/chat-room/abstract-chat-room.h"
 #include "chat/chat-room/basic-chat-room.h"
 #include "chat/chat-room/chat-room-p.h"
@@ -60,48 +60,44 @@ LINPHONE_BEGIN_NAMESPACE
  * If withGruu is true, returns the local address with its gruu parameter. FlexisipChat kind of chatroom (also refered
  * as ClientGroupChatRoom) require a local address with gruu, unlike basic chatrooms.
  */
-IdentityAddress CorePrivate::getDefaultLocalAddress(const IdentityAddress *peerAddress, bool withGruu) const {
+std::shared_ptr<const Address> CorePrivate::getDefaultLocalAddress(const std::shared_ptr<Address> peerAddress,
+                                                                   bool withGruu) const {
 	LinphoneCore *cCore = getCCore();
 	LinphoneProxyConfig *proxy = nullptr;
 
 	if (peerAddress) {
-		LinphoneAddress *cPeerAddress = linphone_address_new(peerAddress->asString().c_str());
+		LinphoneAddress *cPeerAddress = peerAddress->toC();
 		if (cPeerAddress) {
 			proxy = linphone_core_lookup_known_proxy(cCore, cPeerAddress);
-			linphone_address_unref(cPeerAddress);
 		}
 	}
 
 	if (!proxy) proxy = linphone_core_get_default_proxy_config(cCore);
 
-	IdentityAddress localAddress;
+	std::shared_ptr<const Address> localAddress = nullptr;
 	if (proxy) {
-		char *identity = linphone_address_as_string((withGruu && linphone_proxy_config_get_contact(proxy))
-		                                                ? linphone_proxy_config_get_contact(proxy)
-		                                                : linphone_proxy_config_get_identity_address(proxy));
-		localAddress = IdentityAddress(identity);
-		bctbx_free(identity);
-	} else localAddress = IdentityAddress(linphone_core_get_primary_contact(cCore));
-
+		const LinphoneAddress *identity = (withGruu && linphone_proxy_config_get_contact(proxy))
+		                                      ? linphone_proxy_config_get_contact(proxy)
+		                                      : linphone_proxy_config_get_identity_address(proxy);
+		localAddress = Address::toCpp(identity)->getSharedFromThis();
+	} else {
+		localAddress = Address::create(linphone_core_get_primary_contact(cCore));
+	}
 	return localAddress;
 }
 
-IdentityAddress CorePrivate::getIdentityAddressWithGruu(const IdentityAddress &identityAddress) const {
-	LinphoneCore *cCore = getCCore();
-	LinphoneProxyConfig *proxyConfig = nullptr;
-	IdentityAddress identityAddressWithGruu;
+std::shared_ptr<const Address>
+CorePrivate::getIdentityAddressWithGruu(const std::shared_ptr<const Address> &identityAddress) const {
+	std::shared_ptr<const Address> identityAddressWithGruu;
 
-	if (identityAddress.isValid()) {
-		LinphoneAddress *cIdentityAddress = linphone_address_new(identityAddress.asString().c_str());
-		proxyConfig = linphone_core_lookup_known_proxy(cCore, cIdentityAddress);
-		linphone_address_unref(cIdentityAddress);
+	if (identityAddress && identityAddress->isValid()) {
+		LinphoneCore *cCore = getCCore();
+		LinphoneProxyConfig *proxyConfig = linphone_core_lookup_known_proxy(cCore, identityAddress->toC());
 
 		if (proxyConfig) {
 			const LinphoneAddress *contactAddress = linphone_proxy_config_get_contact(proxyConfig);
 			if (contactAddress) {
-				char *contact = linphone_address_as_string(contactAddress);
-				identityAddressWithGruu = IdentityAddress(contact);
-				bctbx_free(contact);
+				identityAddressWithGruu = Address::toCpp(contactAddress)->getSharedFromThis();
 			}
 		}
 	}
@@ -116,13 +112,14 @@ IdentityAddress CorePrivate::getIdentityAddressWithGruu(const IdentityAddress &i
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
 // Base client group chat room creator
-shared_ptr<AbstractChatRoom> CorePrivate::createClientGroupChatRoom(const std::string &subject,
-                                                                    const IdentityAddress &conferenceFactoryUri,
-                                                                    const ConferenceId &conferenceId,
-                                                                    const Content &content,
-                                                                    AbstractChatRoom::CapabilitiesMask capabilities,
-                                                                    const std::shared_ptr<ChatRoomParams> &params,
-                                                                    bool fallback) {
+shared_ptr<AbstractChatRoom>
+CorePrivate::createClientGroupChatRoom(const std::string &subject,
+                                       const std::shared_ptr<Address> &conferenceFactoryUri,
+                                       const ConferenceId &conferenceId,
+                                       const Content &content,
+                                       AbstractChatRoom::CapabilitiesMask capabilities,
+                                       const std::shared_ptr<ChatRoomParams> &params,
+                                       bool fallback) {
 #ifdef HAVE_ADVANCED_IM
 	L_Q();
 
@@ -130,8 +127,8 @@ shared_ptr<AbstractChatRoom> CorePrivate::createClientGroupChatRoom(const std::s
 		lWarning() << "Invalid chat room parameters given for client group chat room creation";
 		return nullptr;
 	}
-	if (!conferenceId.getLocalAddress().hasGruu()) {
-		lError() << "createClientGroupChatRoom(): local address [" << conferenceId.getLocalAddress()
+	if (!conferenceId.getLocalAddress()->hasUriParam("gr")) {
+		lError() << "createClientGroupChatRoom(): local address [" << conferenceId.getLocalAddress()->toString()
 		         << "] must have a gruu.";
 		return nullptr;
 	}
@@ -198,14 +195,14 @@ shared_ptr<AbstractChatRoom>
 CorePrivate::createClientGroupChatRoom(const string &subject, bool fallback, bool encrypted) {
 	L_Q();
 
-	IdentityAddress defaultLocalAddress = getDefaultLocalAddress(nullptr, true);
-	IdentityAddress conferenceFactoryUri(Core::getConferenceFactoryUri(q->getSharedFromThis(), defaultLocalAddress));
+	auto defaultLocalAddress = getDefaultLocalAddress(nullptr, true);
+	std::shared_ptr<Address> conferenceFactoryUri =
+	    Address::create(Core::getConferenceFactoryUri(q->getSharedFromThis(), defaultLocalAddress));
 	shared_ptr<ChatRoomParams> params =
 	    ChatRoomParams::create(subject, encrypted, !fallback, ChatRoomParams::ChatRoomBackend::FlexisipChat);
 
-	return createClientGroupChatRoom(subject, conferenceFactoryUri,
-	                                 ConferenceId(IdentityAddress(), defaultLocalAddress), Content(),
-	                                 ChatRoomParams::toCapabilities(params), params, fallback);
+	return createClientGroupChatRoom(subject, conferenceFactoryUri, ConferenceId(nullptr, defaultLocalAddress),
+	                                 Content(), ChatRoomParams::toCapabilities(params), params, fallback);
 }
 
 shared_ptr<AbstractChatRoom> CorePrivate::createBasicChatRoom(const ConferenceId &conferenceId,
@@ -237,17 +234,18 @@ shared_ptr<AbstractChatRoom> CorePrivate::createBasicChatRoom(const ConferenceId
 	return chatRoom;
 }
 
-shared_ptr<AbstractChatRoom> CorePrivate::searchChatRoom(const shared_ptr<ChatRoomParams> &params,
-                                                         const IdentityAddress &localAddress,
-                                                         const IdentityAddress &remoteAddress,
-                                                         const std::list<IdentityAddress> &participants) const {
+shared_ptr<AbstractChatRoom>
+CorePrivate::searchChatRoom(const shared_ptr<ChatRoomParams> &params,
+                            const std::shared_ptr<const Address> &localAddress,
+                            const std::shared_ptr<const Address> &remoteAddress,
+                            const std::list<std::shared_ptr<Address>> &participants) const {
 	for (auto it = chatRoomsById.begin(); it != chatRoomsById.end(); it++) {
 		const auto &chatRoom = it->second;
-		const IdentityAddress &curLocalAddress = chatRoom->getLocalAddress();
-		const IdentityAddress &curRemoteAddress = chatRoom->getPeerAddress();
-		ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities();
+		std::shared_ptr<Address> curLocalAddress = chatRoom->getLocalAddress();
+		std::shared_ptr<Address> curRemoteAddress = chatRoom->getPeerAddress();
 
 		if (params) {
+			ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities();
 			if (params->getChatRoomBackend() != chatRoom->getCurrentParams()->getChatRoomBackend()) continue;
 
 			if (!params->isGroup() && !(capabilities & ChatRoom::Capabilities::OneToOne)) continue;
@@ -259,17 +257,15 @@ shared_ptr<AbstractChatRoom> CorePrivate::searchChatRoom(const shared_ptr<ChatRo
 			if (!params->getSubject().empty() && params->getSubject() != chatRoom->getSubject()) continue;
 		}
 
-		if (localAddress.getAddressWithoutGruu() != curLocalAddress.getAddressWithoutGruu()) continue;
+		if (localAddress && localAddress->isValid() && (!localAddress->weakEqual(*curLocalAddress))) continue;
 
-		if (remoteAddress.isValid() &&
-		    remoteAddress.getAddressWithoutGruu() != curRemoteAddress.getAddressWithoutGruu())
-			continue;
+		if (remoteAddress && remoteAddress->isValid() && (!remoteAddress->weakEqual(*curRemoteAddress))) continue;
 
 		bool allFound = true;
 		for (const auto &participant : participants) {
 			bool found = false;
 			for (const auto &p : chatRoom->getParticipants()) {
-				if (p->getAddress().getAddressWithoutGruu() == participant.getAddressWithoutGruu()) {
+				if (participant->weakEqual(*(p->getAddress()))) {
 					found = true;
 					break;
 				}
@@ -287,16 +283,16 @@ shared_ptr<AbstractChatRoom> CorePrivate::searchChatRoom(const shared_ptr<ChatRo
 }
 
 shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const shared_ptr<ChatRoomParams> &params,
-                                                         const IdentityAddress &localAddr,
+                                                         const std::shared_ptr<const Address> &localAddr,
                                                          const std::string &subject,
-                                                         const std::list<IdentityAddress> &participants) {
+                                                         const std::list<std::shared_ptr<Address>> &participants) {
 	params->setSubject(subject);
 	return createChatRoom(params, localAddr, participants);
 }
 
 shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const shared_ptr<ChatRoomParams> &params,
-                                                         const IdentityAddress &localAddr,
-                                                         const std::list<IdentityAddress> &participants) {
+                                                         const std::shared_ptr<const Address> &localAddr,
+                                                         const std::list<std::shared_ptr<Address>> &participants) {
 #ifdef HAVE_ADVANCED_IM
 	L_Q();
 #endif
@@ -324,13 +320,13 @@ shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const shared_ptr<ChatRo
 			return nullptr;
 		}
 
-		ConferenceId conferenceId = ConferenceId(IdentityAddress(), localAddr);
-		if (!localAddr.hasGruu()) {
-			lWarning() << "Local identity address [" << localAddr << "] doesn't have a gruu, let's try to find it";
-			IdentityAddress localAddrWithGruu = getIdentityAddressWithGruu(localAddr);
-			if (localAddrWithGruu.isValid()) {
-				lInfo() << "Found matching contact address [" << localAddrWithGruu << "] to use instead";
-				conferenceId = ConferenceId(IdentityAddress(), localAddrWithGruu);
+		ConferenceId conferenceId = ConferenceId(nullptr, localAddr);
+		if (!localAddr->hasUriParam("gr")) {
+			lWarning() << "Local identity address [" << *localAddr << "] doesn't have a gruu, let's try to find it";
+			auto localAddrWithGruu = getIdentityAddressWithGruu(localAddr);
+			if (localAddrWithGruu && localAddrWithGruu->isValid()) {
+				lInfo() << "Found matching contact address [" << *localAddrWithGruu << "] to use instead";
+				conferenceId = ConferenceId(nullptr, localAddrWithGruu);
 			} else {
 				lError() << "Failed to find matching contact address with gruu for identity address [" << localAddr
 				         << "], client group chat room creation will fail!";
@@ -345,8 +341,9 @@ shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const shared_ptr<ChatRo
 			}
 		}
 
-		chatRoom = createClientGroupChatRoom(params->getSubject(), IdentityAddress(conferenceFactoryUri), conferenceId,
-		                                     Content(), ChatRoomParams::toCapabilities(params), params, false);
+		std::shared_ptr<Address> conferenceFactory = Address::create(conferenceFactoryUri);
+		chatRoom = createClientGroupChatRoom(params->getSubject(), conferenceFactory, conferenceId, Content(),
+		                                     ChatRoomParams::toCapabilities(params), params, false);
 
 		if (!chatRoom) {
 			lWarning() << "Cannot create createClientGroupChatRoom with subject [" << params->getSubject() << "]";
@@ -367,8 +364,8 @@ shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const shared_ptr<ChatRo
 		}
 		ChatRoom::CapabilitiesMask capabilities = ChatRoomParams::toCapabilities(params);
 
-		IdentityAddress remoteAddr = IdentityAddress(participants.front());
-		list<IdentityAddress> emptyList;
+		std::shared_ptr<Address> remoteAddr = participants.front();
+		std::list<std::shared_ptr<Address>> emptyList;
 		chatRoom = searchChatRoom(params, localAddr, remoteAddr, emptyList);
 
 		if (chatRoom == nullptr) {
@@ -384,14 +381,14 @@ shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const shared_ptr<ChatRo
 
 shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const shared_ptr<ChatRoomParams> &params,
                                                          const std::string &subject,
-                                                         const std::list<IdentityAddress> &participants) {
-	IdentityAddress defaultLocalAddress =
+                                                         const std::list<std::shared_ptr<Address>> &participants) {
+	auto defaultLocalAddress =
 	    getDefaultLocalAddress(nullptr, params->getChatRoomBackend() == ChatRoomParams::ChatRoomBackend::FlexisipChat);
 	return createChatRoom(params, defaultLocalAddress, subject, participants);
 }
 
 shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const std::string &subject,
-                                                         const std::list<IdentityAddress> &participants) {
+                                                         const std::list<std::shared_ptr<Address>> &participants) {
 	L_Q();
 
 	shared_ptr<ChatRoomParams> params = ChatRoomParams::getDefaults(q->getSharedFromThis());
@@ -401,19 +398,19 @@ shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const std::string &subj
 	} else {
 		params->setChatRoomBackend(ChatRoomParams::ChatRoomBackend::Basic);
 	}
-	IdentityAddress defaultLocalAddress =
+	auto defaultLocalAddress =
 	    getDefaultLocalAddress(nullptr, params->getChatRoomBackend() == ChatRoomParams::ChatRoomBackend::FlexisipChat);
 	return createChatRoom(params, defaultLocalAddress, subject, participants);
 }
 
 shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const shared_ptr<ChatRoomParams> &params,
-                                                         const IdentityAddress &localAddr,
-                                                         const IdentityAddress &participant) {
+                                                         const std::shared_ptr<Address> &localAddr,
+                                                         const std::shared_ptr<Address> &participant) {
 	return createChatRoom(params, localAddr, "", {participant});
 }
 
 // Assume basic chat room creation
-shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const IdentityAddress &participant) {
+shared_ptr<AbstractChatRoom> CorePrivate::createChatRoom(const std::shared_ptr<Address> &participant) {
 	return createChatRoom("", {participant});
 }
 
@@ -421,7 +418,6 @@ void CorePrivate::insertChatRoom(const shared_ptr<AbstractChatRoom> &chatRoom) {
 	L_ASSERT(chatRoom);
 	const ConferenceId &conferenceId = chatRoom->getConferenceId();
 	auto it = chatRoomsById.find(conferenceId);
-	// Chat room not exist or yes but with the same pointer!
 	L_ASSERT(it == chatRoomsById.end() || it->second == chatRoom);
 	if (it == chatRoomsById.end()) {
 		// Remove chat room from workaround cache.
@@ -561,33 +557,32 @@ void CorePrivate::replaceChatRoom(const shared_ptr<AbstractChatRoom> &replacedCh
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
-shared_ptr<AbstractChatRoom> CorePrivate::findExhumableOneToOneChatRoom(const IdentityAddress &localAddress,
-                                                                        const IdentityAddress &participantAddress,
-                                                                        bool encrypted) const {
+shared_ptr<AbstractChatRoom>
+CorePrivate::findExhumableOneToOneChatRoom(const std::shared_ptr<Address> &localAddress,
+                                           const std::shared_ptr<Address> &participantAddress,
+                                           bool encrypted) const {
 #ifdef HAVE_ADVANCED_IM
-	lInfo() << "Looking for exhumable 1-1 chat room with local address [" << localAddress.asString()
-	        << "] and participant [" << participantAddress.asString() << "]";
+	lInfo() << "Looking for exhumable 1-1 chat room with local address [" << localAddress->toString()
+	        << "] and participant [" << participantAddress->toString() << "]";
 
 	for (auto it = chatRoomsById.begin(); it != chatRoomsById.end(); it++) {
 		const auto &chatRoom = it->second;
-		const IdentityAddress &curLocalAddress = chatRoom->getLocalAddress();
+		const std::shared_ptr<Address> &curLocalAddress = chatRoom->getLocalAddress();
 		ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities();
 		// Don't check if terminated, it can be exhumed before the BYE has been received
 		if (/*chatRoom->getState() == ChatRoom::State::Terminated
 		        && */
 		    capabilities & ChatRoom::Capabilities::Conference && capabilities & ChatRoom::Capabilities::OneToOne &&
 		    encrypted == bool(capabilities & ChatRoom::Capabilities::Encrypted)) {
-			if (chatRoom->getParticipants().size() > 0 &&
-			    localAddress.getAddressWithoutGruu() == curLocalAddress.getAddressWithoutGruu() &&
-			    participantAddress.getAddressWithoutGruu() ==
-			        chatRoom->getParticipants().front()->getAddress().getAddressWithoutGruu()) {
+			if (chatRoom->getParticipants().size() > 0 && localAddress->weakEqual(*curLocalAddress) &&
+			    participantAddress->weakEqual(*chatRoom->getParticipants().front()->getAddress())) {
 				return chatRoom;
 			}
 		}
 	}
 
-	lInfo() << "Unable to find exhumable 1-1 chat room with local address [" << localAddress.asString()
-	        << "] and participant [" << participantAddress.asString() << "]";
+	lInfo() << "Unable to find exhumable 1-1 chat room with local address [" << localAddress->toString()
+	        << "] and participant [" << participantAddress->toString() << "]";
 #endif
 	return nullptr;
 }
@@ -654,12 +649,10 @@ static bool compare_chat_room(const shared_ptr<AbstractChatRoom> &first, const s
 	return first->getLastUpdateTime() > second->getLastUpdateTime();
 }
 
-//
-string Core::getConferenceFactoryUri(const shared_ptr<Core> &core, const IdentityAddress &localAddress) {
-	Address addr(localAddress.asAddress());
-	LinphoneAccount *account = linphone_core_lookup_account_by_identity(core->getCCore(), L_GET_C_BACK_PTR(&addr));
+string Core::getConferenceFactoryUri(const shared_ptr<Core> &core, const std::shared_ptr<const Address> &localAddress) {
+	LinphoneAccount *account = linphone_core_lookup_account_by_identity(core->getCCore(), localAddress->toC());
 	if (!account) {
-		lWarning() << "No account found for local address: [" << localAddress.asString() << "]";
+		lWarning() << "No account found for local address: [" << localAddress->toString() << "]";
 		return string();
 	} else return getConferenceFactoryUri(core, account);
 }
@@ -701,7 +694,8 @@ list<shared_ptr<AbstractChatRoom>> Core::getChatRooms() const {
 			for (it = linphone_core_get_proxy_config_list(lc); it != NULL; it = it->next) {
 				LinphoneProxyConfig *cfg = (LinphoneProxyConfig *)it->data;
 				const LinphoneAddress *identityAddr = linphone_proxy_config_get_identity_address(cfg);
-				if (L_GET_CPP_PTR_FROM_C_OBJECT(identityAddr)->weakEqual(chatRoom->getLocalAddress().asAddress())) {
+				auto localAddress = Address::toCpp(const_cast<LinphoneAddress *>(identityAddr))->getSharedFromThis();
+				if (localAddress->weakEqual(*chatRoom->getLocalAddress())) {
 					found = true;
 					break;
 				}
@@ -738,13 +732,13 @@ shared_ptr<AbstractChatRoom> Core::findChatRoom(const ConferenceId &conferenceId
 	return nullptr;
 }
 
-list<shared_ptr<AbstractChatRoom>> Core::findChatRooms(const IdentityAddress &peerAddress) const {
+list<shared_ptr<AbstractChatRoom>> Core::findChatRooms(const std::shared_ptr<Address> &peerAddress) const {
 	L_D();
 
 	list<shared_ptr<AbstractChatRoom>> output;
 	for (auto it = d->chatRoomsById.begin(); it != d->chatRoomsById.end(); it++) {
 		const auto &chatRoom = it->second;
-		if (chatRoom->getPeerAddress() == peerAddress) {
+		if (*chatRoom->getPeerAddress() == *peerAddress) {
 			output.push_front(chatRoom);
 		}
 	}
@@ -752,15 +746,15 @@ list<shared_ptr<AbstractChatRoom>> Core::findChatRooms(const IdentityAddress &pe
 	return output;
 }
 
-shared_ptr<AbstractChatRoom> Core::findOneToOneChatRoom(const IdentityAddress &localAddress,
-                                                        const IdentityAddress &participantAddress,
+shared_ptr<AbstractChatRoom> Core::findOneToOneChatRoom(const std::shared_ptr<const Address> &localAddress,
+                                                        const std::shared_ptr<Address> &participantAddress,
                                                         bool basicOnly,
                                                         bool conferenceOnly,
                                                         bool encrypted) const {
 	L_D();
 	for (auto it = d->chatRoomsById.begin(); it != d->chatRoomsById.end(); it++) {
 		const auto &chatRoom = it->second;
-		const IdentityAddress &curLocalAddress = chatRoom->getLocalAddress();
+		const std::shared_ptr<Address> &curLocalAddress = chatRoom->getLocalAddress();
 		ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities();
 
 		// We are looking for a one to one chatroom
@@ -772,15 +766,14 @@ shared_ptr<AbstractChatRoom> Core::findOneToOneChatRoom(const IdentityAddress &l
 		// One to one client group chat room
 		// The only participant's address must match the participantAddress argument
 		if (!basicOnly && (capabilities & ChatRoom::Capabilities::Conference) && !chatRoom->getParticipants().empty() &&
-		    localAddress.getAddressWithoutGruu() == curLocalAddress.getAddressWithoutGruu() &&
-		    participantAddress.getAddressWithoutGruu() == chatRoom->getParticipants().front()->getAddress())
+		    localAddress->weakEqual(*curLocalAddress) &&
+		    participantAddress->weakEqual(*chatRoom->getParticipants().front()->getAddress()))
 			return chatRoom;
 
 		// One to one basic chat room (addresses without gruu)
 		// The peer address must match the participantAddress argument
 		if (!conferenceOnly && (capabilities & ChatRoom::Capabilities::Basic) &&
-		    localAddress.getAddressWithoutGruu() == curLocalAddress.getAddressWithoutGruu() &&
-		    participantAddress.getAddressWithoutGruu() == chatRoom->getPeerAddress().getAddressWithoutGruu())
+		    localAddress->weakEqual(*curLocalAddress) && participantAddress->weakEqual(*chatRoom->getPeerAddress()))
 			return chatRoom;
 	}
 	return nullptr;
@@ -804,8 +797,8 @@ shared_ptr<AbstractChatRoom> Core::getOrCreateBasicChatRoom(const ConferenceId &
 	return chatRoom;
 }
 
-shared_ptr<AbstractChatRoom> Core::getOrCreateBasicChatRoom(const IdentityAddress &localAddress,
-                                                            const IdentityAddress &peerAddress) {
+shared_ptr<AbstractChatRoom> Core::getOrCreateBasicChatRoom(const std::shared_ptr<Address> &localAddress,
+                                                            const std::shared_ptr<Address> &peerAddress) {
 	L_D();
 
 	shared_ptr<AbstractChatRoom> chatRoom = findOneToOneChatRoom(localAddress, peerAddress, true, false, false);
@@ -815,10 +808,10 @@ shared_ptr<AbstractChatRoom> Core::getOrCreateBasicChatRoom(const IdentityAddres
 	if (d->basicToFlexisipChatroomMigrationEnabled()) {
 		capabilities |= ChatRoom::Capabilities::Migratable;
 	}
-	chatRoom = d->createBasicChatRoom(
-	    ConferenceId(peerAddress,
-	                 (localAddress.isValid() ? localAddress : d->getDefaultLocalAddress(&peerAddress, false))),
-	    capabilities, ChatRoomParams::fromCapabilities(capabilities));
+	chatRoom = d->createBasicChatRoom(ConferenceId(peerAddress, (localAddress && localAddress->isValid()
+	                                                                 ? localAddress
+	                                                                 : d->getDefaultLocalAddress(peerAddress, false))),
+	                                  capabilities, ChatRoomParams::fromCapabilities(capabilities));
 	d->insertChatRoom(chatRoom);
 	d->insertChatRoomWithDb(chatRoom);
 
@@ -827,13 +820,13 @@ shared_ptr<AbstractChatRoom> Core::getOrCreateBasicChatRoom(const IdentityAddres
 
 shared_ptr<AbstractChatRoom> Core::getOrCreateBasicChatRoomFromUri(const std::string &localAddressUri,
                                                                    const std::string &peerAddressUri) {
-	Address peerAddress(interpretUrl(peerAddressUri, true));
-	if (!peerAddress.isValid()) {
+	std::shared_ptr<Address> peerAddress(interpretUrl(peerAddressUri, true));
+	if (!peerAddress || !peerAddress->isValid()) {
 		lError() << "Cannot make a valid address with: `" << peerAddressUri << "`.";
 		return nullptr;
 	}
-	Address localAddress(interpretUrl(localAddressUri, true));
-	if (!localAddress.isValid()) {
+	std::shared_ptr<Address> localAddress(interpretUrl(localAddressUri, true));
+	if (!localAddress || !localAddress->isValid()) {
 		lError() << "Cannot make a valid address with: `" << localAddressUri << "`.";
 		return nullptr;
 	}
@@ -929,17 +922,17 @@ LinphoneReason Core::onSipMessageReceived(SalOp *op, const SalMessage *sal_msg)
 
 	LinphoneCore *cCore = getCCore();
 	LinphoneReason reason = LinphoneReasonNotAcceptable;
-	string peerAddress;
-	string localAddress;
+	std::shared_ptr<Address> peerAddress;
+	std::shared_ptr<Address> localAddress;
 
 	if (linphone_core_conference_server_enabled(cCore)) {
-		localAddress = peerAddress = op->getTo();
+		localAddress = peerAddress = Address::create(op->getTo());
 	} else {
-		peerAddress = op->getFrom();
-		localAddress = op->getTo();
+		peerAddress = Address::create(op->getFrom());
+		localAddress = Address::create(op->getTo());
 	}
 
-	ConferenceId conferenceId{ConferenceAddress(peerAddress), ConferenceAddress(localAddress)};
+	ConferenceId conferenceId{peerAddress, localAddress};
 	shared_ptr<AbstractChatRoom> chatRoom = findChatRoom(conferenceId);
 	if (chatRoom) {
 		reason = handleChatMessagesAggregation(chatRoom, op, sal_msg);
diff --git a/src/core/core-p.h b/src/core/core-p.h
index 3996bd5ae1bfaa9eeb6acc1d82e1edf834f89d3e..d9a143a676490ad52336f0ab222b22ebd3d8f30f 100644
--- a/src/core/core-p.h
+++ b/src/core/core-p.h
@@ -79,7 +79,7 @@ public:
 		return !calls.empty();
 	}
 	bool inviteReplacesABrokenCall(SalCallOp *op);
-	bool isAlreadyInCallWithAddress(const Address &addr) const;
+	bool isAlreadyInCallWithAddress(const std::shared_ptr<Address> &addr) const;
 	void iterateCalls(time_t currentRealTime, bool oneSecondElapsed) const;
 	void notifySoundcardUsage(bool used);
 	int removeCall(const std::shared_ptr<Call> &call);
@@ -106,7 +106,7 @@ public:
 
 	// Base
 	std::shared_ptr<AbstractChatRoom> createClientGroupChatRoom(const std::string &subject,
-	                                                            const IdentityAddress &conferenceFactoryUri,
+	                                                            const std::shared_ptr<Address> &conferenceFactoryUri,
 	                                                            const ConferenceId &conferenceId,
 	                                                            const Content &content,
 	                                                            AbstractChatRoom::CapabilitiesMask capabilities,
@@ -122,36 +122,38 @@ public:
 	createClientGroupChatRoom(const std::string &subject, bool fallback, bool encrypted);
 
 	std::shared_ptr<AbstractChatRoom> createChatRoom(const std::shared_ptr<ChatRoomParams> &params,
-	                                                 const IdentityAddress &localAddr,
+	                                                 const std::shared_ptr<const Address> &localAddr,
 	                                                 const std::string &subject,
-	                                                 const std::list<IdentityAddress> &participants);
+	                                                 const std::list<std::shared_ptr<Address>> &participants);
 	std::shared_ptr<AbstractChatRoom> createChatRoom(const std::shared_ptr<ChatRoomParams> &params,
-	                                                 const IdentityAddress &localAddr,
-	                                                 const std::list<IdentityAddress> &participants);
+	                                                 const std::shared_ptr<const Address> &localAddr,
+	                                                 const std::list<std::shared_ptr<Address>> &participants);
 	std::shared_ptr<AbstractChatRoom> createChatRoom(const std::shared_ptr<ChatRoomParams> &params,
 	                                                 const std::string &subject,
-	                                                 const std::list<IdentityAddress> &participants);
+	                                                 const std::list<std::shared_ptr<Address>> &participants);
 	std::shared_ptr<AbstractChatRoom> createChatRoom(const std::string &subject,
-	                                                 const std::list<IdentityAddress> &participants);
+	                                                 const std::list<std::shared_ptr<Address>> &participants);
 	std::shared_ptr<AbstractChatRoom> createChatRoom(const std::shared_ptr<ChatRoomParams> &params,
-	                                                 const IdentityAddress &localAddr,
-	                                                 const IdentityAddress &participant);
-	std::shared_ptr<AbstractChatRoom> createChatRoom(const IdentityAddress &participant);
+	                                                 const std::shared_ptr<Address> &localAddr,
+	                                                 const std::shared_ptr<Address> &participant);
+	std::shared_ptr<AbstractChatRoom> createChatRoom(const std::shared_ptr<Address> &participant);
 
 	std::shared_ptr<AbstractChatRoom> searchChatRoom(const std::shared_ptr<ChatRoomParams> &params,
-	                                                 const IdentityAddress &localAddr,
-	                                                 const IdentityAddress &remoteAddr,
-	                                                 const std::list<IdentityAddress> &participants) const;
+	                                                 const std::shared_ptr<const Address> &localAddr,
+	                                                 const std::shared_ptr<const Address> &remoteAddr,
+	                                                 const std::list<std::shared_ptr<Address>> &participants) const;
 
-	IdentityAddress getDefaultLocalAddress(const IdentityAddress *peerAddress, bool withGruu) const;
-	IdentityAddress getIdentityAddressWithGruu(const IdentityAddress &identityAddress) const;
+	std::shared_ptr<const Address> getDefaultLocalAddress(const std::shared_ptr<Address> peerAddress,
+	                                                      bool withGruu) const;
+	std::shared_ptr<const Address>
+	getIdentityAddressWithGruu(const std::shared_ptr<const Address> &identityAddress) const;
 
 	void replaceChatRoom(const std::shared_ptr<AbstractChatRoom> &replacedChatRoom,
 	                     const std::shared_ptr<AbstractChatRoom> &newChatRoom);
 
 	void updateChatRoomConferenceId(const std::shared_ptr<AbstractChatRoom> &chatRoom, ConferenceId newConferenceId);
-	std::shared_ptr<AbstractChatRoom> findExhumableOneToOneChatRoom(const IdentityAddress &localAddress,
-	                                                                const IdentityAddress &participantAddress,
+	std::shared_ptr<AbstractChatRoom> findExhumableOneToOneChatRoom(const std::shared_ptr<Address> &localAddress,
+	                                                                const std::shared_ptr<Address> &participantAddress,
 	                                                                bool encrypted) const;
 	std::shared_ptr<AbstractChatRoom> findExumedChatRoomFromPreviousConferenceId(const ConferenceId conferenceId) const;
 
@@ -182,7 +184,6 @@ public:
 
 	/* centralized method to write down all NatPolicy used by Accounts or Core */
 	void writeNatPolicyConfigurations();
-
 	static const Utils::Version conferenceProtocolVersion;
 	static const Utils::Version groupChatProtocolVersion;
 	static const Utils::Version ephemeralProtocolVersion;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index d0e011b006bdcd91c44be7378d2493e5d61958ff..656a54bb5e4d8deefeddca8c6fd35e73789d32a1 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -1043,7 +1043,6 @@ void Core::setOutputAudioDevice(const std::shared_ptr<AudioDevice> &audioDevice)
 }
 
 std::shared_ptr<AudioDevice> Core::getInputAudioDevice() const {
-
 	// If the core in a local conference, then get the audio device of the audio control interface
 	if (getCCore()->conf_ctx) {
 		/* There is a local conference.*/
@@ -1064,7 +1063,6 @@ std::shared_ptr<AudioDevice> Core::getInputAudioDevice() const {
 }
 
 std::shared_ptr<AudioDevice> Core::getOutputAudioDevice() const {
-
 	// If the core in a local conference, then get the audio device of the audio control interface
 	if (getCCore()->conf_ctx) {
 		/* There is a local conference.*/
@@ -1322,14 +1320,12 @@ int Core::getUnreadChatMessageCount() const {
 	return d->mainDb->getUnreadChatMessageCount();
 }
 
-int Core::getUnreadChatMessageCount(const IdentityAddress &localAddress) const {
+int Core::getUnreadChatMessageCount(const std::shared_ptr<Address> &localAddress) const {
 	L_D();
 	int count = 0;
-	auto addressToCompare = localAddress.asAddress();
 	for (auto it = d->chatRoomsById.begin(); it != d->chatRoomsById.end(); it++) {
 		const auto &chatRoom = it->second;
-		if (addressToCompare.weakEqual(chatRoom->getLocalAddress().asAddress()))
-			count += chatRoom->getUnreadChatMessageCount();
+		if (localAddress->weakEqual(*chatRoom->getLocalAddress())) count += chatRoom->getUnreadChatMessageCount();
 	}
 	return count;
 }
@@ -1343,7 +1339,7 @@ int Core::getUnreadChatMessageCountFromActiveLocals() const {
 		for (auto it = linphone_core_get_proxy_config_list(getCCore()); it != NULL; it = it->next) {
 			LinphoneProxyConfig *cfg = (LinphoneProxyConfig *)it->data;
 			const LinphoneAddress *identityAddr = linphone_proxy_config_get_identity_address(cfg);
-			if (L_GET_CPP_PTR_FROM_C_OBJECT(identityAddr)->weakEqual(chatRoom->getLocalAddress().asAddress())) {
+			if (Address::toCpp(identityAddr)->weakEqual(*chatRoom->getLocalAddress())) {
 				count += chatRoom->getUnreadChatMessageCount();
 			}
 		}
@@ -1435,7 +1431,7 @@ void Core::removeLdap(std::shared_ptr<Ldap> ldap) {
 }
 // -----------------------------------------------------------------------------
 
-Address Core::interpretUrl(const std::string &url, bool chatOrCallUse) const {
+std::shared_ptr<Address> Core::interpretUrl(const std::string &url, bool chatOrCallUse) const {
 	bool applyPrefix = true;
 	if (chatOrCallUse) {
 		LinphoneAccount *account = linphone_core_get_default_account(getCCore());
@@ -1446,14 +1442,11 @@ Address Core::interpretUrl(const std::string &url, bool chatOrCallUse) const {
 	}
 
 	LinphoneAddress *cAddress = linphone_core_interpret_url_2(getCCore(), url.c_str(), applyPrefix);
-	if (!cAddress) return Address();
+	if (!cAddress) return nullptr;
 
-	char *str = linphone_address_as_string(cAddress);
+	std::shared_ptr<Address> address = Address::toCpp(cAddress)->getSharedFromThis();
 	linphone_address_unref(cAddress);
 
-	Address address(str);
-	bctbx_free(str);
-
 	return address;
 }
 
@@ -1483,11 +1476,17 @@ void Core::destroyTimer(belle_sip_source_t *timer) {
 }
 
 const ConferenceId Core::prepareConfereceIdForSearch(const ConferenceId &conferenceId) const {
-	Address peerAddress = conferenceId.getPeerAddress().asAddress();
-	peerAddress.removeUriParam("gr");
-	Address localAddress = conferenceId.getLocalAddress().asAddress();
-	localAddress.removeUriParam("gr");
-	ConferenceId prunedConferenceId = ConferenceId(ConferenceAddress(peerAddress), ConferenceAddress(localAddress));
+	std::shared_ptr<Address> peerAddress = nullptr;
+	const auto &rawPeerAddress = conferenceId.getPeerAddress();
+	if (rawPeerAddress) {
+		peerAddress = Address::create(rawPeerAddress->getUriWithoutGruu());
+	}
+	std::shared_ptr<Address> localAddress = nullptr;
+	const auto &rawLocalAddress = conferenceId.getLocalAddress();
+	if (rawLocalAddress) {
+		localAddress = Address::create(rawLocalAddress->getUriWithoutGruu());
+	}
+	ConferenceId prunedConferenceId = ConferenceId(peerAddress, localAddress);
 	return prunedConferenceId;
 }
 
@@ -1538,20 +1537,24 @@ void Core::deleteAudioVideoConference(const shared_ptr<const MediaConference::Co
 
 shared_ptr<MediaConference::Conference>
 Core::searchAudioVideoConference(const shared_ptr<ConferenceParams> &params,
-                                 const ConferenceAddress &localAddress,
-                                 const ConferenceAddress &remoteAddress,
-                                 const std::list<IdentityAddress> &participants) const {
+                                 const std::shared_ptr<const Address> &localAddress,
+                                 const std::shared_ptr<const Address> &remoteAddress,
+                                 const std::list<std::shared_ptr<Address>> &participants) const {
 
+	auto localAddressUri = (localAddress) ? localAddress->getUriWithoutGruu() : Address();
+	auto remoteAddressUri = (remoteAddress) ? remoteAddress->getUriWithoutGruu() : Address();
 	const auto it = std::find_if(audioVideoConferenceById.begin(), audioVideoConferenceById.end(), [&](const auto &p) {
 		// p is of type std::pair<ConferenceId, std::shared_ptr<MediaConference::Conference>
 		const auto &audioVideoConference = p.second;
 		const ConferenceId &conferenceId = audioVideoConference->getConferenceId();
-		const auto &curLocalAddress = conferenceId.getLocalAddress();
-		if (localAddress.getAddressWithoutGruu() != curLocalAddress.getAddressWithoutGruu()) return false;
-		const auto &curRemoteAddress = conferenceId.getPeerAddress();
-		if (remoteAddress.isValid() &&
-		    remoteAddress.getAddressWithoutGruu() != curRemoteAddress.getAddressWithoutGruu())
-			return false;
+
+		auto curLocalAddress =
+		    (conferenceId.getLocalAddress()) ? conferenceId.getLocalAddress()->getUriWithoutGruu() : Address();
+		if (localAddressUri.isValid() && (localAddressUri != curLocalAddress)) return false;
+
+		auto curPeerAddress =
+		    (conferenceId.getPeerAddress()) ? conferenceId.getPeerAddress()->getUriWithoutGruu() : Address();
+		if (remoteAddressUri.isValid() && (remoteAddressUri != curPeerAddress)) return false;
 
 		// Check parameters only if pointer provided as argument is not null
 		if (params) {
@@ -1570,9 +1573,7 @@ Core::searchAudioVideoConference(const shared_ptr<ConferenceParams> &params,
 			const std::list<std::shared_ptr<Participant>> &confParticipants = audioVideoConference->getParticipants();
 			participantListMatch =
 			    equal(participants.cbegin(), participants.cend(), confParticipants.cbegin(), confParticipants.cend(),
-			          [](const auto &p1, const auto &p2) {
-				          return (p2->getAddress().getAddressWithoutGruu() == p1.getAddressWithoutGruu());
-			          });
+			          [](const auto &p1, const auto &p2) { return (p1->weakEqual(*p2->getAddress())); });
 		}
 		return participantListMatch;
 	});
@@ -1586,14 +1587,14 @@ Core::searchAudioVideoConference(const shared_ptr<ConferenceParams> &params,
 }
 
 shared_ptr<MediaConference::Conference>
-Core::searchAudioVideoConference(const ConferenceAddress &conferenceAddress) const {
+Core::searchAudioVideoConference(const std::shared_ptr<Address> &conferenceAddress) const {
 
-	if (!conferenceAddress.isValid()) return nullptr;
+	if (!conferenceAddress || !conferenceAddress->isValid()) return nullptr;
 	const auto it = std::find_if(audioVideoConferenceById.begin(), audioVideoConferenceById.end(), [&](const auto &p) {
 		// p is of type std::pair<ConferenceId, std::shared_ptr<MediaConference::Conference>
 		const auto &audioVideoConference = p.second;
 		const auto curConferenceAddress = audioVideoConference->getConferenceAddress();
-		return (conferenceAddress == curConferenceAddress);
+		return (*conferenceAddress == *curConferenceAddress);
 	});
 
 	shared_ptr<MediaConference::Conference> conference = nullptr;
@@ -1605,15 +1606,15 @@ Core::searchAudioVideoConference(const ConferenceAddress &conferenceAddress) con
 }
 
 shared_ptr<CallSession> Core::createConferenceOnServer(const shared_ptr<ConferenceParams> &confParams,
-                                                       const Address &localAddr,
-                                                       const std::list<IdentityAddress> &participants) {
-	return createOrUpdateConferenceOnServer(confParams, localAddr, participants, ConferenceAddress());
+                                                       const std::shared_ptr<Address> &localAddr,
+                                                       const std::list<std::shared_ptr<Address>> &participants) {
+	return createOrUpdateConferenceOnServer(confParams, localAddr, participants, nullptr);
 }
 
 shared_ptr<CallSession> Core::createOrUpdateConferenceOnServer(const std::shared_ptr<ConferenceParams> &confParams,
-                                                               const Address &localAddr,
-                                                               const std::list<IdentityAddress> &participants,
-                                                               const ConferenceAddress &confAddr) {
+                                                               const std::shared_ptr<Address> &localAddr,
+                                                               const std::list<std::shared_ptr<Address>> &participants,
+                                                               const std::shared_ptr<Address> &confAddr) {
 	L_D()
 	if (!confParams) {
 		lWarning() << "Trying to create conference with null parameters";
@@ -1623,31 +1624,29 @@ shared_ptr<CallSession> Core::createOrUpdateConferenceOnServer(const std::shared
 	LinphoneCore *lc = L_GET_C_BACK_PTR(this);
 	auto params = linphone_core_create_call_params(lc, nullptr);
 
-	Address conferenceFactoryUri;
-	if (confAddr == ConferenceAddress()) {
+	std::shared_ptr<Address> conferenceFactoryUri;
+	if (confAddr) {
+		conferenceFactoryUri = confAddr;
+	} else {
 		LinphoneAddress *factoryUri = Core::getAudioVideoConferenceFactoryAddress(getSharedFromThis(), localAddr);
 		if (factoryUri == nullptr) {
 			lWarning() << "Not creating conference: no conference factory uri for local address [" << localAddr << "]";
 			return nullptr;
 		}
-		auto conferenceFactoryUriStr = linphone_address_as_string_uri_only(factoryUri);
-		linphone_address_unref(factoryUri);
-		conferenceFactoryUri = Address(conferenceFactoryUriStr);
-		ms_free(conferenceFactoryUriStr);
-	} else {
-		conferenceFactoryUri = confAddr.asAddress();
+		conferenceFactoryUri = Address::toCpp(factoryUri)->getSharedFromThis();
 	}
 
-	ConferenceId conferenceId = ConferenceId(IdentityAddress(), localAddr);
-	if (!localAddr.hasUriParam("gr")) {
-		lWarning() << "Local identity address [" << localAddr << "] doesn't have a gruu, let's try to find it";
-		IdentityAddress localAddrWithGruu = d->getIdentityAddressWithGruu(localAddr);
-		if (localAddrWithGruu.isValid()) {
+	ConferenceId conferenceId = ConferenceId(nullptr, localAddr);
+	if (!localAddr->hasUriParam("gr")) {
+		lWarning() << "Local identity address [" << localAddr->toString()
+		           << "] doesn't have a gruu, let's try to find it";
+		auto localAddrWithGruu = d->getIdentityAddressWithGruu(localAddr);
+		if (localAddrWithGruu && localAddrWithGruu->isValid()) {
 			lInfo() << "Found matching contact address [" << localAddrWithGruu << "] to use instead";
-			conferenceId = ConferenceId(IdentityAddress(), localAddrWithGruu);
+			conferenceId = ConferenceId(nullptr, localAddrWithGruu);
 		} else {
-			lError() << "Failed to find matching contact address with gruu for identity address [" << localAddr
-			         << "], client group chat room creation will fail!";
+			lError() << "Failed to find matching contact address with gruu for identity address ["
+			         << localAddr->toString() << "], client group chat room creation will fail!";
 		}
 	}
 
@@ -1688,13 +1687,16 @@ shared_ptr<CallSession> Core::createOrUpdateConferenceOnServer(const std::shared
 
 	linphone_call_params_unref(params);
 
-	Address meCleanedAddress(localAddr);
-	meCleanedAddress.removeUriParam("gr"); // Remove gr parameter for INVITE.
+	std::shared_ptr<Address> meCleanedAddress = Address::create(localAddr->getUriWithoutGruu());
 	session->configure(LinphoneCallOutgoing, nullptr, nullptr, meCleanedAddress, conferenceFactoryUri);
-	LinphoneProxyConfig *destProxy = session->getDestProxy();
+	const auto destAccount = session->getPrivate()->getDestAccount();
 	const LinphoneNatPolicy *natPolicy = nullptr;
-	if (destProxy) {
-		natPolicy = linphone_proxy_config_get_nat_policy(destProxy);
+	if (destAccount) {
+		const auto accountParams = destAccount->getAccountParams();
+		const auto &cppNatPolicy = accountParams->getNatPolicy();
+		if (cppNatPolicy) {
+			natPolicy = cppNatPolicy->toC();
+		}
 	}
 	if (!natPolicy) {
 		natPolicy = linphone_core_get_nat_policy(getCCore());
@@ -1728,20 +1730,19 @@ const std::list<LinphoneMediaEncryption> Core::getSupportedMediaEncryptions() co
 }
 
 LinphoneAddress *Core::getAudioVideoConferenceFactoryAddress(const std::shared_ptr<Core> &core,
-                                                             const IdentityAddress &localAddress) {
-	Address addr(localAddress.asAddress());
-	LinphoneAccount *account = linphone_core_lookup_known_account(core->getCCore(), L_GET_C_BACK_PTR(&addr));
+                                                             const std::shared_ptr<Address> &localAddress) {
+	std::shared_ptr<Address> addr = localAddress;
+	LinphoneAccount *account = linphone_core_lookup_known_account(core->getCCore(), addr->toC());
 
 	if (!account) {
-		lWarning() << "No account found for local address: [" << localAddress.asString() << "]";
+		lWarning() << "No account found for local address: [" << localAddress->toString() << "]";
 		return nullptr;
 	} else return getAudioVideoConferenceFactoryAddress(core, account);
 }
 
 LinphoneAddress *Core::getAudioVideoConferenceFactoryAddress(const std::shared_ptr<Core> &core,
                                                              const LinphoneAccount *account) {
-	const LinphoneAddress *address =
-	    Account::toCpp(account)->getAccountParams()->getAudioVideoConferenceFactoryAddress();
+	const auto &address = Account::toCpp(account)->getAccountParams()->getAudioVideoConferenceFactoryAddress();
 	if (address == nullptr) {
 		string conferenceFactoryUri = getConferenceFactoryUri(core, account);
 		lWarning() << "Audio/video conference factory is null, fallback to default conference factory URI ["
@@ -1749,9 +1750,7 @@ LinphoneAddress *Core::getAudioVideoConferenceFactoryAddress(const std::shared_p
 		if (conferenceFactoryUri.empty()) return nullptr;
 		return linphone_address_new(conferenceFactoryUri.c_str());
 	}
-	char *address_uri = linphone_address_as_string_uri_only(address);
-	LinphoneAddress *factory_address = linphone_address_new(address_uri);
-	ms_free(address_uri);
+	LinphoneAddress *factory_address = address->toC();
 	return factory_address;
 }
 
diff --git a/src/core/core.h b/src/core/core.h
index 5613db74f2239b4b374fa1eacd704f2429d2041a..3dff6a106305c1ed1818a147c142c20d8e087e81 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -25,14 +25,16 @@
 #include <list>
 #include <unordered_map>
 
-#include "object/object.h"
+#include <mediastreamer2/mssndcard.h>
 
 #include "account/account.h"
+#include "c-wrapper/internal/c-sal.h"
 #include "call/audio-device/audio-device.h"
 #include "call/call-log.h"
 #include "conference/conference-id.h"
 #include "event-log/event-log.h"
 #include "linphone/types.h"
+#include "object/object.h"
 #include "sal/event-op.h"
 
 // =============================================================================
@@ -49,13 +51,15 @@ LINPHONE_BEGIN_NAMESPACE
 
 class AbstractChatRoom;
 class Address;
+class AudioDevice;
 class Call;
+class CallLog;
 class CallSession;
 class ConferenceId;
+class ConferenceInfo;
 class Participant;
 class ConferenceParams;
 class CorePrivate;
-class IdentityAddress;
 class EncryptionEngine;
 class ChatMessage;
 class ChatRoom;
@@ -117,10 +121,11 @@ public:
 	// Return a new Core instance. Entry point of Linphone.
 	static std::shared_ptr<Core> create(LinphoneCore *cCore);
 
-	static std::string getConferenceFactoryUri(const std::shared_ptr<Core> &core, const IdentityAddress &localAddress);
+	static std::string getConferenceFactoryUri(const std::shared_ptr<Core> &core,
+	                                           const std::shared_ptr<const Address> &localAddress);
 	static std::string getConferenceFactoryUri(const std::shared_ptr<Core> &core, const LinphoneAccount *account);
 	static LinphoneAddress *getAudioVideoConferenceFactoryAddress(const std::shared_ptr<Core> &core,
-	                                                              const IdentityAddress &localAddress);
+	                                                              const std::shared_ptr<Address> &localAddress);
 	static LinphoneAddress *getAudioVideoConferenceFactoryAddress(const std::shared_ptr<Core> &core,
 	                                                              const LinphoneAccount *account);
 
@@ -144,7 +149,7 @@ public:
 	// ---------------------------------------------------------------------------
 
 	bool areSoundResourcesLocked() const;
-	std::shared_ptr<Call> getCallByRemoteAddress(const Address &addr) const;
+	std::shared_ptr<Call> getCallByRemoteAddress(const std::shared_ptr<Address> &addr) const;
 	std::shared_ptr<Call> getCallByCallId(const std::string &callId) const;
 	const std::list<std::shared_ptr<Call>> &getCalls() const;
 	unsigned int getCallCount() const;
@@ -164,8 +169,8 @@ public:
 	                               std::shared_ptr<CallLog> &callLog,
 	                               std::shared_ptr<ConferenceInfo> confInfo);
 	void reportEarlyCallFailed(LinphoneCallDir dir,
-	                           LinphoneAddress *from,
-	                           LinphoneAddress *to,
+	                           const std::shared_ptr<Address> &from,
+	                           const std::shared_ptr<Address> &to,
 	                           LinphoneErrorInfo *ei,
 	                           const std::string callId);
 
@@ -176,10 +181,10 @@ public:
 	std::list<std::shared_ptr<AbstractChatRoom>> getChatRooms() const;
 
 	std::shared_ptr<AbstractChatRoom> findChatRoom(const ConferenceId &conferenceId, bool logIfNotFound = true) const;
-	std::list<std::shared_ptr<AbstractChatRoom>> findChatRooms(const IdentityAddress &peerAddress) const;
+	std::list<std::shared_ptr<AbstractChatRoom>> findChatRooms(const std::shared_ptr<Address> &peerAddress) const;
 
-	std::shared_ptr<AbstractChatRoom> findOneToOneChatRoom(const IdentityAddress &localAddress,
-	                                                       const IdentityAddress &participantAddress,
+	std::shared_ptr<AbstractChatRoom> findOneToOneChatRoom(const std::shared_ptr<const Address> &localAddress,
+	                                                       const std::shared_ptr<Address> &participantAddress,
 	                                                       bool basicOnly,
 	                                                       bool conferenceOnly,
 	                                                       bool encrypted) const;
@@ -189,14 +194,14 @@ public:
 	                                                            LinphoneChatRoomCapabilitiesMask capabilities,
 	                                                            bool fallback = true);
 	std::shared_ptr<AbstractChatRoom> createClientGroupChatRoom(const std::string &subject,
-	                                                            const Address *localAddress,
+	                                                            const std::shared_ptr<Address> *localAddress,
 	                                                            LinphoneChatRoomCapabilitiesMask capabilities,
 	                                                            bool fallback = true);
 
 	std::shared_ptr<AbstractChatRoom> getOrCreateBasicChatRoom(const ConferenceId &conferenceId);
 
-	std::shared_ptr<AbstractChatRoom> getOrCreateBasicChatRoom(const IdentityAddress &localAddress,
-	                                                           const IdentityAddress &peerAddress);
+	std::shared_ptr<AbstractChatRoom> getOrCreateBasicChatRoom(const std::shared_ptr<Address> &localAddress,
+	                                                           const std::shared_ptr<Address> &peerAddress);
 
 	std::shared_ptr<AbstractChatRoom> getOrCreateBasicChatRoomFromUri(const std::string &localAddressUri,
 	                                                                  const std::string &peerAddressUri);
@@ -210,7 +215,6 @@ public:
 	LinphoneReason onSipMessageReceived(SalOp *op, const SalMessage *sal_msg);
 	LinphoneReason
 	handleChatMessagesAggregation(std::shared_ptr<AbstractChatRoom> chatRoom, SalOp *op, const SalMessage *sal_msg);
-
 	void enableEmptyChatroomsDeletion(const bool enable);
 	bool emptyChatroomsDeletionEnabled() const;
 
@@ -224,11 +228,11 @@ public:
 	void deleteAudioVideoConference(const std::shared_ptr<const MediaConference::Conference> &audioVideoConference);
 	std::shared_ptr<MediaConference::Conference>
 	searchAudioVideoConference(const std::shared_ptr<ConferenceParams> &params,
-	                           const ConferenceAddress &localAddress,
-	                           const ConferenceAddress &remoteAddress,
-	                           const std::list<IdentityAddress> &participants) const;
+	                           const std::shared_ptr<const Address> &localAddress,
+	                           const std::shared_ptr<const Address> &remoteAddress,
+	                           const std::list<std::shared_ptr<Address>> &participants) const;
 	std::shared_ptr<MediaConference::Conference>
-	searchAudioVideoConference(const ConferenceAddress &conferenceAddress) const;
+	searchAudioVideoConference(const std::shared_ptr<Address> &conferenceAddress) const;
 
 	// ---------------------------------------------------------------------------
 	// Paths.
@@ -299,7 +303,7 @@ public:
 
 	void pushNotificationReceived(const std::string &callId, const std::string &payload, bool isCoreStarting);
 	int getUnreadChatMessageCount() const;
-	int getUnreadChatMessageCount(const IdentityAddress &localAddress) const;
+	int getUnreadChatMessageCount(const std::shared_ptr<Address> &localAddress) const;
 	int getUnreadChatMessageCountFromActiveLocals() const;
 	std::shared_ptr<PushNotificationMessage> getPushNotificationMessage(const std::string &callId) const;
 	std::shared_ptr<ChatRoom> getPushNotificationChatRoom(const std::string &chatRoomAddr) const;
@@ -315,7 +319,7 @@ public:
 	void addLdap(std::shared_ptr<Ldap> ldap);
 	void removeLdap(std::shared_ptr<Ldap> ldap);
 
-	Address interpretUrl(const std::string &url, bool chatOrCallUse) const;
+	std::shared_ptr<Address> interpretUrl(const std::string &url, bool chatOrCallUse) const;
 
 	// Execute specified lambda later in main loop. This method can be used from any thread to execute something later
 	// on main thread.
@@ -341,12 +345,13 @@ public:
 	const std::list<LinphoneMediaEncryption> getSupportedMediaEncryptions() const;
 
 	std::shared_ptr<CallSession> createConferenceOnServer(const std::shared_ptr<ConferenceParams> &confParams,
-	                                                      const Address &localAddr,
-	                                                      const std::list<IdentityAddress> &participants);
-	std::shared_ptr<CallSession> createOrUpdateConferenceOnServer(const std::shared_ptr<ConferenceParams> &confParams,
-	                                                              const Address &localAddr,
-	                                                              const std::list<IdentityAddress> &participants,
-	                                                              const ConferenceAddress &confAddr);
+	                                                      const std::shared_ptr<Address> &localAddr,
+	                                                      const std::list<std::shared_ptr<Address>> &participants);
+	std::shared_ptr<CallSession>
+	createOrUpdateConferenceOnServer(const std::shared_ptr<ConferenceParams> &confParams,
+	                                 const std::shared_ptr<Address> &localAddr,
+	                                 const std::list<std::shared_ptr<Address>> &participants,
+	                                 const std::shared_ptr<Address> &confAddr);
 
 	bool isCurrentlyAggregatingChatMessages();
 
@@ -354,7 +359,6 @@ private:
 	Core();
 
 	bool deleteEmptyChatrooms = true;
-
 	std::unordered_map<ConferenceId, std::shared_ptr<MediaConference::Conference>> audioVideoConferenceById;
 	const ConferenceId prepareConfereceIdForSearch(const ConferenceId &conferenceId) const;
 
diff --git a/src/core/platform-helpers/ios-platform-helpers.mm b/src/core/platform-helpers/ios-platform-helpers.mm
index ad9a384ac9646ba08dcd5e9b36a90e8a726cba9c..d9f6b6a26799098479b31c23dcc2de8c3dd1014b 100644
--- a/src/core/platform-helpers/ios-platform-helpers.mm
+++ b/src/core/platform-helpers/ios-platform-helpers.mm
@@ -32,6 +32,8 @@
 #include <belr/grammarbuilder.h>
 #include <AVFoundation/AVAudioSession.h>
 
+#include "core/core.h"
+#include "linphone/core.h"
 #include "linphone/utils/general.h"
 #include "linphone/utils/utils.h"
 #include "c-wrapper/c-wrapper.h"
diff --git a/src/core/platform-helpers/mac-platform-helpers.mm b/src/core/platform-helpers/mac-platform-helpers.mm
index 28be178a5c9ac73468bbdba65fba7011e19b2515..bad53f5fab6e2670cf25761ef25f13439c6ba3bd 100644
--- a/src/core/platform-helpers/mac-platform-helpers.mm
+++ b/src/core/platform-helpers/mac-platform-helpers.mm
@@ -30,6 +30,7 @@
 #include "c-wrapper/c-wrapper.h"
 
 #include "logger/logger.h"
+#include "core/core.h"
 #include "mac-platform-helpers.h"
 
 // =============================================================================
diff --git a/src/core/platform-helpers/platform-helpers.cpp b/src/core/platform-helpers/platform-helpers.cpp
index ddd9812d0fd4e395d2b4ce7e14f557125cbb20d4..427b07fc320f13b7e11630aa998bbea88957f3f4 100644
--- a/src/core/platform-helpers/platform-helpers.cpp
+++ b/src/core/platform-helpers/platform-helpers.cpp
@@ -20,9 +20,9 @@
 
 #include <bctoolbox/defs.h>
 
+#include "core/core.h"
 #include "logger/logger.h"
 #include "platform-helpers.h"
-
 // TODO: Remove me.
 #include "private.h"
 
diff --git a/src/core/platform-helpers/platform-helpers.h b/src/core/platform-helpers/platform-helpers.h
index 56e5d6bf3c06767eab9d79e1d0b94e2360b5c9d7..a02b9932531dae17b42cd3c5984e1e74050e82a4 100644
--- a/src/core/platform-helpers/platform-helpers.h
+++ b/src/core/platform-helpers/platform-helpers.h
@@ -42,6 +42,8 @@ L_DECL_C_STRUCT(LinphoneCore);
 
 LINPHONE_BEGIN_NAMESPACE
 
+class Core;
+
 /**
  * This interface aims at abstracting some features offered by the platform, most often mobile platforms.
  * A per platform implementation is to be made to implement these features, if available on the platform.
diff --git a/src/core/shared-core-helpers/ios-shared-core-helpers.mm b/src/core/shared-core-helpers/ios-shared-core-helpers.mm
index 001ed239211a75dc34ace673729b7935c3419b2c..c822071527626d32a5abc0daec247e2eb356c6a4 100644
--- a/src/core/shared-core-helpers/ios-shared-core-helpers.mm
+++ b/src/core/shared-core-helpers/ios-shared-core-helpers.mm
@@ -28,6 +28,8 @@
 #include <mutex>
 #include <set>
 
+#include "core/core.h"
+#include "linphone/core.h"
 #include "linphone/utils/general.h"
 #include "linphone/utils/utils.h"
 #include "chat/chat-room/chat-room.h"
diff --git a/src/core/shared-core-helpers/shared-core-helpers.h b/src/core/shared-core-helpers/shared-core-helpers.h
index c02dd9a5099ee8915ecb297cb1e3f8333b4ddaf8..dfa68deeffea7a1344b5572fb393808b33f0c95e 100644
--- a/src/core/shared-core-helpers/shared-core-helpers.h
+++ b/src/core/shared-core-helpers/shared-core-helpers.h
@@ -22,6 +22,7 @@
 
 #include "core/core-accessor.h"
 #include "core/core.h"
+#include "linphone/types.h"
 #include "linphone/utils/general.h"
 #include "push-notification-message/push-notification-message.h"
 
@@ -35,6 +36,10 @@ typedef enum {
 	executorCoreStopped   // A Main Core has stopped the Executor Cores. Only a Main Core can start here.
 } SharedCoreState;
 
+class Core;
+class ChatRoom;
+class PushNotificationMessage;
+
 /**
  * This interface aims at abstracting some features offered by the platform, most often mobile platforms.
  * A per platform implementation is to be made to implement these features, if available on the platform.
diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h
index ef1e4fb4f2135cbdaccf9fb97a092d74d594d4bf..5d90a7e957ce059c76d96cb87fa08ebf9960e6c2 100644
--- a/src/db/main-db-p.h
+++ b/src/db/main-db-p.h
@@ -56,7 +56,7 @@ private:
 	// Low level API.
 	// ---------------------------------------------------------------------------
 
-	long long insertSipAddress(const Address &address);
+	long long insertSipAddress(const std::shared_ptr<Address> &address);
 	long long insertSipAddress(const std::string &sipAddress);
 	void insertContent(long long chatMessageId, const Content &content);
 	long long insertContentType(const std::string &contentType);
@@ -168,7 +168,7 @@ private:
 	long long insertConferenceEphemeralMessageEvent(const std::shared_ptr<EventLog> &eventLog);
 
 	void setChatMessageParticipantState(const std::shared_ptr<EventLog> &eventLog,
-	                                    const IdentityAddress &participantAddress,
+	                                    const std::shared_ptr<Address> &participantAddress,
 	                                    ChatMessage::State state,
 	                                    time_t stateChangeTime);
 
diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp
index 52e28276b5e371076e743dbb7aadc93f045a7c2a..44fdce27e3c859ac92ed09c6aba01f238dbd8ae3 100644
--- a/src/db/main-db.cpp
+++ b/src/db/main-db.cpp
@@ -24,6 +24,7 @@
 #endif // _MSC_VER
 
 #if (__GNUC__ == 9 && __GNUC_MINOR__ >= 1)
+#pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wstringop-overflow"
 #endif
 
@@ -298,11 +299,11 @@ MainDbPrivate::findAudioVideoConference(const ConferenceId &conferenceId) const
 // Low level API.
 // -----------------------------------------------------------------------------
 
-long long MainDbPrivate::insertSipAddress(const Address &address) {
+long long MainDbPrivate::insertSipAddress(BCTBX_UNUSED(const std::shared_ptr<Address> &address)) {
 #ifdef HAVE_DB_STORAGE
 	// This is a hack, because all addresses don't print their parameters in the same order.
-	const string sipAddress = ConferenceAddress(address).asString();
-	const string displayName = address.getDisplayName();
+	const string sipAddress = address->toStringUriOnlyOrdered();
+	const string displayName = address->getDisplayName();
 
 	long long sipAddressId = selectSipAddressId(sipAddress);
 
@@ -422,8 +423,8 @@ long long MainDbPrivate::insertChatRoom(const shared_ptr<AbstractChatRoom> &chat
 	L_Q();
 	if (q->isInitialized()) {
 		const ConferenceId &conferenceId = chatRoom->getConferenceId();
-		const long long &peerSipAddressId = insertSipAddress(conferenceId.getPeerAddress().asString());
-		const long long &localSipAddressId = insertSipAddress(conferenceId.getLocalAddress().asString());
+		const long long &peerSipAddressId = insertSipAddress(conferenceId.getPeerAddress()->asStringUriOnly());
+		const long long &localSipAddressId = insertSipAddress(conferenceId.getLocalAddress()->asStringUriOnly());
 
 		long long chatRoomId = selectChatRoomId(peerSipAddressId, localSipAddressId);
 		const int flags = chatRoom->hasBeenLeft() ? 1 : 0;
@@ -468,19 +469,19 @@ long long MainDbPrivate::insertChatRoom(const shared_ptr<AbstractChatRoom> &chat
 		// Do not add 'me' when creating a server-group-chat-room.
 		if (conferenceId.getLocalAddress() != conferenceId.getPeerAddress()) {
 			shared_ptr<Participant> me = chatRoom->getMe();
-			long long meId =
-			    insertChatRoomParticipant(chatRoomId, insertSipAddress(me->getAddress().asString()), me->isAdmin());
+			long long meId = insertChatRoomParticipant(
+			    chatRoomId, insertSipAddress(me->getAddress()->asStringUriOnly()), me->isAdmin());
 			for (const auto &device : me->getDevices())
-				insertChatRoomParticipantDevice(meId, insertSipAddress(device->getAddress().asString()),
+				insertChatRoomParticipantDevice(meId, insertSipAddress(device->getAddress()->asStringUriOnly()),
 				                                device->getName());
 		}
 
 		for (const auto &participant : chatRoom->getParticipants()) {
 			long long participantId = insertChatRoomParticipant(
-			    chatRoomId, insertSipAddress(participant->getAddress().asString()), participant->isAdmin());
+			    chatRoomId, insertSipAddress(participant->getAddress()->asStringUriOnly()), participant->isAdmin());
 			for (const auto &device : participant->getDevices())
-				insertChatRoomParticipantDevice(participantId, insertSipAddress(device->getAddress().asString()),
-				                                device->getName());
+				insertChatRoomParticipantDevice(
+				    participantId, insertSipAddress(device->getAddress()->asStringUriOnly()), device->getName());
 		}
 
 		return chatRoomId;
@@ -561,12 +562,15 @@ long long MainDbPrivate::insertConferenceInfo(const std::shared_ptr<ConferenceIn
 		return -1;
 	}
 
-	if (!conferenceInfo->getOrganizerAddress().isValid() || !conferenceInfo->getUri().isValid()) {
+	const auto &conferenceUri = conferenceInfo->getUri();
+	if (!conferenceInfo->getOrganizerAddress() || !conferenceInfo->getOrganizerAddress()->isValid() || !conferenceUri ||
+	    !conferenceUri->isValid()) {
 		lError() << "Trying to insert a Conference Info without organizer or URI!";
 		return -1;
 	}
-	const long long &organizerSipAddressId = insertSipAddress(conferenceInfo->getOrganizerAddress().asString());
-	const long long &uriSipAddressid = insertSipAddress(conferenceInfo->getUri().asString());
+
+	const long long &organizerSipAddressId = insertSipAddress(conferenceInfo->getOrganizerAddress()->asStringUriOnly());
+	const long long &uriSipAddressid = insertSipAddress(conferenceUri->asStringUriOnly());
 	const tm &startTime = Utils::getTimeTAsTm(conferenceInfo->getDateTime());
 	const unsigned int duration = conferenceInfo->getDuration();
 	const string &subject = conferenceInfo->getUtf8Subject();
@@ -580,7 +584,9 @@ long long MainDbPrivate::insertConferenceInfo(const std::shared_ptr<ConferenceIn
 	if (conferenceInfoId >= 0) {
 		// The conference info is already stored in DB, but still update it some information might have changed
 		lInfo() << "Update conferenceInfo in database: " << conferenceInfoId << ".";
-		dbParticipantList = oldConferenceInfo->getParticipants();
+		if (oldConferenceInfo) {
+			dbParticipantList = oldConferenceInfo->getParticipants();
+		}
 
 		*dbSession.getBackendSession() << "UPDATE conference_info SET"
 		                                  "  organizer_sip_address_id = :organizerSipAddressId,"
@@ -615,19 +621,20 @@ long long MainDbPrivate::insertConferenceInfo(const std::shared_ptr<ConferenceIn
 
 	const auto &participantList = conferenceInfo->getParticipants();
 	for (const auto &participantAddress : participantList) {
-		insertOrUpdateConferenceInfoParticipant(conferenceInfoId, insertSipAddress(participantAddress.first.asString()),
-		                                        false, participantAddress.second);
+		insertOrUpdateConferenceInfoParticipant(conferenceInfoId,
+		                                        insertSipAddress(participantAddress.first->asStringUriOnly()), false,
+		                                        participantAddress.second);
 	}
 
 	for (const auto &oldParticipantAddress : dbParticipantList) {
 		const bool deleted =
 		    (std::find_if(participantList.cbegin(), participantList.cend(), [&oldParticipantAddress](const auto &p) {
-			     return (p.first == oldParticipantAddress.first);
+			     return (p.first->weakEqual(*oldParticipantAddress.first));
 		     }) == participantList.cend());
 		if (deleted) {
 			insertOrUpdateConferenceInfoParticipant(conferenceInfoId,
-			                                        insertSipAddress(oldParticipantAddress.first.asString()), true,
-			                                        oldParticipantAddress.second);
+			                                        insertSipAddress(oldParticipantAddress.first->asStringUriOnly()),
+			                                        true, oldParticipantAddress.second);
 		}
 	}
 
@@ -703,12 +710,15 @@ long long MainDbPrivate::insertOrUpdateConferenceCall(const std::shared_ptr<Call
 	long long conferenceInfoId = -1;
 
 	if (conferenceInfo != nullptr) {
-		const long long &uriSipAddressid = insertSipAddress(conferenceInfo->getUri().asString());
-		conferenceInfoId = selectConferenceInfoId(uriSipAddressid);
-		if (conferenceInfoId < 0) {
-			conferenceInfoId = insertConferenceInfo(conferenceInfo, nullptr);
+		const auto &conferenceAddress = conferenceInfo->getUri();
+		if (conferenceAddress) {
+			const long long &uriSipAddressid = insertSipAddress(conferenceAddress->asStringUriOnly());
+			conferenceInfoId = selectConferenceInfoId(uriSipAddressid);
+			if (conferenceInfoId < 0) {
+				conferenceInfoId = insertConferenceInfo(conferenceInfo, nullptr);
+			}
+			callLog->setConferenceInfoId(conferenceInfoId);
 		}
-		callLog->setConferenceInfoId(conferenceInfoId);
 	}
 
 	int duration = callLog->getDuration();
@@ -724,8 +734,10 @@ long long MainDbPrivate::insertOrUpdateConferenceCall(const std::shared_ptr<Call
 	if (conferenceCallId < 0) {
 		lInfo() << "Insert new conference call in database: " << callLog->getCallId();
 
-		const long long fromSipAddressId = insertSipAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(callLog->getFromAddress()));
-		const long long toSipAddressId = insertSipAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(callLog->getToAddress()));
+		std::shared_ptr<Address> from = callLog->getFromAddress() ? callLog->getFromAddress() : nullptr;
+		const long long fromSipAddressId = insertSipAddress(from);
+		std::shared_ptr<Address> to = callLog->getToAddress() ? callLog->getToAddress() : nullptr;
+		const long long toSipAddressId = insertSipAddress(to);
 		int direction = static_cast<int>(callLog->getDirection());
 		const tm &startTime = Utils::getTimeTAsTm(callLog->getStartTime());
 
@@ -796,10 +808,12 @@ long long MainDbPrivate::selectChatRoomId(long long peerSipAddressId, long long
 
 long long MainDbPrivate::selectChatRoomId(const ConferenceId &conferenceId) const {
 #ifdef HAVE_DB_STORAGE
-	long long peerSipAddressId = selectSipAddressId(conferenceId.getPeerAddress().asString());
+	long long peerSipAddressId =
+	    conferenceId.getPeerAddress() ? selectSipAddressId(conferenceId.getPeerAddress()->asStringUriOnly()) : -1;
 	if (peerSipAddressId < 0) return -1;
 
-	long long localSipAddressId = selectSipAddressId(conferenceId.getLocalAddress().asString());
+	long long localSipAddressId =
+	    conferenceId.getLocalAddress() ? selectSipAddressId(conferenceId.getLocalAddress()->asStringUriOnly()) : -1;
 	if (localSipAddressId < 0) return -1;
 
 	long long id = selectChatRoomId(peerSipAddressId, localSipAddressId);
@@ -822,7 +836,7 @@ ConferenceId MainDbPrivate::selectConferenceId(const long long chatRoomId) const
 	soci::session *session = dbSession.getBackendSession();
 	*session << query, soci::use(chatRoomId), soci::into(peerSipAddress), soci::into(localSipAddress);
 
-	ConferenceId conferenceId = ConferenceId(IdentityAddress(peerSipAddress), IdentityAddress(localSipAddress));
+	ConferenceId conferenceId = ConferenceId(Address::create(peerSipAddress), Address::create(localSipAddress));
 
 	if (conferenceId.isValid()) {
 		cache(conferenceId, chatRoomId);
@@ -1048,10 +1062,9 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceCallEvent(const soci::row &r
 	long long conferenceCallId = dbSession.resolveId(row, 3);
 	auto callLog = getCallLogFromCache(conferenceCallId);
 	if (callLog == nullptr) {
-
-		callLog = CallLog::create(q->getCore(), static_cast<LinphoneCallDir>(row.get<int>(6)),
-		                          linphone_address_new(row.get<string>(4).c_str()),
-		                          linphone_address_new(row.get<string>(5).c_str()));
+		const std::shared_ptr<Address> from = Address::create(row.get<string>(4));
+		const std::shared_ptr<Address> to = Address::create(row.get<string>(5));
+		callLog = CallLog::create(q->getCore(), static_cast<LinphoneCallDir>(row.get<int>(6)), from, to);
 		callLog->setDuration(row.get<int>(7));
 		callLog->setStartTime(dbSession.getTime(row, 8));
 		callLog->setConnectedTime(dbSession.getTime(row, 9));
@@ -1077,10 +1090,10 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceCallEvent(const soci::row &r
 		if (conferenceInfo == nullptr) {
 			conferenceInfo = ConferenceInfo::create();
 
-			IdentityAddress organizer = IdentityAddress(row.get<string>(16));
+			std::shared_ptr<Address> organizer = Address::create(row.get<string>(16));
 			conferenceInfo->setOrganizer(organizer);
 
-			ConferenceAddress uri = ConferenceAddress(row.get<string>(17));
+			std::shared_ptr<Address> uri = Address::create(row.get<string>(17));
 			conferenceInfo->setUri(uri);
 
 			conferenceInfo->setDateTime(dbSession.getTime(row, 18));
@@ -1097,7 +1110,7 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceCallEvent(const soci::row &r
 			soci::session *session = dbSession.getBackendSession();
 			soci::rowset<soci::row> participantRows = (session->prepare << query, soci::use(conferenceInfoId));
 			for (const auto &participantRow : participantRows) {
-				IdentityAddress participant(participantRow.get<string>(0));
+				std::shared_ptr<Address> participant = Address::create(participantRow.get<string>(0));
 				ConferenceInfo::participant_params_t participantParams;
 				conferenceInfo->addParticipant(participant, participantParams);
 			}
@@ -1132,8 +1145,8 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceChatMessageEvent(const share
 		}
 		dChatMessage->forceState(messageState);
 
-		dChatMessage->forceFromAddress(IdentityAddress(row.get<string>(3)));
-		dChatMessage->forceToAddress(ConferenceAddress(row.get<string>(4)));
+		dChatMessage->forceFromAddress(Address::create(row.get<string>(3)));
+		dChatMessage->forceToAddress(Address::create(row.get<string>(4)));
 
 		dChatMessage->setTime(dbSession.getTime(row, 5));
 		dChatMessage->setImdnMessageId(row.get<string>(6));
@@ -1154,7 +1167,7 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceChatMessageEvent(const share
 		}
 		if (row.get_indicator(24) != soci::i_null) {
 			dChatMessage->setReplyToMessageIdAndSenderAddress(row.get<string>(23),
-			                                                  IdentityAddress(row.get<string>(24)));
+			                                                  Address::create(row.get<string>(24)));
 		}
 
 		cache(chatMessage, eventId);
@@ -1168,7 +1181,7 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceParticipantEvent(const Confe
                                                                      const soci::row &row) const {
 
 	shared_ptr<AbstractChatRoom> chatRoom = findChatRoom(conferenceId);
-	IdentityAddress participantAddress(IdentityAddress(row.get<string>(12)));
+	std::shared_ptr<Address> participantAddress = Address::create(row.get<string>(12));
 
 	std::shared_ptr<ConferenceParticipantEvent> event = make_shared<ConferenceParticipantEvent>(
 	    type, getConferenceEventCreationTimeFromRow(row), conferenceId, participantAddress);
@@ -1180,8 +1193,8 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceParticipantDeviceEvent(const
                                                                            EventLog::Type type,
                                                                            const soci::row &row) const {
 	shared_ptr<AbstractChatRoom> chatRoom = findChatRoom(conferenceId);
-	IdentityAddress participantAddress(IdentityAddress(row.get<string>(12)));
-	IdentityAddress deviceAddress(IdentityAddress(row.get<string>(11)));
+	std::shared_ptr<Address> participantAddress = Address::create(row.get<string>(12));
+	std::shared_ptr<Address> deviceAddress = Address::create(row.get<string>(11));
 
 	shared_ptr<ConferenceParticipantDeviceEvent> event = make_shared<ConferenceParticipantDeviceEvent>(
 	    type, getConferenceEventCreationTimeFromRow(row), conferenceId, participantAddress, deviceAddress);
@@ -1195,7 +1208,7 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceSecurityEvent(const Conferen
 	return make_shared<ConferenceSecurityEvent>(
 	    getConferenceEventCreationTimeFromRow(row), conferenceId,
 	    static_cast<ConferenceSecurityEvent::SecurityEventType>(row.get<int>(16)),
-	    IdentityAddress(row.get<string>(17)));
+	    Address::create(row.get<string>(17)));
 }
 
 shared_ptr<EventLog> MainDbPrivate::selectConferenceEphemeralMessageEvent(const ConferenceId &conferenceId,
@@ -1337,8 +1350,8 @@ long long MainDbPrivate::insertConferenceChatMessageEvent(const shared_ptr<Event
 	if (eventId < 0) return -1;
 
 	shared_ptr<ChatMessage> chatMessage = static_pointer_cast<ConferenceChatMessageEvent>(eventLog)->getChatMessage();
-	const long long &fromSipAddressId = insertSipAddress(chatMessage->getFromAddress().asString());
-	const long long &toSipAddressId = insertSipAddress(chatMessage->getToAddress().asString());
+	const long long &fromSipAddressId = insertSipAddress(chatMessage->getFromAddress()->asStringUriOnly());
+	const long long &toSipAddressId = insertSipAddress(chatMessage->getToAddress()->asStringUriOnly());
 	const string &forwardInfo = chatMessage->getForwardInfo();
 	const tm &messageTime = Utils::getTimeTAsTm(chatMessage->getTime());
 	const int &state = int(chatMessage->getState());
@@ -1350,11 +1363,10 @@ long long MainDbPrivate::insertConferenceChatMessageEvent(const shared_ptr<Event
 	const int &markedAsRead = chatMessage->getPrivate()->isMarkedAsRead() ? 1 : 0;
 	const bool &isEphemeral = chatMessage->isEphemeral();
 	const string &callId = chatMessage->getPrivate()->getCallId();
-
 	const string &replyMessageId = chatMessage->getReplyToMessageId();
 	long long sipAddressId = 0;
 	if (!replyMessageId.empty()) {
-		sipAddressId = insertSipAddress(chatMessage->getReplyToSenderAddress().asString());
+		sipAddressId = insertSipAddress(chatMessage->getReplyToSenderAddress()->asStringUriOnly());
 	}
 	const long long &replyToSipAddressId = sipAddressId;
 
@@ -1391,7 +1403,7 @@ long long MainDbPrivate::insertConferenceChatMessageEvent(const shared_ptr<Event
 
 	shared_ptr<AbstractChatRoom> chatRoom(chatMessage->getChatRoom());
 	for (const auto &participant : chatRoom->getParticipants()) {
-		const long long &participantSipAddressId = selectSipAddressId(participant->getAddress().asString());
+		const long long &participantSipAddressId = selectSipAddressId(participant->getAddress()->asStringUriOnly());
 		insertChatMessageParticipant(eventId, participantSipAddressId, state, chatMessage->getTime());
 	}
 
@@ -1509,7 +1521,8 @@ long long MainDbPrivate::insertConferenceParticipantEvent(const shared_ptr<Event
 
 	shared_ptr<ConferenceParticipantEvent> participantEvent = static_pointer_cast<ConferenceParticipantEvent>(eventLog);
 
-	const long long &participantAddressId = insertSipAddress(participantEvent->getParticipantAddress().asString());
+	const long long &participantAddressId =
+	    insertSipAddress(participantEvent->getParticipantAddress()->asStringUriOnly());
 
 	*dbSession.getBackendSession() << "INSERT INTO conference_participant_event (event_id, participant_sip_address_id)"
 	                                  " VALUES (:eventId, :participantAddressId)",
@@ -1553,7 +1566,7 @@ long long MainDbPrivate::insertConferenceParticipantDeviceEvent(const shared_ptr
 	shared_ptr<ConferenceParticipantDeviceEvent> participantDeviceEvent =
 	    static_pointer_cast<ConferenceParticipantDeviceEvent>(eventLog);
 
-	const string participantAddress = participantDeviceEvent->getParticipantAddress().asString();
+	const string participantAddress = participantDeviceEvent->getParticipantAddress()->asStringUriOnly();
 	const long long &participantAddressId = selectSipAddressId(participantAddress);
 	if (participantAddressId < 0) {
 		lError() << "Unable to find sip address id of: `" << participantAddress << "`.";
@@ -1565,7 +1578,7 @@ long long MainDbPrivate::insertConferenceParticipantDeviceEvent(const shared_ptr
 		         << " and participant address id = " << participantAddressId;
 		return -1;
 	}
-	const long long &deviceAddressId = insertSipAddress(participantDeviceEvent->getDeviceAddress().asString());
+	const long long &deviceAddressId = insertSipAddress(participantDeviceEvent->getDeviceAddress()->asStringUriOnly());
 
 	*dbSession.getBackendSession()
 	    << "INSERT INTO conference_participant_device_event (event_id, device_sip_address_id)"
@@ -1602,7 +1615,7 @@ long long MainDbPrivate::insertConferenceSecurityEvent(const shared_ptr<EventLog
 
 	const int &securityEventType = int(static_pointer_cast<ConferenceSecurityEvent>(eventLog)->getSecurityEventType());
 	const string &faultyDevice =
-	    static_pointer_cast<ConferenceSecurityEvent>(eventLog)->getFaultyDeviceAddress().asString();
+	    static_pointer_cast<ConferenceSecurityEvent>(eventLog)->getFaultyDeviceAddress()->asStringUriOnly();
 
 	// insert security event into new table "conference_security_event"
 	soci::session *session = dbSession.getBackendSession();
@@ -1695,14 +1708,14 @@ long long MainDbPrivate::insertConferenceEphemeralMessageEvent(const shared_ptr<
 }
 
 void MainDbPrivate::setChatMessageParticipantState(const shared_ptr<EventLog> &eventLog,
-                                                   const IdentityAddress &participantAddress,
+                                                   const std::shared_ptr<Address> &participantAddress,
                                                    ChatMessage::State state,
                                                    time_t stateChangeTime) {
 #ifdef HAVE_DB_STORAGE
 	const EventLogPrivate *dEventLog = eventLog->getPrivate();
 	MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
 	const long long &eventId = dEventKey->storageId;
-	const long long &participantSipAddressId = selectSipAddressId(participantAddress.asString());
+	const long long &participantSipAddressId = selectSipAddressId(participantAddress->asStringUriOnly());
 
 	/* setChatMessageParticipantState can be called by updateConferenceChatMessageEvent, which try to update participant
 	 state by message state. However, we can not change state Displayed/DeliveredToUser to Delivered/NotDelivered. */
@@ -1742,11 +1755,11 @@ std::shared_ptr<CallLog> MainDbPrivate::selectCallLog(const soci::row &row) cons
 	auto callLog = getCallLogFromCache(dbCallLogId);
 	if (callLog) return callLog;
 
-	LinphoneAddress *from = linphone_address_new(row.get<string>(1).c_str());
-	if (row.get_indicator(2) == soci::i_ok) linphone_address_set_display_name(from, row.get<string>(2).c_str());
+	const std::shared_ptr<Address> from = Address::create(row.get<string>(1));
+	if (row.get_indicator(2) == soci::i_ok) from->setDisplayName(row.get<string>(2));
 
-	LinphoneAddress *to = linphone_address_new(row.get<string>(3).c_str());
-	if (row.get_indicator(4) == soci::i_ok) linphone_address_set_display_name(to, row.get<string>(4).c_str());
+	const std::shared_ptr<Address> to = Address::create(row.get<string>(3));
+	if (row.get_indicator(4) == soci::i_ok) to->setDisplayName(row.get<string>(4));
 
 	callLog = CallLog::create(q->getCore(), static_cast<LinphoneCallDir>(row.get<int>(5)), from, to);
 
@@ -1784,7 +1797,7 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row &
 	if (conferenceInfo) return conferenceInfo;
 
 	conferenceInfo = ConferenceInfo::create();
-	ConferenceAddress uri(row.get<string>(2));
+	std::shared_ptr<Address> uri = Address::create(row.get<string>(2));
 	conferenceInfo->setUri(uri);
 
 	conferenceInfo->setDateTime(dbSession.getTime(row, 3));
@@ -1800,7 +1813,7 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row &
 	// 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.
-	IdentityAddress organizer(row.get<string>(1));
+	std::shared_ptr<Address> organizer = Address::create(row.get<string>(1));
 	ConferenceInfo::participant_params_t defaultOrganizerParams;
 	defaultOrganizerParams.insert(std::make_pair(ConferenceInfo::sequenceParam, std::to_string(icsSequence)));
 	conferenceInfo->setOrganizer(organizer, defaultOrganizerParams);
@@ -1818,7 +1831,7 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row &
 	for (const auto &participantRow : participantRows) {
 		int deleted = participantRow.get<int>(1);
 		if (deleted == 0) {
-			IdentityAddress participantAddress(participantRow.get<string>(0));
+			std::shared_ptr<Address> participantAddress = Address::create(participantRow.get<string>(0));
 			const string participantParamsStr = participantRow.get<string>(2);
 			ConferenceInfo::participant_params_t participantParams =
 			    ConferenceInfo::stringToMemberParameters(participantParamsStr);
@@ -1834,7 +1847,7 @@ shared_ptr<ConferenceInfo> MainDbPrivate::selectConferenceInfo(const soci::row &
 
 	soci::rowset<soci::row> organizerRows = (session->prepare << organizerQuery, soci::use(dbConferenceInfoId));
 	for (const auto &organizerRow : organizerRows) {
-		IdentityAddress organizerAddress(organizerRow.get<string>(0));
+		std::shared_ptr<Address> organizerAddress = Address::create(organizerRow.get<string>(0));
 		const string organizerParamsStr = organizerRow.get<string>(1);
 		ConferenceInfo::participant_params_t organizerParams =
 		    ConferenceInfo::stringToMemberParameters(organizerParamsStr);
@@ -2470,10 +2483,10 @@ void MainDbPrivate::importLegacyHistory(DbSession &inDbSession) {
 			    soci::use(creationTime);
 
 			const long long &eventId = dbSession.getLastInsertId();
-			const long long &localSipAddressId =
-			    insertSipAddress(IdentityAddress(message.get<string>(LegacyMessageColLocalAddress)).asString());
-			const long long &remoteSipAddressId =
-			    insertSipAddress(IdentityAddress(message.get<string>(LegacyMessageColRemoteAddress)).asString());
+			const auto localAddress = Address::create(message.get<string>(LegacyMessageColLocalAddress));
+			const long long &localSipAddressId = insertSipAddress(localAddress->asStringUriOnly());
+			const auto remoteAddress = Address::create(message.get<string>(LegacyMessageColRemoteAddress));
+			const long long &remoteSipAddressId = insertSipAddress(remoteAddress->asStringUriOnly());
 			const long long &chatRoomId =
 			    insertOrUpdateImportedBasicChatRoom(remoteSipAddressId, localSipAddressId, creationTime);
 			const int &isSecured = message.get<int>(LegacyMessageColIsSecured, 0);
@@ -2547,9 +2560,9 @@ void MainDbPrivate::importLegacyCallLogs(DbSession &inDbSession) {
 				continue;
 			}
 
-			auto callLog = CallLog::create(q->getCore(), static_cast<LinphoneCallDir>(direction),
-			                               linphone_address_new(log.get<string>(LegacyCallLogColFrom).c_str()),
-			                               linphone_address_new(log.get<string>(LegacyCallLogColTo).c_str()));
+			const std::shared_ptr<Address> from = Address::create(log.get<string>(LegacyCallLogColFrom));
+			const std::shared_ptr<Address> to = Address::create(log.get<string>(LegacyCallLogColTo));
+			auto callLog = CallLog::create(q->getCore(), static_cast<LinphoneCallDir>(direction), from, to);
 
 			callLog->setDuration(log.get<int>(LegacyCallLogColDuration));
 			callLog->setStartTime((time_t)std::stoul(log.get<string>(LegacyCallLogColStartTime)));
@@ -3512,7 +3525,8 @@ shared_ptr<EventLog> MainDb::getEvent(const unique_ptr<MainDb> &mainDb, const lo
 		*d->dbSession.getBackendSession() << Statements::get(Statements::SelectConferenceEvent), soci::into(row),
 		    soci::use(storageId);
 
-		ConferenceId conferenceId(ConferenceAddress(row.get<string>(16)), ConferenceAddress(row.get<string>(17)));
+		ConferenceId conferenceId(Address::create(row.get<string>(16))->getSharedFromThis(),
+		                          Address::create(row.get<string>(17)));
 		shared_ptr<AbstractChatRoom> chatRoom = d->findChatRoom(conferenceId);
 		if (!chatRoom) return shared_ptr<EventLog>();
 
@@ -3546,8 +3560,8 @@ list<shared_ptr<EventLog>> MainDb::getConferenceNotifiedEvents(const ConferenceI
 
 	/*
 	DurationLogger durationLogger(
-	    "Get conference notified events of: (peer=" + conferenceId.getPeerAddress().asString() +
-	    ", local=" + conferenceId.getLocalAddress().asString() +
+	    "Get conference notified events of: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() +
 	    ", lastNotifyId=" + Utils::toString(lastNotifyId) + ")."
 	);
 	*/
@@ -3574,8 +3588,8 @@ int MainDb::getChatMessageCount(const ConferenceId &conferenceId) const {
 #ifdef HAVE_DB_STORAGE
 	/*
 	DurationLogger durationLogger(
-	    "Get chat messages count of: (peer=" + conferenceId.getPeerAddress().asString() +
-	    ", local=" + conferenceId.getLocalAddress().asString() + ")."
+	    "Get chat messages count of: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() + ")."
 	);
 	*/
 
@@ -3623,8 +3637,8 @@ int MainDb::getUnreadChatMessageCount(const ConferenceId &conferenceId) const {
 
 	/*
 	DurationLogger durationLogger(
-	    "Get unread chat messages count of: (peer=" + conferenceId.getPeerAddress().asString() +
-	    ", local=" + conferenceId.getLocalAddress().asString() + ")."
+	    "Get unread chat messages count of: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() + ")."
 	);
 	*/
 
@@ -3660,8 +3674,8 @@ void MainDb::markChatMessagesAsRead(const ConferenceId &conferenceId) const {
 
 	/*
 	DurationLogger durationLogger(
-	    "Mark chat messages as read of: (peer=" + conferenceId.getPeerAddress().asString() +
-	    ", local=" + conferenceId.getLocalAddress().asString() + ")."
+	    "Mark chat messages as read of: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() + ")."
 	);
 	*/
 
@@ -3731,8 +3745,9 @@ list<shared_ptr<ChatMessage>> MainDb::getUnreadChatMessages(const ConferenceId &
 	static const string query =
 	    Statements::get(Statements::SelectConferenceEvents) + string(" AND marked_as_read == 0");
 
-	DurationLogger durationLogger("Get unread chat messages: (peer=" + conferenceId.getPeerAddress().asString() +
-	                              ", local=" + conferenceId.getLocalAddress().asString() + ").");
+	DurationLogger durationLogger(
+	    "Get unread chat messages: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() + ").");
 
 	return L_DB_TRANSACTION {
 		L_D();
@@ -3835,7 +3850,7 @@ list<MainDb::ParticipantState> MainDb::getChatMessageParticipantsByImdnState(con
 
 		list<MainDb::ParticipantState> result;
 		for (const auto &row : rows)
-			result.emplace_back(IdentityAddress(row.get<string>(0)), state, d->dbSession.getTime(row, 1));
+			result.emplace_back(Address::create(row.get<string>(0)), state, d->dbSession.getTime(row, 1));
 		return result;
 	};
 #else
@@ -3871,7 +3886,7 @@ list<ChatMessage::State> MainDb::getChatMessageParticipantStates(const shared_pt
 }
 
 ChatMessage::State MainDb::getChatMessageParticipantState(const shared_ptr<EventLog> &eventLog,
-                                                          const IdentityAddress &participantAddress) const {
+                                                          const std::shared_ptr<Address> &participantAddress) const {
 #ifdef HAVE_DB_STORAGE
 	return L_DB_TRANSACTION {
 		L_D();
@@ -3879,7 +3894,7 @@ ChatMessage::State MainDb::getChatMessageParticipantState(const shared_ptr<Event
 		const EventLogPrivate *dEventLog = eventLog->getPrivate();
 		MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
 		const long long &eventId = dEventKey->storageId;
-		const long long &participantSipAddressId = d->selectSipAddressId(participantAddress.asString());
+		const long long &participantSipAddressId = d->selectSipAddressId(participantAddress->asStringUriOnly());
 
 		unsigned int state;
 		*d->dbSession.getBackendSession()
@@ -3895,7 +3910,7 @@ ChatMessage::State MainDb::getChatMessageParticipantState(const shared_ptr<Event
 }
 
 void MainDb::setChatMessageParticipantState(const shared_ptr<EventLog> &eventLog,
-                                            const IdentityAddress &participantAddress,
+                                            const std::shared_ptr<Address> &participantAddress,
                                             ChatMessage::State state,
                                             time_t stateChangeTime) {
 #ifdef HAVE_DB_STORAGE
@@ -3979,8 +3994,8 @@ list<shared_ptr<ChatMessage>> MainDb::findChatMessages(const ConferenceId &confe
 
 	/*
 	DurationLogger durationLogger(
-	    "Find chat messages: (peer=" + conferenceId.getPeerAddress().asString() +
-	    ", local=" + conferenceId.getLocalAddress().asString() + ")."
+	    "Find chat messages: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() + ")."
 	);
 	*/
 	return L_DB_TRANSACTION {
@@ -4017,8 +4032,8 @@ list<shared_ptr<ChatMessage>> MainDb::findChatMessages(const ConferenceId &confe
 
 	/*
 	DurationLogger durationLogger(
-	    "Find chat messages: (peer=" + conferenceId.getPeerAddress().asString() +
-	    ", local=" + conferenceId.getLocalAddress().asString() + ")."
+	    "Find chat messages: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() + ")."
 	);
 	*/
 	return L_DB_TRANSACTION {
@@ -4132,8 +4147,8 @@ list<shared_ptr<ChatMessage>> MainDb::findChatMessagesToBeNotifiedAsDelivered()
 
 	/*
 	DurationLogger durationLogger(
-	    "Find chat messages to be notified as delivered: (peer=" + conferenceId.getPeerAddress().asString() +
-	    ", local=" + conferenceId.getLocalAddress().asString() + ")."
+	    "Find chat messages to be notified as delivered: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() + ")."
 	);
 	*/
 
@@ -4206,8 +4221,8 @@ MainDb::getHistoryRange(const ConferenceId &conferenceId, int begin, int end, Fi
 
 	/*
 	DurationLogger durationLogger(
-	    "Get history range of: (peer=" + conferenceId.getPeerAddress().asString() +
-	    ", local=" + conferenceId.getLocalAddress().asString() +
+	    "Get history range of: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() +
 	    ", begin=" + Utils::toString(begin) + ", end=" + Utils::toString(end) + ")."
 	);
 	*/
@@ -4266,8 +4281,8 @@ void MainDb::cleanHistory(const ConferenceId &conferenceId, FilterMask mask) {
 
 	/*
 	DurationLogger durationLogger(
-	    "Clean history of: (peer=" + conferenceId.getPeerAddress().asString() +
-	    ", local=" + conferenceId.getLocalAddress().asString() +
+	    "Clean history of: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+	    ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() +
 	    ", mask=" + Utils::toString(mask) + ")."
 	);
 	*/
@@ -4435,8 +4450,7 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const {
 
 		soci::rowset<soci::row> rows = (session->prepare << query);
 		for (const auto &row : rows) {
-			ConferenceId conferenceId =
-			    ConferenceId(ConferenceAddress(row.get<string>(1)), ConferenceAddress(row.get<string>(2)));
+			ConferenceId conferenceId(Address::create(row.get<string>(1)), Address::create(row.get<string>(2)));
 
 			shared_ptr<AbstractChatRoom> chatRoom = core->findChatRoom(conferenceId, false);
 			if (chatRoom) {
@@ -4473,7 +4487,7 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const {
 				shared_ptr<Participant> me;
 				for (const auto &row : rows) {
 					shared_ptr<Participant> participant =
-					    Participant::create(nullptr, IdentityAddress(row.get<string>(1)));
+					    Participant::create(nullptr, Address::create(row.get<string>(1)));
 					participant->setAdmin(!!row.get<int>(2));
 
 					// Fetch devices.
@@ -4487,22 +4501,24 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const {
 						soci::rowset<soci::row> rows = (session->prepare << query, soci::use(participantId));
 						for (const auto &row : rows) {
 							shared_ptr<ParticipantDevice> device =
-							    participant->addDevice(IdentityAddress(row.get<string>(0)), row.get<string>(2, ""));
+							    participant->addDevice(Address::create(row.get<string>(0)), row.get<string>(2, ""));
 							device->setState(ParticipantDevice::State(static_cast<unsigned int>(row.get<int>(1, 0))));
 						}
 					}
 
-					if (participant->getAddress() == conferenceId.getLocalAddress().getAddressWithoutGruu())
+					if (participant->getAddress()->weakEqual(*conferenceId.getLocalAddress())) {
 						me = participant;
-					else participants.push_back(participant);
+					} else {
+						participants.push_back(participant);
+					}
 				}
 
 				Conference *conference = nullptr;
 				if (!linphone_core_conference_server_enabled(core->getCCore())) {
 					bool hasBeenLeft = !!row.get<int>(8, 0);
 					if (!me) {
-						lError() << "Unable to find me in: (peer=" + conferenceId.getPeerAddress().asString() +
-						                ", local=" + conferenceId.getLocalAddress().asString() + ").";
+						lError() << "Unable to find me in: (peer=" + conferenceId.getPeerAddress()->asStringUriOnly() +
+						                ", local=" + conferenceId.getLocalAddress()->asStringUriOnly() + ").";
 						continue;
 					}
 					shared_ptr<ClientGroupChatRoom> clientGroupChatRoom(new ClientGroupChatRoom(
@@ -4525,7 +4541,7 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const {
 						soci::rowset<soci::row> rows = (session->prepare << query, soci::use(dbChatRoomId));
 						for (const auto &row : rows) {
 							ConferenceId previousId =
-							    ConferenceId(ConferenceAddress(row.get<string>(0)), conferenceId.getLocalAddress());
+							    ConferenceId(Address::create(row.get<string>(0)), conferenceId.getLocalAddress());
 							if (previousId != conferenceId) {
 								lInfo() << "Keeping around previous chat room ID [" << previousId
 								        << "] in case BYE is received for exhumed chat room [" << conferenceId << "]";
@@ -4559,8 +4575,8 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const {
 			dChatRoom->setLastUpdateTime(lastUpdateTime);
 			dChatRoom->setIsEmpty(lastMessageId == 0);
 
-			lDebug() << "Found chat room in DB: (peer=" << conferenceId.getPeerAddress().asString()
-			         << ", local=" << conferenceId.getLocalAddress().asString() << ").";
+			lDebug() << "Found chat room in DB: (peer=" << conferenceId.getPeerAddress()->asStringUriOnly()
+			         << ", local=" << conferenceId.getLocalAddress()->asStringUriOnly() << ").";
 
 			chatRooms.push_back(chatRoom);
 		}
@@ -4577,7 +4593,8 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const {
 void MainDbPrivate::insertNewPreviousConferenceId(const ConferenceId &currentConfId,
                                                   const ConferenceId &previousConfId) {
 #ifdef HAVE_DB_STORAGE
-	const long long &previousConferenceSipAddressId = selectSipAddressId(previousConfId.getPeerAddress().asString());
+	const long long &previousConferenceSipAddressId =
+	    selectSipAddressId(previousConfId.getPeerAddress()->asStringUriOnly());
 	const long long &chatRoomId = selectChatRoomId(currentConfId);
 
 	*dbSession.getBackendSession() << "INSERT INTO one_to_one_chat_room_previous_conference_id ("
@@ -4603,7 +4620,8 @@ void MainDb::insertNewPreviousConferenceId(const ConferenceId &currentConfId, co
 
 void MainDbPrivate::removePreviousConferenceId(const ConferenceId &previousConfId) {
 #ifdef HAVE_DB_STORAGE
-	const long long &previousConferenceSipAddressId = selectSipAddressId(previousConfId.getPeerAddress().asString());
+	const long long &previousConferenceSipAddressId =
+	    selectSipAddressId(previousConfId.getPeerAddress()->asStringUriOnly());
 
 	*dbSession.getBackendSession() << "DELETE FROM one_to_one_chat_room_previous_conference_id WHERE "
 	                                  "sip_address_id = :previousConferenceSipAddressId",
@@ -4657,7 +4675,7 @@ void MainDb::updateChatRoomConferenceId(const ConferenceId oldConferenceId, cons
 	L_DB_TRANSACTION {
 		L_D();
 
-		const long long &peerSipAddressId = d->insertSipAddress(newConferenceId.getPeerAddress().asString());
+		const long long &peerSipAddressId = d->insertSipAddress(newConferenceId.getPeerAddress()->asStringUriOnly());
 		const long long &dbChatRoomId = d->selectChatRoomId(oldConferenceId);
 
 		*d->dbSession.getBackendSession() << "UPDATE chat_room"
@@ -4724,8 +4742,8 @@ void MainDb::migrateBasicToClientGroupChatRoom(const shared_ptr<AbstractChatRoom
 		const long long &dbChatRoomId = d->selectChatRoomId(basicChatRoom->getConferenceId());
 
 		const ConferenceId &newConferenceId = clientGroupChatRoom->getConferenceId();
-		const long long &peerSipAddressId = d->insertSipAddress(newConferenceId.getPeerAddress().asString());
-		const long long &localSipAddressId = d->insertSipAddress(newConferenceId.getLocalAddress().asString());
+		const long long &peerSipAddressId = d->insertSipAddress(newConferenceId.getPeerAddress()->asStringUriOnly());
+		const long long &localSipAddressId = d->insertSipAddress(newConferenceId.getLocalAddress()->asStringUriOnly());
 		const int &capabilities = clientGroupChatRoom->getCapabilities();
 
 		*d->dbSession.getBackendSession() << "UPDATE chat_room"
@@ -4737,17 +4755,17 @@ void MainDb::migrateBasicToClientGroupChatRoom(const shared_ptr<AbstractChatRoom
 
 		shared_ptr<Participant> me = clientGroupChatRoom->getMe();
 		long long meId =
-		    d->insertChatRoomParticipant(dbChatRoomId, d->insertSipAddress(me->getAddress().asString()), true);
+		    d->insertChatRoomParticipant(dbChatRoomId, d->insertSipAddress(me->getAddress()->asStringUriOnly()), true);
 		for (const auto &device : me->getDevices())
-			d->insertChatRoomParticipantDevice(meId, d->insertSipAddress(device->getAddress().asString()),
+			d->insertChatRoomParticipantDevice(meId, d->insertSipAddress(device->getAddress()->asStringUriOnly()),
 			                                   device->getName());
 
 		for (const auto &participant : clientGroupChatRoom->getParticipants()) {
 			long long participantId = d->insertChatRoomParticipant(
-			    dbChatRoomId, d->insertSipAddress(participant->getAddress().asString()), true);
+			    dbChatRoomId, d->insertSipAddress(participant->getAddress()->asStringUriOnly()), true);
 			for (const auto &device : participant->getDevices())
-				d->insertChatRoomParticipantDevice(participantId, d->insertSipAddress(device->getAddress().asString()),
-				                                   device->getName());
+				d->insertChatRoomParticipantDevice(
+				    participantId, d->insertSipAddress(device->getAddress()->asStringUriOnly()), device->getName());
 		}
 
 		tr.commit();
@@ -4755,9 +4773,8 @@ void MainDb::migrateBasicToClientGroupChatRoom(const shared_ptr<AbstractChatRoom
 #endif
 }
 
-IdentityAddress
-MainDb::findMissingOneToOneConferenceChatRoomParticipantAddress(const shared_ptr<AbstractChatRoom> &chatRoom,
-                                                                const IdentityAddress &presentParticipantAddr) {
+std::shared_ptr<Address> MainDb::findMissingOneToOneConferenceChatRoomParticipantAddress(
+    const shared_ptr<AbstractChatRoom> &chatRoom, const std::shared_ptr<Address> &presentParticipantAddr) {
 #ifdef HAVE_DB_STORAGE
 	L_ASSERT(linphone_core_conference_server_enabled(chatRoom->getCore()->getCCore()));
 	L_ASSERT(chatRoom->getCapabilities() & ChatRoom::Capabilities::OneToOne);
@@ -4781,32 +4798,34 @@ MainDb::findMissingOneToOneConferenceChatRoomParticipantAddress(const shared_ptr
 		                                     " AND participant_b_sip_address_id = participant_b_sip_address.id",
 		    soci::into(participantASipAddress), soci::into(participantBSipAddress), soci::use(chatRoomId);
 
-		string presentParticipantAddress(presentParticipantAddr.asString());
+		string presentParticipantAddress(presentParticipantAddr->asStringUriOnly());
 		if (presentParticipantAddress == participantASipAddress) missingParticipantAddress = participantBSipAddress;
 		else if (presentParticipantAddress == participantBSipAddress)
 			missingParticipantAddress = participantASipAddress;
 
-		return IdentityAddress(missingParticipantAddress);
+		auto missingParticipant = Address::create(missingParticipantAddress);
+		return missingParticipant;
 	};
 #else
-	return IdentityAddress();
+	return nullptr;
 #endif
 }
 
-ConferenceAddress MainDb::findOneToOneConferenceChatRoomAddress(const IdentityAddress &participantA,
-                                                                const IdentityAddress &participantB,
-                                                                bool encrypted) const {
+std::shared_ptr<Address> MainDb::findOneToOneConferenceChatRoomAddress(const std::shared_ptr<Address> &participantA,
+                                                                       const std::shared_ptr<Address> &participantB,
+                                                                       bool encrypted) const {
 #ifdef HAVE_DB_STORAGE
 	return L_DB_TRANSACTION {
 		L_D();
 
-		const long long &participantASipAddressId = d->selectSipAddressId(participantA.asString());
-		const long long &participantBSipAddressId = d->selectSipAddressId(participantB.asString());
-		if (participantASipAddressId == -1 || participantBSipAddressId == -1) return ConferenceAddress();
+		std::shared_ptr<Address> address = nullptr;
+		const long long &participantASipAddressId = d->selectSipAddressId(participantA->asStringUriOnly());
+		const long long &participantBSipAddressId = d->selectSipAddressId(participantB->asStringUriOnly());
+		if (participantASipAddressId == -1 || participantBSipAddressId == -1) return address;
 
 		const long long &chatRoomId =
 		    d->selectOneToOneChatRoomId(participantASipAddressId, participantBSipAddressId, encrypted);
-		if (chatRoomId == -1) return ConferenceAddress();
+		if (chatRoomId == -1) return address;
 
 		string chatRoomAddress;
 		*d->dbSession.getBackendSession()
@@ -4815,10 +4834,11 @@ ConferenceAddress MainDb::findOneToOneConferenceChatRoomAddress(const IdentityAd
 		       " WHERE chat_room.id = :chatRoomId AND peer_sip_address_id = sip_address.id",
 		    soci::use(chatRoomId), soci::into(chatRoomAddress);
 
-		return ConferenceAddress(chatRoomAddress);
+		address = Address::create(chatRoomAddress);
+		return address;
 	};
 #else
-	return ConferenceAddress();
+	return nullptr;
 #endif
 }
 
@@ -4832,8 +4852,9 @@ void MainDb::insertOneToOneConferenceChatRoom(const shared_ptr<AbstractChatRoom>
 
 		const list<shared_ptr<Participant>> &participants = chatRoom->getParticipants();
 		const long long &participantASipAddressId =
-		    d->selectSipAddressId(participants.front()->getAddress().asString());
-		const long long &participantBSipAddressId = d->selectSipAddressId(participants.back()->getAddress().asString());
+		    d->selectSipAddressId(participants.front()->getAddress()->asStringUriOnly());
+		const long long &participantBSipAddressId =
+		    d->selectSipAddressId(participants.back()->getAddress()->asStringUriOnly());
 		L_ASSERT(participantASipAddressId != -1);
 		L_ASSERT(participantBSipAddressId != -1);
 
@@ -4881,9 +4902,10 @@ void MainDb::updateChatRoomParticipantDevice(const shared_ptr<AbstractChatRoom>
 
 			const long long &dbChatRoomId = d->selectChatRoomId(chatRoom->getConferenceId());
 			const long long &participantSipAddressId =
-			    d->selectSipAddressId(device->getParticipant()->getAddress().asString());
+			    d->selectSipAddressId(device->getParticipant()->getAddress()->asStringUriOnly());
 			const long long &participantId = d->selectChatRoomParticipantId(dbChatRoomId, participantSipAddressId);
-			const long long &participantSipDeviceAddressId = d->selectSipAddressId(device->getAddress().asString());
+			const long long &participantSipDeviceAddressId =
+			    d->selectSipAddressId(device->getAddress()->asStringUriOnly());
 			unsigned int state = static_cast<unsigned int>(device->getState());
 			*d->dbSession.getBackendSession() << "UPDATE chat_room_participant_device SET state = :state, name = :name"
 			                                     " WHERE chat_room_participant_id = :participantId AND "
@@ -4898,12 +4920,12 @@ void MainDb::updateChatRoomParticipantDevice(const shared_ptr<AbstractChatRoom>
 }
 
 void MainDb::deleteChatRoomParticipant(const std::shared_ptr<AbstractChatRoom> &chatRoom,
-                                       const IdentityAddress &participant) {
+                                       const std::shared_ptr<Address> &participant) {
 #ifdef HAVE_DB_STORAGE
 	L_D();
 	if (isInitialized()) {
 		const long long &dbChatRoomId = d->selectChatRoomId(chatRoom->getConferenceId());
-		const long long &participantSipAddressId = d->selectSipAddressId(participant.asString());
+		const long long &participantSipAddressId = d->selectSipAddressId(participant->asStringUriOnly());
 		d->deleteChatRoomParticipant(dbChatRoomId, participantSipAddressId);
 	}
 #endif
@@ -4916,7 +4938,7 @@ void MainDb::deleteChatRoomParticipantDevice(const shared_ptr<AbstractChatRoom>
 	if (isInitialized()) {
 		const long long &dbChatRoomId = d->selectChatRoomId(chatRoom->getConferenceId());
 		const long long &participantSipAddressId =
-		    d->selectSipAddressId(device->getParticipant()->getAddress().asString());
+		    d->selectSipAddressId(device->getParticipant()->getAddress()->asStringUriOnly());
 		const long long &participantId = d->selectChatRoomParticipantId(dbChatRoomId, participantSipAddressId);
 		d->deleteChatRoomParticipantDevice(participantId, participantSipAddressId);
 	}
@@ -5004,16 +5026,16 @@ std::shared_ptr<ConferenceInfo> MainDb::getConferenceInfo(long long conferenceIn
 #endif
 }
 
-std::shared_ptr<ConferenceInfo> MainDb::getConferenceInfoFromURI(const ConferenceAddress &uri) const {
+std::shared_ptr<ConferenceInfo> MainDb::getConferenceInfoFromURI(const std::shared_ptr<Address> &uri) const {
 #ifdef HAVE_DB_STORAGE
-	if (isInitialized()) {
+	if (isInitialized() && uri) {
 		string query = "SELECT conference_info.id, organizer_sip_address.value, uri_sip_address.value,"
 		               " start_time, duration, subject, description, state, ics_sequence, ics_uid"
 		               " FROM conference_info, sip_address AS organizer_sip_address, sip_address AS uri_sip_address"
 		               " WHERE conference_info.organizer_sip_address_id = organizer_sip_address.id AND "
 		               "conference_info.uri_sip_address_id = uri_sip_address.id"
 		               "  AND uri_sip_address.value = '" +
-		               uri.asString() + "'";
+		               uri->asStringUriOnly() + "'";
 
 		return L_DB_TRANSACTION {
 			L_D();
@@ -5058,7 +5080,7 @@ void MainDb::deleteConferenceInfo(const std::shared_ptr<ConferenceInfo> &confere
 		L_DB_TRANSACTION {
 			L_D();
 
-			const long long &uriSipAddressId = d->selectSipAddressId(conferenceInfo->getUri().asString());
+			const long long &uriSipAddressId = d->selectSipAddressId(conferenceInfo->getUri()->asStringUriOnly());
 			const long long &dbConferenceId = d->selectConferenceInfoId(uriSipAddressId);
 
 			*d->dbSession.getBackendSession() << "DELETE FROM conference_info WHERE id = :conferenceId",
@@ -5184,7 +5206,7 @@ std::list<std::shared_ptr<CallLog>> MainDb::getCallHistory(int limit) {
 #endif
 }
 
-std::list<std::shared_ptr<CallLog>> MainDb::getCallHistory(const ConferenceAddress &address, int limit) {
+std::list<std::shared_ptr<CallLog>> MainDb::getCallHistory(const std::shared_ptr<Address> &address, int limit) {
 #ifdef HAVE_DB_STORAGE
 	string query = "SELECT conference_call.id, from_sip_address.value, from_sip_address.display_name, "
 	               "to_sip_address.value, to_sip_address.display_name,"
@@ -5194,10 +5216,10 @@ std::list<std::shared_ptr<CallLog>> MainDb::getCallHistory(const ConferenceAddre
 	               " WHERE conference_call.from_sip_address_id = from_sip_address.id AND "
 	               "conference_call.to_sip_address_id = to_sip_address.id"
 	               "  AND (from_sip_address.value LIKE '%%" +
-	               address.asString() +
+	               address->asStringUriOnly() +
 	               "%%'"
 	               "  OR to_sip_address.value LIKE '%%" +
-	               address.asString() +
+	               address->asStringUriOnly() +
 	               "%%')"
 	               " ORDER BY conference_call.id DESC";
 
@@ -5228,7 +5250,7 @@ std::list<std::shared_ptr<CallLog>> MainDb::getCallHistory(const ConferenceAddre
 }
 
 std::list<std::shared_ptr<CallLog>>
-MainDb::getCallHistory(const ConferenceAddress &peer, const ConferenceAddress &local, int limit) {
+MainDb::getCallHistory(const std::shared_ptr<Address> &peer, const std::shared_ptr<Address> &local, int limit) {
 #ifdef HAVE_DB_STORAGE
 	string query = "SELECT conference_call.id, from_sip_address.value, from_sip_address.display_name, "
 	               "to_sip_address.value, to_sip_address.display_name,"
@@ -5238,10 +5260,10 @@ MainDb::getCallHistory(const ConferenceAddress &peer, const ConferenceAddress &l
 	               " WHERE conference_call.from_sip_address_id = from_sip_address.id AND "
 	               "conference_call.to_sip_address_id = to_sip_address.id"
 	               "  AND ((from_sip_address.value LIKE '%%" +
-	               local.asString() + "%%' AND to_sip_address.value LIKE '%%" + peer.asString() +
+	               local->asStringUriOnly() + "%%' AND to_sip_address.value LIKE '%%" + peer->asStringUriOnly() +
 	               "%%' AND direction = 0) OR"
 	               "  (from_sip_address.value LIKE '%%" +
-	               peer.asString() + "%%' AND to_sip_address.value LIKE '%%" + local.asString() +
+	               peer->asStringUriOnly() + "%%' AND to_sip_address.value LIKE '%%" + local->asStringUriOnly() +
 	               "%%' AND DIRECTION = 1))"
 	               " ORDER BY conference_call.id DESC";
 
diff --git a/src/db/main-db.h b/src/db/main-db.h
index d309198295e07741a36c993dee36c210d35ceedb..4f9573fa5722c55ca0fb9365ba5241afdabf748f 100644
--- a/src/db/main-db.h
+++ b/src/db/main-db.h
@@ -66,11 +66,11 @@ public:
 	typedef EnumMask<Filter> FilterMask;
 
 	struct ParticipantState {
-		ParticipantState(const IdentityAddress &address, ChatMessage::State state, time_t timestamp)
+		ParticipantState(const std::shared_ptr<Address> &address, ChatMessage::State state, time_t timestamp)
 		    : address(address), state(state), timestamp(timestamp) {
 		}
 
-		IdentityAddress address;
+		std::shared_ptr<Address> address;
 		ChatMessage::State state = ChatMessage::State::Idle;
 		time_t timestamp = 0;
 	};
@@ -116,9 +116,9 @@ public:
 	                                                                  ChatMessage::State state) const;
 	std::list<ChatMessage::State> getChatMessageParticipantStates(const std::shared_ptr<EventLog> &eventLog) const;
 	ChatMessage::State getChatMessageParticipantState(const std::shared_ptr<EventLog> &eventLog,
-	                                                  const IdentityAddress &participantAddress) const;
+	                                                  const std::shared_ptr<Address> &participantAddress) const;
 	void setChatMessageParticipantState(const std::shared_ptr<EventLog> &eventLog,
-	                                    const IdentityAddress &participantAddress,
+	                                    const std::shared_ptr<Address> &participantAddress,
 	                                    ChatMessage::State state,
 	                                    time_t stateChangeTime);
 
@@ -177,19 +177,19 @@ public:
 	void migrateBasicToClientGroupChatRoom(const std::shared_ptr<AbstractChatRoom> &basicChatRoom,
 	                                       const std::shared_ptr<AbstractChatRoom> &clientGroupChatRoom);
 
-	IdentityAddress
+	std::shared_ptr<Address>
 	findMissingOneToOneConferenceChatRoomParticipantAddress(const std::shared_ptr<AbstractChatRoom> &chatRoom,
-	                                                        const IdentityAddress &presentParticipantAddr);
-	ConferenceAddress findOneToOneConferenceChatRoomAddress(const IdentityAddress &participantA,
-	                                                        const IdentityAddress &participantB,
-	                                                        bool encrypted) const;
+	                                                        const std::shared_ptr<Address> &presentParticipantAddr);
+	std::shared_ptr<Address> findOneToOneConferenceChatRoomAddress(const std::shared_ptr<Address> &participantA,
+	                                                               const std::shared_ptr<Address> &participantB,
+	                                                               bool encrypted) const;
 	void insertOneToOneConferenceChatRoom(const std::shared_ptr<AbstractChatRoom> &chatRoom, bool encrypted);
 
 	void updateChatRoomParticipantDevice(const std::shared_ptr<AbstractChatRoom> &chatRoom,
 	                                     const std::shared_ptr<ParticipantDevice> &device);
 
 	void deleteChatRoomParticipant(const std::shared_ptr<AbstractChatRoom> &chatRoom,
-	                               const IdentityAddress &participant);
+	                               const std::shared_ptr<Address> &participant);
 
 	void deleteChatRoomParticipantDevice(const std::shared_ptr<AbstractChatRoom> &chatRoom,
 	                                     const std::shared_ptr<ParticipantDevice> &device);
@@ -203,7 +203,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 ConferenceAddress &uri) const;
+	std::shared_ptr<ConferenceInfo> getConferenceInfoFromURI(const std::shared_ptr<Address> &uri) const;
 	void insertConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo);
 	void deleteConferenceInfo(const std::shared_ptr<ConferenceInfo> &conferenceInfo);
 
@@ -217,9 +217,9 @@ public:
 	std::shared_ptr<CallLog> getCallLog(const std::string &callId, int limit);
 
 	std::list<std::shared_ptr<CallLog>> getCallHistory(int limit = -1);
-	std::list<std::shared_ptr<CallLog>> getCallHistory(const ConferenceAddress &address, int limit = -1);
+	std::list<std::shared_ptr<CallLog>> getCallHistory(const std::shared_ptr<Address> &address, int limit = -1);
 	std::list<std::shared_ptr<CallLog>>
-	getCallHistory(const ConferenceAddress &peer, const ConferenceAddress &local, int limit = -1);
+	getCallHistory(const std::shared_ptr<Address> &peer, const std::shared_ptr<Address> &local, int limit = -1);
 	std::shared_ptr<CallLog> getLastOutgoingCall();
 	void deleteCallHistory();
 
diff --git a/src/event-log/conference/conference-participant-device-event.cpp b/src/event-log/conference/conference-participant-device-event.cpp
index e581cf1a547bed532f7b4ecc728fae1e39d15d15..f4d9b2766f3e0ffde612736a66a2c86bd03c9d7a 100644
--- a/src/event-log/conference/conference-participant-device-event.cpp
+++ b/src/event-log/conference/conference-participant-device-event.cpp
@@ -33,7 +33,7 @@ LINPHONE_BEGIN_NAMESPACE
 
 class ConferenceParticipantDeviceEventPrivate : public ConferenceParticipantEventPrivate {
 public:
-	IdentityAddress deviceAddress;
+	std::shared_ptr<Address> deviceAddress;
 	string deviceName;
 };
 
@@ -42,8 +42,8 @@ public:
 ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent(Type type,
                                                                    time_t creationTime,
                                                                    const ConferenceId &conferenceId,
-                                                                   const IdentityAddress &participantAddress,
-                                                                   const IdentityAddress &deviceAddress,
+                                                                   const std::shared_ptr<Address> &participantAddress,
+                                                                   const std::shared_ptr<Address> &deviceAddress,
                                                                    const string &name)
     : ConferenceParticipantEvent(
           *new ConferenceParticipantDeviceEventPrivate, type, creationTime, conferenceId, participantAddress) {
@@ -56,7 +56,7 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent(Type type,
 	d->deviceName = name;
 }
 
-const IdentityAddress &ConferenceParticipantDeviceEvent::getDeviceAddress() const {
+const std::shared_ptr<Address> &ConferenceParticipantDeviceEvent::getDeviceAddress() const {
 	L_D();
 	return d->deviceAddress;
 }
diff --git a/src/event-log/conference/conference-participant-device-event.h b/src/event-log/conference/conference-participant-device-event.h
index 309bdc48582af6b2282d948943d17a2e60dc86eb..2dc965c0b753402461d85e630dcb263e9d19428f 100644
--- a/src/event-log/conference/conference-participant-device-event.h
+++ b/src/event-log/conference/conference-participant-device-event.h
@@ -39,11 +39,11 @@ public:
 	ConferenceParticipantDeviceEvent(Type type,
 	                                 time_t creationTime,
 	                                 const ConferenceId &conferenceId,
-	                                 const IdentityAddress &participantAddress,
-	                                 const IdentityAddress &deviceAddress,
+	                                 const std::shared_ptr<Address> &participantAddress,
+	                                 const std::shared_ptr<Address> &deviceAddress,
 	                                 const std::string &name = "");
 
-	const IdentityAddress &getDeviceAddress() const;
+	const std::shared_ptr<Address> &getDeviceAddress() const;
 	const std::string &getDeviceName() const;
 
 private:
diff --git a/src/event-log/conference/conference-participant-event-p.h b/src/event-log/conference/conference-participant-event-p.h
index a954140b793b2fb7668f2182e708284f24d197b1..5be2ae418e218d579422c1513ca55a7b2182593e 100644
--- a/src/event-log/conference/conference-participant-event-p.h
+++ b/src/event-log/conference/conference-participant-event-p.h
@@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE
 
 class ConferenceParticipantEventPrivate : public ConferenceNotifiedEventPrivate {
 private:
-	IdentityAddress participantAddress;
+	std::shared_ptr<Address> participantAddress;
 
 	L_DECLARE_PUBLIC(ConferenceParticipantEvent);
 };
diff --git a/src/event-log/conference/conference-participant-event.cpp b/src/event-log/conference/conference-participant-event.cpp
index 1c1fa67e922587afa41f2e40bcd5bbc88f249819..9517d84703572641f3890c3e64032a65723e35a4 100644
--- a/src/event-log/conference/conference-participant-event.cpp
+++ b/src/event-log/conference/conference-participant-event.cpp
@@ -32,7 +32,7 @@ LINPHONE_BEGIN_NAMESPACE
 ConferenceParticipantEvent::ConferenceParticipantEvent(Type type,
                                                        time_t creationTime,
                                                        const ConferenceId &conferenceId,
-                                                       const IdentityAddress &participantAddress)
+                                                       const std::shared_ptr<Address> &participantAddress)
     : ConferenceNotifiedEvent(*new ConferenceParticipantEventPrivate, type, creationTime, conferenceId) {
 	L_D();
 	L_ASSERT(type == Type::ConferenceParticipantAdded || type == Type::ConferenceParticipantRemoved ||
@@ -44,13 +44,13 @@ ConferenceParticipantEvent::ConferenceParticipantEvent(ConferenceParticipantEven
                                                        Type type,
                                                        time_t creationTime,
                                                        const ConferenceId &conferenceId,
-                                                       const IdentityAddress &participantAddress)
+                                                       const std::shared_ptr<Address> &participantAddress)
     : ConferenceNotifiedEvent(p, type, creationTime, conferenceId) {
 	L_D();
 	d->participantAddress = participantAddress;
 }
 
-const IdentityAddress &ConferenceParticipantEvent::getParticipantAddress() const {
+const std::shared_ptr<Address> &ConferenceParticipantEvent::getParticipantAddress() const {
 	L_D();
 	return d->participantAddress;
 }
diff --git a/src/event-log/conference/conference-participant-event.h b/src/event-log/conference/conference-participant-event.h
index f1f4146a28fdf5a1871ea49a8f137f6bdbe4f6c8..7c7c9dc76729496a9fca172d5edaeeeef80e5ab1 100644
--- a/src/event-log/conference/conference-participant-event.h
+++ b/src/event-log/conference/conference-participant-event.h
@@ -28,7 +28,7 @@
 LINPHONE_BEGIN_NAMESPACE
 
 class ConferenceParticipantEventPrivate;
-class IdentityAddress;
+class Address;
 class Conference;
 class Participant;
 
@@ -40,16 +40,16 @@ public:
 	ConferenceParticipantEvent(Type type,
 	                           time_t creationTime,
 	                           const ConferenceId &conferenceId,
-	                           const IdentityAddress &participantAddress);
+	                           const std::shared_ptr<Address> &participantAddress);
 
-	const IdentityAddress &getParticipantAddress() const;
+	const std::shared_ptr<Address> &getParticipantAddress() const;
 
 protected:
 	ConferenceParticipantEvent(ConferenceParticipantEventPrivate &p,
 	                           Type type,
 	                           time_t creationTime,
 	                           const ConferenceId &conferenceId,
-	                           const IdentityAddress &participantAddress);
+	                           const std::shared_ptr<Address> &participantAddress);
 
 private:
 	L_DECLARE_PRIVATE(ConferenceParticipantEvent);
diff --git a/src/event-log/conference/conference-security-event.cpp b/src/event-log/conference/conference-security-event.cpp
index 7ce94d1b8ff65557a9dd7cded176524223bd1707..de8e89464d4302e71a703030842864b37e848171 100644
--- a/src/event-log/conference/conference-security-event.cpp
+++ b/src/event-log/conference/conference-security-event.cpp
@@ -32,7 +32,7 @@ LINPHONE_BEGIN_NAMESPACE
 class ConferenceSecurityEventPrivate : public ConferenceEventPrivate {
 public:
 	ConferenceSecurityEvent::SecurityEventType securityEventType;
-	IdentityAddress faultyDevice;
+	std::shared_ptr<Address> faultyDevice;
 };
 
 // -----------------------------------------------------------------------------
@@ -40,7 +40,7 @@ public:
 ConferenceSecurityEvent::ConferenceSecurityEvent(time_t creationTime,
                                                  const ConferenceId &conferenceId,
                                                  SecurityEventType securityEventType,
-                                                 const IdentityAddress &faultyDevice)
+                                                 const std::shared_ptr<Address> &faultyDevice)
     : ConferenceEvent(*new ConferenceSecurityEventPrivate, Type::ConferenceSecurityEvent, creationTime, conferenceId) {
 	L_D();
 	d->securityEventType = securityEventType;
@@ -60,7 +60,7 @@ ConferenceSecurityEvent::SecurityEventType ConferenceSecurityEvent::getSecurityE
 	return d->securityEventType;
 }
 
-const IdentityAddress &ConferenceSecurityEvent::getFaultyDeviceAddress() const {
+const std::shared_ptr<Address> &ConferenceSecurityEvent::getFaultyDeviceAddress() const {
 	L_D();
 	return d->faultyDevice;
 }
diff --git a/src/event-log/conference/conference-security-event.h b/src/event-log/conference/conference-security-event.h
index 82fb31eeb4fcc6d346a00ad358b48535bf8fa42f..af4e2b5595851ada5e105198223139a8d4517a5b 100644
--- a/src/event-log/conference/conference-security-event.h
+++ b/src/event-log/conference/conference-security-event.h
@@ -30,7 +30,7 @@
 
 LINPHONE_BEGIN_NAMESPACE
 
-class IdentityAddress;
+class Address;
 class ConferenceSecurityEventPrivate;
 
 class LINPHONE_PUBLIC ConferenceSecurityEvent : public ConferenceEvent {
@@ -56,12 +56,12 @@ public:
 	ConferenceSecurityEvent(time_t creationTime,
 	                        const ConferenceId &conferenceId,
 	                        SecurityEventType securityEventType,
-	                        const IdentityAddress &faultyDevice);
+	                        const std::shared_ptr<Address> &faultyDevice);
 
 	ConferenceSecurityEvent(time_t creationTime, const ConferenceId &conferenceId, SecurityEventType securityEventType);
 
 	SecurityEventType getSecurityEventType() const;
-	const IdentityAddress &getFaultyDeviceAddress() const;
+	const std::shared_ptr<Address> &getFaultyDeviceAddress() const;
 
 private:
 	L_DECLARE_PRIVATE(ConferenceSecurityEvent);
diff --git a/src/event/event-publish.cpp b/src/event/event-publish.cpp
index 868584a2a0143a90d61a39d5e6dd8588adc0ace2..d1ab56256fbc1da3cfcd026b60e53ad6ea253a39 100644
--- a/src/event/event-publish.cpp
+++ b/src/event/event-publish.cpp
@@ -66,23 +66,24 @@ EventPublish::EventPublish(const shared_ptr<Core> &core, LinphonePrivate::SalEve
 
 EventPublish::EventPublish(const shared_ptr<Core> &core,
                            const shared_ptr<Account> &account,
-                           const LinphoneAddress *resource,
+                           const std::shared_ptr<Address> resourceAddr,
                            const string &event,
                            int expires)
     : EventPublish(core, new SalPublishOp(core->getCCore()->sal.get()), event) {
-	if (!resource && account) resource = account->getAccountParams()->getIdentityAddress();
+	auto resource = resourceAddr;
+	if ((!resource || !resource->isValid()) && account) resource = account->getAccountParams()->getIdentityAddress();
 
 	setExpires(expires);
 	if (!account) {
 		auto coreAccount =
-		    Account::toCpp(linphone_core_lookup_known_account(core->getCCore(), resource))->getSharedFromThis();
+		    Account::toCpp(linphone_core_lookup_known_account(core->getCCore(), resource->toC()))->getSharedFromThis();
 		linphone_configure_op_with_account(
-		    core->getCCore(), mOp, resource, nullptr,
+		    core->getCCore(), mOp, resource->toC(), nullptr,
 		    !!linphone_config_get_int(core->getCCore()->config, "sip", "publish_msg_with_contact", 0),
 		    coreAccount->toC());
 	} else {
 		linphone_configure_op_with_account(
-		    core->getCCore(), mOp, resource, nullptr,
+		    core->getCCore(), mOp, resource->toC(), nullptr,
 		    !!linphone_config_get_int(core->getCCore()->config, "sip", "publish_msg_with_contact", 0), account->toC());
 	}
 
@@ -91,13 +92,13 @@ EventPublish::EventPublish(const shared_ptr<Core> &core,
 }
 
 EventPublish::EventPublish(const shared_ptr<Core> &core,
-                           const LinphoneAddress *resource,
+                           const std::shared_ptr<Address> resource,
                            const string &event,
                            int expires)
     : EventPublish(core, nullptr, resource, event, expires) {
 }
 
-EventPublish::EventPublish(const shared_ptr<Core> &core, const LinphoneAddress *resource, const string &event)
+EventPublish::EventPublish(const shared_ptr<Core> &core, const std::shared_ptr<Address> resource, const string &event)
     : EventPublish(core, resource, event, -1) {
 	setOneshot(true);
 	setUnrefWhenTerminated(true);
@@ -190,4 +191,4 @@ void EventPublish::terminate() {
 	setState(LinphonePublishTerminating);
 }
 
-LINPHONE_END_NAMESPACE
\ No newline at end of file
+LINPHONE_END_NAMESPACE
diff --git a/src/event/event-publish.h b/src/event/event-publish.h
index 30c28b73712dd1b62b97d4c71f4e433b40749599..ab113d9e9e52ced619ea176f125071e33a9c744a 100644
--- a/src/event/event-publish.h
+++ b/src/event/event-publish.h
@@ -33,14 +33,14 @@ public:
 	EventPublish(const std::shared_ptr<Core> &core, LinphonePrivate::SalEventOp *op, const std::string &name);
 	EventPublish(const std::shared_ptr<Core> &core,
 	             const std::shared_ptr<Account> &account,
-	             const LinphoneAddress *resource,
+	             const std::shared_ptr<Address> resource,
 	             const std::string &event,
 	             int expires);
 	EventPublish(const std::shared_ptr<Core> &core,
-	             const LinphoneAddress *resource,
+	             const std::shared_ptr<Address> resource,
 	             const std::string &event,
 	             int expires);
-	EventPublish(const std::shared_ptr<Core> &core, const LinphoneAddress *resource, const std::string &event);
+	EventPublish(const std::shared_ptr<Core> &core, const std::shared_ptr<Address> resource, const std::string &event);
 
 	std::string toString() const override;
 
@@ -68,4 +68,4 @@ private:
 
 LINPHONE_END_NAMESPACE
 
-#endif // ifndef _L_EVENT_PUBLISH_H_
\ No newline at end of file
+#endif // ifndef _L_EVENT_PUBLISH_H_
diff --git a/src/event/event-subscribe.cpp b/src/event/event-subscribe.cpp
index c0a91f32df35bcf585a398c1d03449c609f4a590..74e47692546b4ccacf5036422142c11688f3f69c 100644
--- a/src/event/event-subscribe.cpp
+++ b/src/event/event-subscribe.cpp
@@ -59,31 +59,33 @@ EventSubscribe::EventSubscribe(const shared_ptr<Core> &core,
 	mIsOutOfDialogOp = is_out_of_dialog;
 }
 
-EventSubscribe::EventSubscribe(const shared_ptr<Core> &core, const LinphoneAddress *resource, const string &event)
+EventSubscribe::EventSubscribe(const shared_ptr<Core> &core,
+                               const std::shared_ptr<Address> resource,
+                               const string &event)
     : EventSubscribe(core, LinphoneSubscriptionIncoming, event, -1) {
-	linphone_configure_op(core->getCCore(), mOp, resource, NULL, TRUE);
+	linphone_configure_op(core->getCCore(), mOp, resource->toC(), NULL, TRUE);
 	setState(LinphoneSubscriptionIncomingReceived);
 	mOp->setEvent(event);
 	setIsOutOfDialogOp(true);
 }
 
 EventSubscribe::EventSubscribe(const shared_ptr<Core> &core,
-                               const LinphoneAddress *resource,
+                               const std::shared_ptr<Address> resource,
                                const string &event,
                                int expires)
     : EventSubscribe(core, LinphoneSubscriptionOutgoing, event, expires) {
-	linphone_configure_op(core->getCCore(), mOp, resource, NULL, TRUE);
+	linphone_configure_op(core->getCCore(), mOp, resource->toC(), NULL, TRUE);
 	mOp->setManualRefresherMode(
 	    !linphone_config_get_int(core->getCCore()->config, "sip", "refresh_generic_subscribe", 1));
 }
 
 EventSubscribe::EventSubscribe(const shared_ptr<Core> &core,
-                               const LinphoneAddress *resource,
+                               const std::shared_ptr<Address> resource,
                                LinphoneProxyConfig *cfg,
                                const string &event,
                                int expires)
     : EventSubscribe(core, LinphoneSubscriptionOutgoing, event, expires) {
-	linphone_configure_op_with_proxy(core->getCCore(), mOp, resource, NULL, TRUE, cfg);
+	linphone_configure_op_with_proxy(core->getCCore(), mOp, resource->toC(), NULL, TRUE, cfg);
 	mOp->setManualRefresherMode(
 	    !linphone_config_get_int(core->getCCore()->config, "sip", "refresh_generic_subscribe", 1));
 }
@@ -217,16 +219,6 @@ void EventSubscribe::setIsOutOfDialogOp(bool isOutOfDialogOp) {
 	mIsOutOfDialogOp = isOutOfDialogOp;
 }
 
-const LinphoneAddress *EventSubscribe::getRemoteContact() const {
-	if (mRemoteContactAddress) linphone_address_unref(mRemoteContactAddress);
-
-	char *buf = sal_address_as_string(mOp->getRemoteContactAddress());
-	mRemoteContactAddress = linphone_address_new(buf);
-	ms_free(buf);
-
-	return mRemoteContactAddress;
-}
-
 void EventSubscribe::unpublish() {
 	if (mOp) {
 		auto op = dynamic_cast<SalPublishOp *>(mOp);
@@ -259,4 +251,4 @@ void EventSubscribe::terminate() {
 	}
 }
 
-LINPHONE_END_NAMESPACE
\ No newline at end of file
+LINPHONE_END_NAMESPACE
diff --git a/src/event/event-subscribe.h b/src/event/event-subscribe.h
index 6c018461cdba80ab7422e6cbfe3c7c3a4d155b6b..11155741a447d917e9fe0675c02670dd9e714de3 100644
--- a/src/event/event-subscribe.h
+++ b/src/event/event-subscribe.h
@@ -42,13 +42,15 @@ public:
 	               LinphoneSubscriptionDir dir,
 	               const std::string &name,
 	               bool_t is_out_of_dialog);
-	EventSubscribe(const std::shared_ptr<Core> &core, const LinphoneAddress *resource, const std::string &event);
 	EventSubscribe(const std::shared_ptr<Core> &core,
-	               const LinphoneAddress *resource,
+	               const std::shared_ptr<Address> resource,
+	               const std::string &event);
+	EventSubscribe(const std::shared_ptr<Core> &core,
+	               const std::shared_ptr<Address> resource,
 	               const std::string &event,
 	               int expires);
 	EventSubscribe(const std::shared_ptr<Core> &core,
-	               const LinphoneAddress *resource,
+	               const std::shared_ptr<Address> resource,
 	               LinphoneProxyConfig *cfg,
 	               const std::string &event,
 	               int expires);
@@ -72,8 +74,6 @@ public:
 	bool isOutOfDialogOp() const;
 	void setIsOutOfDialogOp(bool isOutOfDialogOp);
 
-	const LinphoneAddress *getRemoteContact() const;
-
 	void unpublish() override;
 
 	void terminate() override;
@@ -87,4 +87,4 @@ private:
 
 LINPHONE_END_NAMESPACE
 
-#endif // ifndef _L_EVENT_SUBSCRIBE_H_
\ No newline at end of file
+#endif // ifndef _L_EVENT_SUBSCRIBE_H_
diff --git a/src/event/event.cpp b/src/event/event.cpp
index 7e675e279be5775495a913b6141616303f69dae8..3168316672d0b2e7bad026e3be68351867ec59e0 100644
--- a/src/event/event.cpp
+++ b/src/event/event.cpp
@@ -52,9 +52,6 @@ Event::~Event() {
 	}
 
 	if (mSendCustomHeaders) sal_custom_header_free(mSendCustomHeaders);
-	if (mToAddress) linphone_address_unref(mToAddress);
-	if (mFromAddress) linphone_address_unref(mFromAddress);
-	if (mRemoteContactAddress) linphone_address_unref(mRemoteContactAddress);
 }
 
 LinphoneReason Event::getReason() const {
@@ -94,51 +91,47 @@ const string &Event::getName() const {
 	return mName;
 }
 
-const LinphoneAddress *Event::getFrom() const {
+const std::shared_ptr<Address> Event::getFrom() const {
 	return cacheFrom();
 }
 
-void Event::setFrom(const LinphoneAddress *fromAddress) {
-	if (mFromAddress) {
-		linphone_address_unref(mFromAddress);
-		mFromAddress = nullptr;
-	}
-	if (fromAddress) {
-		mFromAddress = linphone_address_clone(fromAddress);
-	}
+void Event::setFrom(const std::shared_ptr<Address> &fromAddress) {
+	mFromAddress = fromAddress->clone()->toSharedPtr();
 }
 
-const LinphoneAddress *Event::getTo() const {
+const std::shared_ptr<Address> Event::getTo() const {
 	return cacheTo();
 }
 
-void Event::setTo(const LinphoneAddress *toAddress) {
-	if (mToAddress) {
-		linphone_address_unref(mToAddress);
-		mToAddress = nullptr;
-	}
-	if (toAddress) {
-		mToAddress = linphone_address_clone(toAddress);
-	}
+void Event::setTo(const std::shared_ptr<Address> &toAddress) {
+	mToAddress = toAddress->clone()->toSharedPtr();
 }
 
-const LinphoneAddress *Event::getResource() const {
+const std::shared_ptr<Address> Event::getResource() const {
 	return cacheTo();
 }
 
-const LinphoneAddress *Event::cacheFrom() const {
-	if (mFromAddress) linphone_address_unref(mFromAddress);
-	char *buf = sal_address_as_string(mOp->getFromAddress());
-	mFromAddress = linphone_address_new(buf);
-	ms_free(buf);
+const std::shared_ptr<Address> Event::getRemoteContact() const {
+	if (!mRemoteContactAddress) {
+		mRemoteContactAddress = Address::create();
+	}
+	mRemoteContactAddress->setImpl(mOp->getRemoteContactAddress());
+	return mRemoteContactAddress;
+}
+
+const std::shared_ptr<Address> Event::cacheFrom() const {
+	if (!mFromAddress) {
+		mFromAddress = Address::create();
+	}
+	mFromAddress->setImpl(mOp->getFromAddress());
 	return mFromAddress;
 }
 
-const LinphoneAddress *Event::cacheTo() const {
-	if (mToAddress) linphone_address_unref(mToAddress);
-	char *buf = sal_address_as_string(mOp->getToAddress());
-	mToAddress = linphone_address_new(buf);
-	ms_free(buf);
+const std::shared_ptr<Address> Event::cacheTo() const {
+	if (!mToAddress) {
+		mToAddress = Address::create();
+	}
+	mToAddress->setImpl(mOp->getToAddress());
 	return mToAddress;
 }
 
@@ -178,4 +171,4 @@ void Event::setManualRefresherMode(bool manual) {
 	mOp->setManualRefresherMode(manual);
 }
 
-LINPHONE_END_NAMESPACE
\ No newline at end of file
+LINPHONE_END_NAMESPACE
diff --git a/src/event/event.h b/src/event/event.h
index 768f54895efdee5d45e3df71c24c047a576e48b5..6b525a0b2c0f908eb283ef71bae86c71b1973386 100644
--- a/src/event/event.h
+++ b/src/event/event.h
@@ -67,13 +67,15 @@ public:
 
 	const std::string &getName() const;
 
-	const LinphoneAddress *getFrom() const;
-	void setFrom(const LinphoneAddress *fromAddress);
+	const std::shared_ptr<Address> getFrom() const;
+	void setFrom(const std::shared_ptr<Address> &fromAddress);
 
-	const LinphoneAddress *getTo() const;
-	void setTo(const LinphoneAddress *toAddress);
+	const std::shared_ptr<Address> getTo() const;
+	void setTo(const std::shared_ptr<Address> &toAddress);
 
-	const LinphoneAddress *getResource() const;
+	const std::shared_ptr<Address> getRemoteContact() const;
+
+	const std::shared_ptr<Address> getResource() const;
 
 	LinphonePrivate::SalEventOp *getOp() const;
 	void setManualRefresherMode(bool manual);
@@ -91,12 +93,12 @@ public:
 	virtual void terminate() = 0;
 
 protected:
-	const LinphoneAddress *cacheFrom() const;
-	const LinphoneAddress *cacheTo() const;
+	const std::shared_ptr<Address> cacheFrom() const;
+	const std::shared_ptr<Address> cacheTo() const;
 
-	mutable LinphoneAddress *mFromAddress = nullptr;
-	mutable LinphoneAddress *mToAddress = nullptr;
-	mutable LinphoneAddress *mRemoteContactAddress = nullptr;
+	mutable std::shared_ptr<Address> mFromAddress = nullptr;
+	mutable std::shared_ptr<Address> mToAddress = nullptr;
+	mutable std::shared_ptr<Address> mRemoteContactAddress = nullptr;
 	LinphonePrivate::SalEventOp *mOp = nullptr;
 	SalCustomHeader *mSendCustomHeaders = nullptr;
 
@@ -113,4 +115,4 @@ private:
 
 LINPHONE_END_NAMESPACE
 
-#endif // ifndef _L_EVENT_H_
\ No newline at end of file
+#endif // ifndef _L_EVENT_H_
diff --git a/src/factory/factory.cpp b/src/factory/factory.cpp
index 739eaa0ffc8e047f9fc7a0450c11c63c37ac09fc..6add139efddd5786a76c8c36267e8b830bbc55d9 100644
--- a/src/factory/factory.cpp
+++ b/src/factory/factory.cpp
@@ -38,11 +38,11 @@
 #include <fstream>
 #include <sstream>
 
-#include "address/address.h"
 #include "bctoolbox/crypto.h"
 #include "bctoolbox/vfs_encrypted.hh"
 #include <bctoolbox/defs.h>
 
+#include "address/address.h"
 #include "chat/ics/ics.h"
 #include "conference/conference-info.h"
 #include "content/file-content.h"
diff --git a/src/nat/nat-policy.cpp b/src/nat/nat-policy.cpp
index ee26778f1ffb1e0a11aa30862adc260f7f7f1097..56a42cb7de2ee96aed7ffa14c068d3f6442a66de 100644
--- a/src/nat/nat-policy.cpp
+++ b/src/nat/nat-policy.cpp
@@ -19,6 +19,7 @@
  */
 
 #include "nat-policy.h"
+#include "core/core.h"
 
 #include <cstring>
 
diff --git a/src/push-notification/push-notification-config.cpp b/src/push-notification/push-notification-config.cpp
index b079f218bbbf89d087b108ea603b794ecee869d6..eac235ca126de28657d09453060b7efc91dec374 100644
--- a/src/push-notification/push-notification-config.cpp
+++ b/src/push-notification/push-notification-config.cpp
@@ -231,9 +231,9 @@ string PushNotificationConfig::asString(bool withRemoteSpecificParams) const {
 }
 
 void PushNotificationConfig::readPushParamsFromString(string const &serializedConfig) {
-	Address pushParamsWrapper("sip:dummy;" + serializedConfig);
+	std::shared_ptr<Address> pushParamsWrapper = Address::create("sip:dummy;" + serializedConfig);
 	for (auto &param : mPushParams) {
-		string paramValue = pushParamsWrapper.getUriParamValue(param.first);
+		string paramValue = pushParamsWrapper->getUriParamValue(param.first);
 		if (!paramValue.empty()) param.second = paramValue;
 	}
 }
diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp
index ab6b1957aec7f1f8a7191c03e7216d7bab7a207f..8ea4e01f6bba60ff9ec6ceda82e333bfe51e486a 100644
--- a/src/sal/call-op.cpp
+++ b/src/sal/call-op.cpp
@@ -22,14 +22,13 @@
 
 #include "bellesip_sal/sal_impl.h"
 #include "content/content-manager.h"
+#include "linphone/utils/utils.h"
 #include "offeranswer.h"
 #include "sal/call-op.h"
 
-#include <bctoolbox/defs.h>
+#include <belle-sip/defs.h>
 #include <belle-sip/provider.h>
 
-#include "linphone/utils/utils.h"
-
 using namespace std;
 
 LINPHONE_BEGIN_NAMESPACE
diff --git a/src/sal/offeranswer.cpp b/src/sal/offeranswer.cpp
index 948ae633fbad569e68b6e2e7a7788855e2fe31ec..f0f07363140c55cb5899b3e47cb2c39ee3eae0db 100644
--- a/src/sal/offeranswer.cpp
+++ b/src/sal/offeranswer.cpp
@@ -28,7 +28,6 @@
 #include "sal/sal_media_description.h"
 #include "sal/sal_stream_bundle.h"
 #include "sal/sal_stream_configuration.h"
-
 #include "utils/payload-type-handler.h"
 
 static PayloadType *opus_match(BCTBX_UNUSED(MSOfferAnswerContext *ctx),
diff --git a/src/sal/op.h b/src/sal/op.h
index 2e28700d0c636ae0b4c471a80356696ec4826b2b..a7e234f7d64eacef30778189e82caee9ab2635b4 100644
--- a/src/sal/op.h
+++ b/src/sal/op.h
@@ -91,7 +91,7 @@ public:
 		return mToAddress;
 	}
 
-	BorrowedMut<SalAddress> getRequestAddress() {
+	SalAddress *getRequestAddress() {
 		return mRequestAddress.borrow();
 	}
 
diff --git a/src/sal/sal.cpp b/src/sal/sal.cpp
index 81ba5018c4a7ff3c0c9227c84ab1842531afb81a..33ad810ccb357a6159445f0e8283109fa92cb33c 100644
--- a/src/sal/sal.cpp
+++ b/src/sal/sal.cpp
@@ -23,9 +23,10 @@
 #include "bctoolbox/crypto.hh"
 #include "bctoolbox/defs.h"
 #include "bctoolbox/utils.hh"
+
 #include "bellesip_sal/sal_impl.h"
-#include "private.h"
 
+#include "private.h"
 #include "sal/call-op.h"
 #include "sal/event-op.h"
 #include "sal/message-op.h"
diff --git a/src/sal/sal_stream_description.cpp b/src/sal/sal_stream_description.cpp
index 70323f7e95e837537da5bbaa6786513b029eca6c..93131320a9fc69e8d39ebcf6f68ae90d22a4ef39 100644
--- a/src/sal/sal_stream_description.cpp
+++ b/src/sal/sal_stream_description.cpp
@@ -22,8 +22,10 @@
 
 #include "bellesip_sal/sal_impl.h"
 #include "c-wrapper/internal/c-tools.h"
+#include "linphone/misc.h"
 #include "linphone/utils/utils.h"
 #include "sal/sal_stream_description.h"
+#include "sal_media_description.h"
 #include "utils/payload-type-handler.h"
 
 LINPHONE_BEGIN_NAMESPACE
diff --git a/src/search/magic-search.cpp b/src/search/magic-search.cpp
index 40482eb7b9ecd375c47bf4208c27972915e0a6af..2a6faf241ed90eb5791854ba5474f1ab597a168f 100644
--- a/src/search/magic-search.cpp
+++ b/src/search/magic-search.cpp
@@ -18,14 +18,11 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "magic-search-p.h"
-#include "search-async-data.h"
+#include <algorithm>
 
 #include "bctoolbox/defs.h"
 #include <bctoolbox/list.h>
 
-#include <algorithm>
-
 #include "../ldap/ldap.h"
 #include "c-wrapper/c-wrapper.h"
 #include "c-wrapper/internal/c-tools.h"
@@ -33,7 +30,9 @@
 #include "linphone/types.h"
 #include "linphone/utils/utils.h"
 #include "logger/logger.h"
+#include "magic-search-p.h"
 #include "private.h"
+#include "search-async-data.h"
 
 //#include "linphone/belle-sip/object.h"
 
diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp
index 6a5560caa3cf23ffbee05f75485106940f20b163..091c883fc2c3e226723a57d85df6e8eef7908d21 100644
--- a/src/utils/utils.cpp
+++ b/src/utils/utils.cpp
@@ -27,10 +27,9 @@
 #include <bctoolbox/charconv.h>
 #include <bctoolbox/port.h>
 
+#include "conference/conference-info.h"
 #include "linphone/utils/utils.h"
-
 #include "logger/logger.h"
-
 #include "private.h"
 
 #ifdef HAVE_ADVANCED_IM
@@ -341,20 +340,20 @@ std::string Utils::getSipFragAddress(const Content &content) {
 	std::string toErase = "From: ";
 	size_t contactPosition = id.find(toErase);
 	if (contactPosition != std::string::npos) id.erase(contactPosition, toErase.length());
-	IdentityAddress tmpIdentityAddress(id);
-	return tmpIdentityAddress.asString();
+	auto tmpIdentityAddress = Address::create(id);
+	return tmpIdentityAddress->toString();
 }
 
 #ifndef _MSC_VER
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
-std::string Utils::getResourceLists(const std::list<IdentityAddress> &addresses) {
+std::string Utils::getResourceLists(const std::list<std::shared_ptr<Address>> &addresses) {
 #ifdef HAVE_ADVANCED_IM
 	Xsd::ResourceLists::ResourceLists rl = Xsd::ResourceLists::ResourceLists();
 	Xsd::ResourceLists::ListType l = Xsd::ResourceLists::ListType();
 	for (const auto &addr : addresses) {
-		Xsd::ResourceLists::EntryType entry = Xsd::ResourceLists::EntryType(addr.asString());
+		Xsd::ResourceLists::EntryType entry = Xsd::ResourceLists::EntryType(addr->toString());
 		l.getEntry().push_back(entry);
 	}
 	rl.getList().push_back(l);
@@ -378,7 +377,7 @@ std::string Utils::getResourceLists(const std::list<IdentityAddress> &addresses)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif // _MSC_VER
-std::list<IdentityAddress> Utils::parseResourceLists(const Content &content) {
+std::list<std::shared_ptr<Address>> Utils::parseResourceLists(const Content &content) {
 #ifdef HAVE_ADVANCED_IM
 	if ((content.getContentType() == ContentType::ResourceLists) &&
 	    ((content.getContentDisposition().weakEqual(ContentDisposition::RecipientList)) ||
@@ -386,19 +385,19 @@ std::list<IdentityAddress> Utils::parseResourceLists(const Content &content) {
 		std::istringstream data(content.getBodyAsString());
 		std::unique_ptr<Xsd::ResourceLists::ResourceLists> rl(
 		    Xsd::ResourceLists::parseResourceLists(data, Xsd::XmlSchema::Flags::dont_validate));
-		std::list<IdentityAddress> addresses;
+		std::list<std::shared_ptr<Address>> addresses;
 		for (const auto &l : rl->getList()) {
 			for (const auto &entry : l.getEntry()) {
-				IdentityAddress addr(entry.getUri());
-				addresses.push_back(std::move(addr));
+				std::shared_ptr<Address> addr = Address::create(entry.getUri());
+				addresses.push_back(addr);
 			}
 		}
 		return addresses;
 	}
-	return std::list<IdentityAddress>();
+	return std::list<std::shared_ptr<Address>>();
 #else
 	lWarning() << "Advanced IM such as group chat is disabled!";
-	return std::list<IdentityAddress>();
+	return std::list<std::shared_ptr<Address>>();
 #endif
 }
 #ifndef _MSC_VER
@@ -413,8 +412,9 @@ std::shared_ptr<ConferenceInfo> Utils::createConferenceInfoFromOp(SalCallOp *op,
 
 	if (!sipfrag.isEmpty()) {
 		auto organizer = Utils::getSipFragAddress(sipfrag);
-		info->setOrganizer(IdentityAddress(organizer));
+		info->setOrganizer(Address::create(organizer));
 	}
+
 	if (!resourceList.isEmpty()) {
 		auto invitees = Utils::parseResourceLists(resourceList);
 		for (const auto &i : invitees) {
@@ -422,11 +422,9 @@ std::shared_ptr<ConferenceInfo> Utils::createConferenceInfoFromOp(SalCallOp *op,
 		}
 	}
 
-	char *remoteContactAddressStr =
-	    sal_address_as_string(remote ? op->getRemoteContactAddress() : op->getContactAddress());
-	const ConferenceAddress conferenceAddress(remoteContactAddressStr);
-	ms_free(remoteContactAddressStr);
-	if (conferenceAddress.isValid()) {
+	const std::shared_ptr<Address> conferenceAddress = Address::create();
+	conferenceAddress->setImpl(remote ? op->getRemoteContactAddress() : op->getContactAddress());
+	if (conferenceAddress && conferenceAddress->isValid()) {
 		info->setUri(conferenceAddress);
 	}
 
diff --git a/tester/accountmanager.c b/tester/accountmanager.c
index 8b16407e453918f5e34821e2dd5fd4b90766bcf1..d5f24cd81424bda2529e857e6df7ba2a191a8414 100644
--- a/tester/accountmanager.c
+++ b/tester/accountmanager.c
@@ -21,6 +21,7 @@
 #include <ctype.h>
 
 #include <bctoolbox/defs.h>
+
 #include <belle-sip/belle-sip.h>
 
 #include "liblinphone_tester.h"
diff --git a/tester/audio-quality-tester.cpp b/tester/audio-quality-tester.cpp
index 09d3a4a51274fc13bddb28b9b3b157f521f150d7..cb1d2b4efee83f7c73648c8a169596ba62f05197 100644
--- a/tester/audio-quality-tester.cpp
+++ b/tester/audio-quality-tester.cpp
@@ -30,12 +30,11 @@
 #include "content/content.h"
 #include "content/file-content.h"
 #include "core/core.h"
-
 // TODO: Remove me later.
-#include "private.h"
-
 #include "liblinphone_tester.h"
+#include "private.h"
 #include "tester_utils.h"
+
 // =============================================================================
 
 using namespace std;
diff --git a/tester/audio_bypass_tester.c b/tester/audio_bypass_tester.c
index e95447d8005cd901dbdc24ad029969178ea0a5e4..d50f3b146b01b935d01589267868d4fc26340632 100644
--- a/tester/audio_bypass_tester.c
+++ b/tester/audio_bypass_tester.c
@@ -18,9 +18,9 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "audio_bypass_wav_header.h" // This is a copy of mediastreamer2/src/audiofilters/wav_header.h
 #include <bctoolbox/defs.h>
 
+#include "audio_bypass_wav_header.h" // This is a copy of mediastreamer2/src/audiofilters/wav_header.h
 #include "liblinphone_tester.h"
 #include "tester_utils.h"
 
diff --git a/tester/audio_routes_tester.c b/tester/audio_routes_tester.c
index 4747670d88366850b7d57d1a1113011b91b736ce..e984c7353a358a98fd80dc4d5e4cd2cb8afa7968 100644
--- a/tester/audio_routes_tester.c
+++ b/tester/audio_routes_tester.c
@@ -18,14 +18,16 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "belle-sip/sipstack.h"
-#include "liblinphone_tester.h"
-
 #include <sys/stat.h>
 #include <sys/types.h>
 
 #include <bctoolbox/defs.h>
 
+#include "belle-sip/sipstack.h"
+
+#include "mediastreamer2/msutils.h"
+
+#include "liblinphone_tester.h"
 #include "linphone/core.h"
 #include "linphone/lpconfig.h"
 #include "mediastreamer2/msutils.h"
diff --git a/tester/call_secure_tester.cpp b/tester/call_secure_tester.cpp
index 599b68995bd343a86acd158cfe3bee042e612bdc..8fef5375d3d1bfdcb93e3096c4b5de5a1fac58f1 100644
--- a/tester/call_secure_tester.cpp
+++ b/tester/call_secure_tester.cpp
@@ -18,18 +18,22 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <bctoolbox/crypto.hh>
+#include <bctoolbox/defs.h>
+
 #include "belle-sip/sipstack.h"
+
+#include "mediastreamer2/msutils.h"
+
 #include "liblinphone_tester.h"
 #include "linphone/api/c-call-stats.h"
 #include "linphone/core.h"
 #include "linphone/lpconfig.h"
-#include "mediastreamer2/msutils.h"
 #include "private.h"
 #include "tester_utils.h"
-#include <bctoolbox/crypto.hh>
-#include <bctoolbox/defs.h>
-#include <sys/stat.h>
-#include <sys/types.h>
 
 #ifdef _WIN32
 #define unlink _unlink
diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c
index 08aeb073ca2e00afd16143be3e8aa377594cf500..2a1ea1378ac273f09554fd526fd8381502d71cd6 100644
--- a/tester/call_single_tester.c
+++ b/tester/call_single_tester.c
@@ -22,13 +22,14 @@
 #include <sys/types.h>
 
 #include "bctoolbox/defs.h"
-#include "liblinphone_tester.h"
 
-#include <bctoolbox/defs.h>
+#include "belle-sip/sipstack.h"
+
+#include "mediastreamer2/msutils.h"
 
+#include "liblinphone_tester.h"
 #include "linphone/core.h"
 #include "linphone/lpconfig.h"
-#include "mediastreamer2/msutils.h"
 #include "shared_tester_functions.h"
 #include "tester_utils.h"
 
@@ -676,7 +677,9 @@ static void call_outbound_with_multiple_proxy(void) {
 	if (!BC_ASSERT_PTR_NOT_NULL(lpc) || !BC_ASSERT_PTR_NOT_NULL(registered_lpc)) return;
 
 	// create new LPC that will successfully register
-	linphone_proxy_config_set_identity_address(registered_lpc, linphone_proxy_config_get_identity_address(lpc));
+	LinphoneAddress *identity_address = linphone_address_clone(linphone_proxy_config_get_identity_address(lpc));
+	linphone_proxy_config_set_identity_address(registered_lpc, identity_address);
+	linphone_address_unref(identity_address);
 	linphone_proxy_config_set_server_addr(registered_lpc, linphone_proxy_config_get_addr(lpc));
 	linphone_proxy_config_set_route(registered_lpc, linphone_proxy_config_get_route(lpc));
 	linphone_proxy_config_enable_register(registered_lpc, TRUE);
@@ -721,7 +724,7 @@ static void call_outbound_using_different_proxies(void) {
 		call_count++;
 		if (BC_ASSERT_PTR_NOT_NULL(caller)) {
 			wait_for_until(marie->lc, pauline->lc, NULL, 5, 500);
-			const LinphoneCallParams *callerParameters = linphone_call_get_current_params(caller);
+			const LinphoneCallParams *callerParameters = linphone_call_get_params(caller);
 			if (BC_ASSERT_PTR_NOT_NULL(callerParameters)) {
 				const LinphoneProxyConfig *callerProxyConfig = linphone_call_params_get_proxy_config(callerParameters);
 				if (BC_ASSERT_PTR_NOT_NULL(callerProxyConfig)) {
@@ -2658,7 +2661,6 @@ static void call_callee_with_custom_header_or_sdp_cb(BCTBX_UNUSED(LinphoneCore *
                                                      LinphoneCall *call,
                                                      LinphoneCallState cstate,
                                                      BCTBX_UNUSED(const char *message)) {
-
 	const char *value;
 	if (cstate == LinphoneCallOutgoingInit) {
 		LinphoneCallParams *params = linphone_call_params_copy(linphone_call_get_params(call));
diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp
index cf5c2e2acb076f8ab289812c1db0c61bdbe48425..1feccef189ed4b0c4f141511c3d0e7000ccb0311 100644
--- a/tester/conference-event-tester.cpp
+++ b/tester/conference-event-tester.cpp
@@ -25,7 +25,7 @@
 
 #include "c-wrapper/c-wrapper.h"
 
-#include "address/identity-address.h"
+#include "address/address.h"
 #include "call/call.h"
 #include "conference/conference-listener.h"
 #include "conference/handlers/local-conference-event-handler.h"
@@ -746,14 +746,14 @@ L_ENABLE_ATTR_ACCESS(LocalConference, shared_ptr<LocalConferenceEventHandler>, e
 
 class ConferenceEventTester : public RemoteConference {
 public:
-	ConferenceEventTester(const shared_ptr<Core> &core, const Address &confAddr);
+	ConferenceEventTester(const shared_ptr<Core> &core, const std::shared_ptr<Address> &confAddr);
 	~ConferenceEventTester();
 
 private:
-	void onConferenceCreated(const ConferenceAddress &addr) override;
+	void onConferenceCreated(const std::shared_ptr<Address> &addr) override;
 	void onConferenceKeywordsChanged(const vector<string> &keywords) override;
-	void onConferenceTerminated(const IdentityAddress &addr) override;
-	void onFirstNotifyReceived(const IdentityAddress &addr) override;
+	void onConferenceTerminated(const std::shared_ptr<Address> &addr) override;
+	void onFirstNotifyReceived(const std::shared_ptr<Address> &addr) override;
 	void onParticipantAdded(const shared_ptr<ConferenceParticipantEvent> &event,
 	                        const std::shared_ptr<Participant> &participant) override;
 	void onParticipantRemoved(const shared_ptr<ConferenceParticipantEvent> &event,
@@ -775,7 +775,7 @@ public:
 	bool oneToOne = false;
 };
 
-ConferenceEventTester::ConferenceEventTester(const shared_ptr<Core> &core, const Address &confAddr)
+ConferenceEventTester::ConferenceEventTester(const shared_ptr<Core> &core, const std::shared_ptr<Address> &confAddr)
     : RemoteConference(core, confAddr, nullptr, ConferenceParams::create(core->getCCore())) {
 	handler = new RemoteConferenceEventHandler(this, this);
 }
@@ -784,7 +784,7 @@ ConferenceEventTester::~ConferenceEventTester() {
 	delete handler;
 }
 
-void ConferenceEventTester::onConferenceCreated(BCTBX_UNUSED(const ConferenceAddress &address)) {
+void ConferenceEventTester::onConferenceCreated(BCTBX_UNUSED(const std::shared_ptr<Address> &address)) {
 }
 
 void ConferenceEventTester::onConferenceKeywordsChanged(const vector<string> &keywords) {
@@ -793,30 +793,30 @@ void ConferenceEventTester::onConferenceKeywordsChanged(const vector<string> &ke
 	}
 }
 
-void ConferenceEventTester::onConferenceTerminated(BCTBX_UNUSED(const IdentityAddress &addr)) {
+void ConferenceEventTester::onConferenceTerminated(BCTBX_UNUSED(const std::shared_ptr<Address> &addr)) {
 }
 
-void ConferenceEventTester::onFirstNotifyReceived(BCTBX_UNUSED(const IdentityAddress &addr)) {
+void ConferenceEventTester::onFirstNotifyReceived(BCTBX_UNUSED(const std::shared_ptr<Address> &addr)) {
 }
 
 void ConferenceEventTester::onParticipantAdded(const shared_ptr<ConferenceParticipantEvent> &event,
                                                BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	participants.insert({addr.asString(), false});
-	participantDevices.insert({addr.asString(), 0});
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	participants.insert({addr->toString(), false});
+	participantDevices.insert({addr->toString(), 0});
 }
 
 void ConferenceEventTester::onParticipantRemoved(const shared_ptr<ConferenceParticipantEvent> &event,
                                                  BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	participants.erase(addr.asString());
-	participantDevices.erase(addr.asString());
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	participants.erase(addr->toString());
+	participantDevices.erase(addr->toString());
 }
 
 void ConferenceEventTester::onParticipantSetAdmin(const shared_ptr<ConferenceParticipantEvent> &event,
                                                   BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	auto it = participants.find(addr.asString());
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	auto it = participants.find(addr->toString());
 	if (it != participants.end()) it->second = (event->getType() == EventLog::Type::ConferenceParticipantSetAdmin);
 }
 
@@ -826,22 +826,22 @@ void ConferenceEventTester::onSubjectChanged(const shared_ptr<ConferenceSubjectE
 
 void ConferenceEventTester::onParticipantDeviceAdded(const shared_ptr<ConferenceParticipantDeviceEvent> &event,
                                                      BCTBX_UNUSED(const std::shared_ptr<ParticipantDevice> &device)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	auto it = participantDevices.find(addr.asString());
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	auto it = participantDevices.find(addr->toString());
 	if (it != participantDevices.end()) it->second++;
 }
 
 void ConferenceEventTester::onParticipantDeviceRemoved(const shared_ptr<ConferenceParticipantDeviceEvent> &event,
                                                        BCTBX_UNUSED(const std::shared_ptr<ParticipantDevice> &device)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	auto it = participantDevices.find(addr.asString());
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	auto it = participantDevices.find(addr->toString());
 	if (it != participantDevices.end() && it->second > 0) it->second--;
 }
 
 class LocalConferenceTester : public LocalConference {
 public:
 	LocalConferenceTester(const std::shared_ptr<Core> &core,
-	                      const IdentityAddress &myAddress,
+	                      const std::shared_ptr<Address> &myAddress,
 	                      CallSessionListener *listener)
 	    : LocalConference(core, myAddress, listener, ConferenceParams::create(core->getCCore())) {
 	}
@@ -852,7 +852,7 @@ public:
 
 	// Addressing compilation error -Werror=overloaded-virtual
 	using LinphonePrivate::Conference::addParticipant;
-	bool addParticipant(const IdentityAddress &addr) override {
+	bool addParticipant(const std::shared_ptr<Address> &addr) override {
 		bool status = LocalConference::addParticipant(addr);
 		std::shared_ptr<Participant> p = findParticipant(addr);
 		p->addDevice(addr);
@@ -908,26 +908,26 @@ public:
 void ConferenceListenerInterfaceTester::onParticipantAdded(
     const shared_ptr<ConferenceParticipantEvent> &event,
     BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	participants.insert({addr.asString(), false});
-	participantDevices.insert({addr.asString(), 0});
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	participants.insert({addr->toString(), false});
+	participantDevices.insert({addr->toString(), 0});
 	lastNotify++;
 }
 
 void ConferenceListenerInterfaceTester::onParticipantRemoved(
     const shared_ptr<ConferenceParticipantEvent> &event,
     BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	participants.erase(addr.asString());
-	participantDevices.erase(addr.asString());
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	participants.erase(addr->toString());
+	participantDevices.erase(addr->toString());
 	lastNotify++;
 }
 
 void ConferenceListenerInterfaceTester::onParticipantSetAdmin(
     const shared_ptr<ConferenceParticipantEvent> &event,
     BCTBX_UNUSED(const std::shared_ptr<Participant> &participant)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	auto it = participants.find(addr.asString());
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	auto it = participants.find(addr->toString());
 	if (it != participants.end()) it->second = (event->getType() == EventLog::Type::ConferenceParticipantSetAdmin);
 	lastNotify++;
 }
@@ -940,8 +940,8 @@ void ConferenceListenerInterfaceTester::onSubjectChanged(const shared_ptr<Confer
 void ConferenceListenerInterfaceTester::onParticipantDeviceAdded(
     const shared_ptr<ConferenceParticipantDeviceEvent> &event,
     BCTBX_UNUSED(const std::shared_ptr<ParticipantDevice> &device)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	auto it = participantDevices.find(addr.asString());
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	auto it = participantDevices.find(addr->toString());
 	if (it != participantDevices.end()) it->second++;
 	lastNotify++;
 }
@@ -949,13 +949,14 @@ void ConferenceListenerInterfaceTester::onParticipantDeviceAdded(
 void ConferenceListenerInterfaceTester::onParticipantDeviceRemoved(
     const shared_ptr<ConferenceParticipantDeviceEvent> &event,
     BCTBX_UNUSED(const std::shared_ptr<ParticipantDevice> &device)) {
-	const IdentityAddress addr = event->getParticipantAddress();
-	auto it = participantDevices.find(addr.asString());
+	const std::shared_ptr<Address> addr = event->getParticipantAddress();
+	auto it = participantDevices.find(addr->toString());
 	if (it != participantDevices.end() && it->second > 0) it->second--;
 	lastNotify++;
 }
 
-static void setParticipantAsAdmin(shared_ptr<LocalConferenceTester> localConf, Address addr, bool isAdmin) {
+static void
+setParticipantAsAdmin(shared_ptr<LocalConferenceTester> localConf, std::shared_ptr<Address> addr, bool isAdmin) {
 	shared_ptr<Participant> p = localConf->findParticipant(addr);
 	p->setAdmin(isAdmin);
 	localConf->notifyParticipantSetAdmin(time(nullptr), false, p, isAdmin);
@@ -964,9 +965,7 @@ static void setParticipantAsAdmin(shared_ptr<LocalConferenceTester> localConf, A
 void first_notify_parsing() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri);
-	char *confAddressStr = linphone_address_as_string(confAddress);
-	Address addr(confAddressStr);
-	bctbx_free(confAddressStr);
+	std::shared_ptr<Address> addr = Address::toCpp(confAddress)->getSharedFromThis();
 	linphone_address_unref(confAddress);
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri);
@@ -974,7 +973,7 @@ void first_notify_parsing() {
 	size_t size = strlen(first_notify) + strlen(confUri);
 	char *notify = new char[size];
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
 
 	snprintf(notify, size, first_notify, confUri);
 
@@ -1011,9 +1010,7 @@ void first_notify_parsing() {
 void first_notify_with_extensions_parsing() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri);
-	char *confAddressStr = linphone_address_as_string(confAddress);
-	Address addr(confAddressStr);
-	bctbx_free(confAddressStr);
+	std::shared_ptr<Address> addr = Address::toCpp(confAddress)->getSharedFromThis();
 	linphone_address_unref(confAddress);
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri);
@@ -1021,7 +1018,7 @@ void first_notify_with_extensions_parsing() {
 	size_t size = strlen(first_notify) + strlen(confUri);
 	char *notify = new char[size];
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
 
 	snprintf(notify, size, first_notify, confUri);
 
@@ -1058,9 +1055,7 @@ void first_notify_with_extensions_parsing() {
 void first_notify_parsing_wrong_conf() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, "sips:conf322@example.com");
-	char *confAddressStr = linphone_address_as_string(confAddress);
-	Address addr(confAddressStr);
-	bctbx_free(confAddressStr);
+	std::shared_ptr<Address> addr = Address::toCpp(confAddress)->getSharedFromThis();
 	linphone_address_unref(confAddress);
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri);
@@ -1068,7 +1063,7 @@ void first_notify_parsing_wrong_conf() {
 	size_t size = strlen(first_notify) + strlen(confUri);
 	char *notify = new char[size];
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
 	snprintf(notify, size, first_notify, confUri);
 
 	Content content;
@@ -1098,9 +1093,7 @@ void first_notify_parsing_wrong_conf() {
 void participant_added_parsing() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri);
-	char *confAddressStr = linphone_address_as_string(confAddress);
-	Address addr(confAddressStr);
-	bctbx_free(confAddressStr);
+	std::shared_ptr<Address> addr = Address::toCpp(confAddress)->getSharedFromThis();
 	linphone_address_unref(confAddress);
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri);
@@ -1111,7 +1104,7 @@ void participant_added_parsing() {
 	size_t size2 = strlen(participant_added_notify) + strlen(confUri);
 	char *notify_added = new char[size2];
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
 	snprintf(notify, size, first_notify, confUri);
 
 	Content content;
@@ -1161,9 +1154,7 @@ void participant_not_added_parsing() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	setup_mgr_for_conference(marie, NULL);
 	LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri);
-	char *confAddressStr = linphone_address_as_string(confAddress);
-	Address addr(confAddressStr);
-	bctbx_free(confAddressStr);
+	std::shared_ptr<Address> addr = Address::toCpp(confAddress)->getSharedFromThis();
 	linphone_address_unref(confAddress);
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri);
@@ -1178,9 +1169,9 @@ void participant_not_added_parsing() {
 	size_t size4 = strlen(participant_device_not_added_notify) + strlen(confUri) + sizeof(int);
 	char *notify_device_not_added = new char[size4];
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getLocalAddress()) =
-	    ConferenceAddress(linphone_core_get_identity(marie->lc));
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId())
+	    .setLocalAddress(Address::create(linphone_core_get_identity(marie->lc)));
 	snprintf(notify, size, first_notify, confUri);
 
 	Content content;
@@ -1263,9 +1254,7 @@ void participant_not_added_parsing() {
 void participant_deleted_parsing() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri);
-	char *confAddressStr = linphone_address_as_string(confAddress);
-	Address addr(confAddressStr);
-	bctbx_free(confAddressStr);
+	std::shared_ptr<Address> addr = Address::toCpp(confAddress)->getSharedFromThis();
 	linphone_address_unref(confAddress);
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri);
@@ -1275,7 +1264,7 @@ void participant_deleted_parsing() {
 	size_t size2 = strlen(participant_deleted_notify) + strlen(confUri);
 	char *notify_deleted = new char[size2];
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
 	snprintf(notify, size, first_notify, confUri);
 
 	Content content;
@@ -1320,9 +1309,7 @@ void participant_deleted_parsing() {
 void participant_admined_parsing() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri);
-	char *confAddressStr = linphone_address_as_string(confAddress);
-	Address addr(confAddressStr);
-	bctbx_free(confAddressStr);
+	std::shared_ptr<Address> addr = Address::toCpp(confAddress)->getSharedFromThis();
 	linphone_address_unref(confAddress);
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri);
@@ -1332,7 +1319,7 @@ void participant_admined_parsing() {
 	size_t size2 = strlen(participant_admined_notify) + strlen(confUri);
 	char *notify_admined = new char[size2];
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
 	snprintf(notify, size, first_notify, confUri);
 
 	Content content;
@@ -1376,9 +1363,7 @@ void participant_admined_parsing() {
 void participant_unadmined_parsing() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri);
-	char *confAddressStr = linphone_address_as_string(confAddress);
-	Address addr(confAddressStr);
-	bctbx_free(confAddressStr);
+	std::shared_ptr<Address> addr = Address::toCpp(confAddress)->getSharedFromThis();
 	linphone_address_unref(confAddress);
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri);
@@ -1388,7 +1373,7 @@ void participant_unadmined_parsing() {
 	size_t size2 = strlen(participant_unadmined_notify) + strlen(confUri);
 	char *notify_unadmined = new char[size2];
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
 	snprintf(notify, size, first_notify, confUri);
 
 	Content content;
@@ -1433,9 +1418,7 @@ void send_first_notify() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneCoreManager *pauline =
 	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	shared_ptr<LocalConference> localConf =
 	    make_shared<LocalConference>(pauline->lc->cppPtr, addr, nullptr, ConferenceParams::create(pauline->lc));
@@ -1443,14 +1426,10 @@ void send_first_notify() {
 	    std::make_shared<ConferenceListenerInterfaceTester>();
 	localConf->addListener(confListener);
 	LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri);
-	char *bobAddrStr = linphone_address_as_string(cBobAddr);
-	Address bobAddr(bobAddrStr);
-	bctbx_free(bobAddrStr);
+	std::shared_ptr<Address> bobAddr = Address::toCpp(cBobAddr)->getSharedFromThis();
 	linphone_address_unref(cBobAddr);
 	LinphoneAddress *cAliceAddr = linphone_core_interpret_url(marie->lc, aliceUri);
-	char *aliceAddrStr = linphone_address_as_string(cAliceAddr);
-	Address aliceAddr(aliceAddrStr);
-	bctbx_free(aliceAddrStr);
+	std::shared_ptr<Address> aliceAddr = Address::toCpp(cAliceAddr)->getSharedFromThis();
 	linphone_address_unref(cAliceAddr);
 
 	localConf->addParticipant(bobAddr);
@@ -1460,19 +1439,19 @@ void send_first_notify() {
 	alice->setAdmin(true);
 
 	LocalConferenceEventHandler *localHandler = (L_ATTR_GET(localConf.get(), eventHandler)).get();
-	localConf->setConferenceAddress(ConferenceAddress(addr));
+	localConf->setConferenceAddress(addr);
 	Content content = localHandler->createNotifyFullState(NULL);
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
 
 	tester->handler->notifyReceived(content);
 
 	BC_ASSERT_STRING_EQUAL(tester->confSubject.c_str(), "A random test subject");
 	BC_ASSERT_EQUAL((int)tester->participants.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(tester->participants.find(bobAddr.asString()) != tester->participants.end());
-	BC_ASSERT_TRUE(tester->participants.find(aliceAddr.asString()) != tester->participants.end());
-	BC_ASSERT_TRUE(!tester->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(tester->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(tester->participants.find(bobAddr->toString()) != tester->participants.end());
+	BC_ASSERT_TRUE(tester->participants.find(aliceAddr->toString()) != tester->participants.end());
+	BC_ASSERT_TRUE(!tester->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(tester->participants.find(aliceAddr->toString())->second);
 
 	tester = nullptr;
 	localConf = nullptr;
@@ -1485,41 +1464,33 @@ void send_added_notify_through_address() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneCoreManager *pauline =
 	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	shared_ptr<LocalConferenceTester> localConf =
 	    make_shared<LocalConferenceTester>(pauline->lc->cppPtr, addr, nullptr);
 	std::shared_ptr<ConferenceListenerInterfaceTester> confListener =
 	    std::make_shared<ConferenceListenerInterfaceTester>();
 	localConf->addListener(confListener);
 	LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri);
-	char *bobAddrStr = linphone_address_as_string(cBobAddr);
-	Address bobAddr(bobAddrStr);
-	bctbx_free(bobAddrStr);
+	std::shared_ptr<Address> bobAddr = Address::toCpp(cBobAddr)->getSharedFromThis();
 	linphone_address_unref(cBobAddr);
 	LinphoneAddress *cAliceAddr = linphone_core_interpret_url(marie->lc, aliceUri);
-	char *aliceAddrStr = linphone_address_as_string(cAliceAddr);
-	Address aliceAddr(aliceAddrStr);
-	bctbx_free(aliceAddrStr);
+	std::shared_ptr<Address> aliceAddr = Address::toCpp(cAliceAddr)->getSharedFromThis();
 	linphone_address_unref(cAliceAddr);
 	LinphoneAddress *cFrankAddr = linphone_core_interpret_url(marie->lc, frankUri);
-	char *frankAddrStr = linphone_address_as_string(cFrankAddr);
-	Address frankAddr(frankAddrStr);
-	bctbx_free(frankAddrStr);
+	std::shared_ptr<Address> frankAddr = Address::toCpp(cFrankAddr)->getSharedFromThis();
 	linphone_address_unref(cFrankAddr);
 
 	localConf->addParticipant(bobAddr);
 	localConf->addParticipant(aliceAddr);
 	setParticipantAsAdmin(localConf, aliceAddr, true);
-	localConf->setConferenceAddress(ConferenceAddress(addr));
+	localConf->setConferenceAddress(addr);
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 2, int, "%d");
 	BC_ASSERT_EQUAL((int)confListener->participantDevices.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
 
 	unsigned int lastNotifyCount = confListener->lastNotify;
 
@@ -1527,13 +1498,13 @@ void send_added_notify_through_address() {
 
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 3, int, "%d");
 	BC_ASSERT_EQUAL((int)confListener->participantDevices.size(), 3, int, "%d");
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(frankAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(frankAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
-	BC_ASSERT_TRUE(!confListener->participants.find(frankAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(frankAddr->toString())->second);
 
 	BC_ASSERT_EQUAL(localConf->getLastNotify(), (lastNotifyCount + 1), int, "%d");
 
@@ -1609,7 +1580,8 @@ remove_participant_from_conference_through_call(bctbx_list_t **removed_mgrs,
 
 	if (participantCall) {
 		const LinphoneAddress *cParticipantAddress = linphone_call_get_to_address(participantCall);
-		std::string participantUri = L_GET_CPP_PTR_FROM_C_OBJECT(cParticipantAddress)->asStringUriOnly();
+		std::string participantUri =
+		    Address::toCpp(const_cast<LinphoneAddress *>(cParticipantAddress))->asStringUriOnly();
 		BC_ASSERT_TRUE(confListener->participants.find(participantUri) == confListener->participants.end());
 	}
 
@@ -1827,7 +1799,8 @@ add_participant_to_conference_through_call(bctbx_list_t **mgrs,
 	if (participantCall) {
 		const LinphoneAddress *cParticipantAddress = linphone_call_get_to_address(participantCall);
 
-		std::string participantUri = L_GET_CPP_PTR_FROM_C_OBJECT(cParticipantAddress)->asStringUriOnly();
+		std::string participantUri =
+		    Address::toCpp(const_cast<LinphoneAddress *>(cParticipantAddress))->asStringUriOnly();
 
 		BC_ASSERT_TRUE(confListener->participants.find(participantUri) != confListener->participants.end());
 
@@ -1874,9 +1847,7 @@ void send_added_notify_through_call() {
 	bctbx_list_t *mgrs = NULL;
 	mgrs = bctbx_list_append(mgrs, pauline);
 
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	stats initialPaulineStats = pauline->stat;
 	{
 		shared_ptr<MediaConference::LocalConference> localConf = std::shared_ptr<MediaConference::LocalConference>(
@@ -1947,9 +1918,7 @@ void send_removed_notify_through_call() {
 
 	bctbx_list_t *removed_mgrs = NULL;
 
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	stats initialPaulineStats = pauline->stat;
 
 	{
@@ -2036,37 +2005,31 @@ void send_removed_notify() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneCoreManager *pauline =
 	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	shared_ptr<LocalConferenceTester> localConf =
 	    make_shared<LocalConferenceTester>(pauline->lc->cppPtr, addr, nullptr);
 	std::shared_ptr<ConferenceListenerInterfaceTester> confListener =
 	    std::make_shared<ConferenceListenerInterfaceTester>();
 	localConf->addListener(confListener);
 	LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri);
-	char *bobAddrStr = linphone_address_as_string(cBobAddr);
-	Address bobAddr(bobAddrStr);
-	bctbx_free(bobAddrStr);
+	std::shared_ptr<Address> bobAddr = Address::toCpp(cBobAddr)->getSharedFromThis();
 	linphone_address_unref(cBobAddr);
 	LinphoneAddress *cAliceAddr = linphone_core_interpret_url(marie->lc, aliceUri);
-	char *aliceAddrStr = linphone_address_as_string(cAliceAddr);
-	Address aliceAddr(aliceAddrStr);
-	bctbx_free(aliceAddrStr);
+	std::shared_ptr<Address> aliceAddr = Address::toCpp(cAliceAddr)->getSharedFromThis();
 	linphone_address_unref(cAliceAddr);
 
 	localConf->addParticipant(bobAddr);
 	localConf->addParticipant(aliceAddr);
 	setParticipantAsAdmin(localConf, aliceAddr, true);
-	localConf->setConferenceAddress(ConferenceAddress(addr));
+	localConf->setConferenceAddress(addr);
 
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 2, int, "%d");
 	BC_ASSERT_EQUAL((int)confListener->participantDevices.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
 
 	unsigned int lastNotifyCount = confListener->lastNotify;
 
@@ -2074,10 +2037,10 @@ void send_removed_notify() {
 
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 1, int, "%d");
 	BC_ASSERT_EQUAL((int)confListener->participantDevices.size(), 1, int, "%d");
-	BC_ASSERT_FALSE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_FALSE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
 	BC_ASSERT_EQUAL(localConf->getLastNotify(), (lastNotifyCount + 1), int, "%d");
 
 	localConf = nullptr;
@@ -2089,47 +2052,41 @@ void send_admined_notify() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneCoreManager *pauline =
 	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	shared_ptr<LocalConferenceTester> localConf =
 	    make_shared<LocalConferenceTester>(pauline->lc->cppPtr, addr, nullptr);
 	std::shared_ptr<ConferenceListenerInterfaceTester> confListener =
 	    std::make_shared<ConferenceListenerInterfaceTester>();
 	localConf->addListener(confListener);
 	LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri);
-	char *bobAddrStr = linphone_address_as_string(cBobAddr);
-	Address bobAddr(bobAddrStr);
-	bctbx_free(bobAddrStr);
+	std::shared_ptr<Address> bobAddr = Address::toCpp(cBobAddr)->getSharedFromThis();
 	linphone_address_unref(cBobAddr);
 	LinphoneAddress *cAliceAddr = linphone_core_interpret_url(marie->lc, aliceUri);
-	char *aliceAddrStr = linphone_address_as_string(cAliceAddr);
-	Address aliceAddr(aliceAddrStr);
-	bctbx_free(aliceAddrStr);
+	std::shared_ptr<Address> aliceAddr = Address::toCpp(cAliceAddr)->getSharedFromThis();
 	linphone_address_unref(cAliceAddr);
 
 	localConf->addParticipant(bobAddr);
 	localConf->addParticipant(aliceAddr);
 	setParticipantAsAdmin(localConf, aliceAddr, true);
-	localConf->setConferenceAddress(ConferenceAddress(addr));
+	localConf->setConferenceAddress(addr);
 
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
 
 	unsigned int lastNotifyCount = confListener->lastNotify;
 
 	localConf->notifyParticipantSetAdmin(time(nullptr), false, localConf->findParticipant(bobAddr), true);
 
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString())->second);
 
 	BC_ASSERT_EQUAL(localConf->getLastNotify(), (lastNotifyCount + 1), int, "%d");
 
@@ -2142,46 +2099,40 @@ void send_unadmined_notify() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneCoreManager *pauline =
 	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	shared_ptr<LocalConferenceTester> localConf =
 	    make_shared<LocalConferenceTester>(pauline->lc->cppPtr, addr, nullptr);
 	std::shared_ptr<ConferenceListenerInterfaceTester> confListener =
 	    std::make_shared<ConferenceListenerInterfaceTester>();
 	localConf->addListener(confListener);
 	LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri);
-	char *bobAddrStr = linphone_address_as_string(cBobAddr);
-	Address bobAddr(bobAddrStr);
-	bctbx_free(bobAddrStr);
+	std::shared_ptr<Address> bobAddr = Address::toCpp(cBobAddr)->getSharedFromThis();
 	linphone_address_unref(cBobAddr);
 	LinphoneAddress *cAliceAddr = linphone_core_interpret_url(marie->lc, aliceUri);
-	char *aliceAddrStr = linphone_address_as_string(cAliceAddr);
-	Address aliceAddr(aliceAddrStr);
-	bctbx_free(aliceAddrStr);
+	std::shared_ptr<Address> aliceAddr = Address::toCpp(cAliceAddr)->getSharedFromThis();
 	linphone_address_unref(cAliceAddr);
 
 	localConf->addParticipant(bobAddr);
 	localConf->addParticipant(aliceAddr);
 	setParticipantAsAdmin(localConf, aliceAddr, true);
-	localConf->setConferenceAddress(ConferenceAddress(addr));
+	localConf->setConferenceAddress(addr);
 
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
 	unsigned int lastNotifyCount = confListener->lastNotify;
 
 	localConf->notifyParticipantSetAdmin(time(nullptr), false, localConf->findParticipant(aliceAddr), false);
 
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(aliceAddr.asString())->second);
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(aliceAddr->toString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
 	BC_ASSERT_EQUAL(localConf->getLastNotify(), (lastNotifyCount + 1), int, "%d");
 
 	localConf = nullptr;
@@ -2193,38 +2144,32 @@ void send_subject_changed_notify() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneCoreManager *pauline =
 	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	shared_ptr<LocalConferenceTester> localConf =
 	    make_shared<LocalConferenceTester>(pauline->lc->cppPtr, addr, nullptr);
 	std::shared_ptr<ConferenceListenerInterfaceTester> confListener =
 	    std::make_shared<ConferenceListenerInterfaceTester>();
 	localConf->addListener(confListener);
 	LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri);
-	char *bobAddrStr = linphone_address_as_string(cBobAddr);
-	Address bobAddr(bobAddrStr);
-	bctbx_free(bobAddrStr);
+	std::shared_ptr<Address> bobAddr = Address::toCpp(cBobAddr)->getSharedFromThis();
 	linphone_address_unref(cBobAddr);
 	LinphoneAddress *cAliceAddr = linphone_core_interpret_url(marie->lc, aliceUri);
-	char *aliceAddrStr = linphone_address_as_string(cAliceAddr);
-	Address aliceAddr(aliceAddrStr);
-	bctbx_free(aliceAddrStr);
+	std::shared_ptr<Address> aliceAddr = Address::toCpp(cAliceAddr)->getSharedFromThis();
 	linphone_address_unref(cAliceAddr);
 
 	localConf->addParticipant(bobAddr);
 	localConf->addParticipant(aliceAddr);
 	localConf->setSubject("A random test subject");
 	setParticipantAsAdmin(localConf, aliceAddr, true);
-	localConf->setConferenceAddress(ConferenceAddress(addr));
+	localConf->setConferenceAddress(addr);
 
 	BC_ASSERT_STRING_EQUAL(confListener->confSubject.c_str(), "A random test subject");
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
 
 	unsigned int lastNotifyCount = confListener->lastNotify;
 
@@ -2232,11 +2177,11 @@ void send_subject_changed_notify() {
 
 	BC_ASSERT_STRING_EQUAL(confListener->confSubject.c_str(), "Another random test subject...");
 	BC_ASSERT_EQUAL((int)confListener->participants.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participants.find(bobAddr.asString()) != confListener->participants.end());
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(bobAddr->toString()) != confListener->participants.end());
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString()) != confListener->participants.end());
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
 	BC_ASSERT_EQUAL(localConf->getLastNotify(), (lastNotifyCount + 1), int, "%d");
 
 	localConf = nullptr;
@@ -2252,51 +2197,48 @@ void send_device_added_notify() {
 	_linphone_core_add_callbacks(pauline->lc, cbs, TRUE);
 	linphone_core_cbs_unref(cbs);
 
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	shared_ptr<LocalConferenceTester> localConf =
 	    make_shared<LocalConferenceTester>(pauline->lc->cppPtr, addr, nullptr);
 	std::shared_ptr<ConferenceListenerInterfaceTester> confListener =
 	    std::make_shared<ConferenceListenerInterfaceTester>();
 	localConf->addListener(confListener);
 	LinphoneAddress *cBobAddr = linphone_core_interpret_url(pauline->lc, bobUri);
-	char *bobAddrStr = linphone_address_as_string(cBobAddr);
-	Address bobAddr(bobAddrStr);
-	bctbx_free(bobAddrStr);
+	std::shared_ptr<Address> bobAddr = Address::toCpp(cBobAddr)->getSharedFromThis();
 	linphone_address_unref(cBobAddr);
 	LinphoneAddress *cAliceAddr = linphone_core_interpret_url(pauline->lc, aliceUri);
-	char *aliceAddrStr = linphone_address_as_string(cAliceAddr);
-	Address aliceAddr(aliceAddrStr);
-	bctbx_free(aliceAddrStr);
+	std::shared_ptr<Address> aliceAddr = Address::toCpp(cAliceAddr)->getSharedFromThis();
 	linphone_address_unref(cAliceAddr);
 
 	localConf->addParticipant(bobAddr);
 	localConf->addParticipant(aliceAddr);
 	shared_ptr<Participant> alice = localConf->findParticipant(aliceAddr);
 	setParticipantAsAdmin(localConf, aliceAddr, true);
-	localConf->setConferenceAddress(ConferenceAddress(addr));
+	localConf->setConferenceAddress(addr);
 	BC_ASSERT_EQUAL((int)confListener->participantDevices.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr.asString()) != confListener->participantDevices.end());
-	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr.asString()) !=
+	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr->toString()) !=
 	               confListener->participantDevices.end());
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr.asString())->second, 0, int, "%d");
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr.asString())->second, 0, int, "%d");
+	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr->toString()) !=
+	               confListener->participantDevices.end());
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr->toString())->second, 0, int, "%d");
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr->toString())->second, 0, int, "%d");
+
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
 
 	localConf->notifyParticipantDeviceAdded(time(nullptr), false, alice, alice->findDevice(aliceAddr));
 
 	BC_ASSERT_EQUAL((int)confListener->participantDevices.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr.asString()) != confListener->participantDevices.end());
-	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr.asString()) !=
+	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr->toString()) !=
+	               confListener->participantDevices.end());
+	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr->toString()) !=
 	               confListener->participantDevices.end());
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr.asString())->second, 0, int, "%d");
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr.asString())->second, 1, int, "%d");
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr->toString())->second, 0, int, "%d");
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr->toString())->second, 1, int, "%d");
 	// Admin check
-	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr.asString())->second);
-	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr.asString())->second);
+	BC_ASSERT_TRUE(!confListener->participants.find(bobAddr->toString())->second);
+	BC_ASSERT_TRUE(confListener->participants.find(aliceAddr->toString())->second);
 
 	for (const auto &p : localConf->getParticipants()) {
 		for (const auto &d : p->getDevices()) {
@@ -2309,12 +2251,12 @@ void send_device_added_notify() {
 	auto op = new SalSubscribeOp(pauline->lc->sal.get());
 	SalAddress *toAddr = sal_address_new(linphone_core_get_identity(pauline->lc));
 	op->setToAddress(toAddr);
-	op->setFrom(bobAddr.asString().c_str());
-	op->overrideRemoteContact(bobAddr.asString().c_str());
+	op->setFrom(bobAddr->toString().c_str());
+	op->overrideRemoteContact(bobAddr->toString().c_str());
 	LinphoneAccount *default_account = linphone_core_get_default_account(pauline->lc);
 	op->setRealm(linphone_account_params_get_realm(linphone_account_get_params(default_account)));
 	const LinphoneAddress *contact = linphone_account_get_contact_address(default_account);
-	SalAddress *contactAddr = sal_address_clone(L_GET_CPP_PTR_FROM_C_OBJECT(contact)->getInternalAddress());
+	SalAddress *contactAddr = sal_address_clone(Address::toCpp(const_cast<LinphoneAddress *>(contact))->getImpl());
 	op->setContactAddress(contactAddr);
 	SalCustomHeader *ch =
 	    sal_custom_header_append(NULL, "Last-Notify-Version", std::to_string(localConf->getLastNotify() + 10).c_str());
@@ -2350,23 +2292,17 @@ void send_device_added_notify() {
 void send_device_removed_notify() {
 	LinphoneCoreManager *pauline =
 	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	shared_ptr<LocalConferenceTester> localConf =
 	    make_shared<LocalConferenceTester>(pauline->lc->cppPtr, addr, nullptr);
 	std::shared_ptr<ConferenceListenerInterfaceTester> confListener =
 	    std::make_shared<ConferenceListenerInterfaceTester>();
 	localConf->addListener(confListener);
 	LinphoneAddress *cBobAddr = linphone_core_interpret_url(pauline->lc, bobUri);
-	char *bobAddrStr = linphone_address_as_string(cBobAddr);
-	Address bobAddr(bobAddrStr);
-	bctbx_free(bobAddrStr);
+	std::shared_ptr<Address> bobAddr = Address::toCpp(cBobAddr)->getSharedFromThis();
 	linphone_address_unref(cBobAddr);
 	LinphoneAddress *cAliceAddr = linphone_core_interpret_url(pauline->lc, aliceUri);
-	char *aliceAddrStr = linphone_address_as_string(cAliceAddr);
-	Address aliceAddr(aliceAddrStr);
-	bctbx_free(aliceAddrStr);
+	std::shared_ptr<Address> aliceAddr = Address::toCpp(cAliceAddr)->getSharedFromThis();
 	linphone_address_unref(cAliceAddr);
 
 	localConf->addParticipant(bobAddr);
@@ -2374,32 +2310,35 @@ void send_device_removed_notify() {
 	localConf->setSubject("A random test subject");
 	shared_ptr<Participant> alice = localConf->findParticipant(aliceAddr);
 	setParticipantAsAdmin(localConf, aliceAddr, true);
-	localConf->setConferenceAddress(ConferenceAddress(addr));
+	localConf->setConferenceAddress(addr);
 
 	BC_ASSERT_EQUAL((int)confListener->participantDevices.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr.asString()) != confListener->participantDevices.end());
-	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr.asString()) !=
+	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr->toString()) !=
+	               confListener->participantDevices.end());
+	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr->toString()) !=
 	               confListener->participantDevices.end());
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr.asString())->second, 0, int, "%d");
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr.asString())->second, 0, int, "%d");
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr->toString())->second, 0, int, "%d");
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr->toString())->second, 0, int, "%d");
 
 	localConf->notifyParticipantDeviceAdded(time(nullptr), false, alice, alice->findDevice(aliceAddr));
 
 	BC_ASSERT_EQUAL((int)confListener->participantDevices.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr.asString()) != confListener->participantDevices.end());
-	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr.asString()) !=
+	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr->toString()) !=
 	               confListener->participantDevices.end());
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr.asString())->second, 0, int, "%d");
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr.asString())->second, 1, int, "%d");
+	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr->toString()) !=
+	               confListener->participantDevices.end());
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr->toString())->second, 0, int, "%d");
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr->toString())->second, 1, int, "%d");
 
 	localConf->notifyParticipantDeviceRemoved(time(nullptr), false, alice, alice->findDevice(aliceAddr));
 
 	BC_ASSERT_EQUAL((int)confListener->participantDevices.size(), 2, int, "%d");
-	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr.asString()) != confListener->participantDevices.end());
-	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr.asString()) !=
+	BC_ASSERT_TRUE(confListener->participantDevices.find(bobAddr->toString()) !=
+	               confListener->participantDevices.end());
+	BC_ASSERT_TRUE(confListener->participantDevices.find(aliceAddr->toString()) !=
 	               confListener->participantDevices.end());
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr.asString())->second, 0, int, "%d");
-	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr.asString())->second, 0, int, "%d");
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(bobAddr->toString())->second, 0, int, "%d");
+	BC_ASSERT_EQUAL(confListener->participantDevices.find(aliceAddr->toString())->second, 0, int, "%d");
 
 	localConf = nullptr;
 	alice = nullptr;
@@ -2410,9 +2349,7 @@ void one_to_one_keyword() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 	LinphoneCoreManager *pauline =
 	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
-	char *identityStr = linphone_address_as_string(pauline->identity);
-	Address addr(identityStr);
-	bctbx_free(identityStr);
+	std::shared_ptr<Address> addr = Address::toCpp(pauline->identity)->getSharedFromThis();
 	shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
 	shared_ptr<LocalConference> localConf =
 	    make_shared<LocalConference>(pauline->lc->cppPtr, addr, nullptr, ConferenceParams::create(pauline->lc));
@@ -2420,9 +2357,7 @@ void one_to_one_keyword() {
 	    std::make_shared<ConferenceListenerInterfaceTester>();
 	localConf->addListener(confListener);
 	LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri);
-	char *bobAddrStr = linphone_address_as_string(cBobAddr);
-	Address bobAddr(bobAddrStr);
-	bctbx_free(bobAddrStr);
+	std::shared_ptr<Address> bobAddr = Address::toCpp(cBobAddr)->getSharedFromThis();
 	linphone_address_unref(cBobAddr);
 
 	// Create basic chat room with OneToOne capability to ensure that one to one is added to notify
@@ -2430,16 +2365,16 @@ void one_to_one_keyword() {
 
 	localConf->addParticipant(bobAddr);
 	LocalConferenceEventHandler *localHandler = (L_ATTR_GET(localConf.get(), eventHandler)).get();
-	localConf->setConferenceAddress(ConferenceAddress(addr));
+	localConf->setConferenceAddress(addr);
 	Content content = localHandler->createNotifyFullState(NULL);
 
-	const_cast<ConferenceAddress &>(tester->handler->getConferenceId().getPeerAddress()) = ConferenceAddress(addr);
+	const_cast<ConferenceId &>(tester->handler->getConferenceId()).setPeerAddress(addr);
 
 	tester->handler->notifyReceived(content);
 
 	BC_ASSERT_EQUAL((int)tester->participantDevices.size(), 1, int, "%d");
-	BC_ASSERT_TRUE(tester->participantDevices.find(bobAddr.asString()) != tester->participantDevices.end());
-	BC_ASSERT_EQUAL(tester->participantDevices.find(bobAddr.asString())->second, 0, int, "%d");
+	BC_ASSERT_TRUE(tester->participantDevices.find(bobAddr->toString()) != tester->participantDevices.end());
+	BC_ASSERT_EQUAL(tester->participantDevices.find(bobAddr->toString())->second, 0, int, "%d");
 	BC_ASSERT_TRUE(tester->oneToOne);
 
 	tester = nullptr;
diff --git a/tester/conference-info-tester.cpp b/tester/conference-info-tester.cpp
index 032d0d25e24c53fff76ea7e0b56a0366e4bb4227..9c6686bdb1b36206f3e8ee6c0c31bfd411853527 100644
--- a/tester/conference-info-tester.cpp
+++ b/tester/conference-info-tester.cpp
@@ -37,12 +37,13 @@ using namespace LinphonePrivate;
 static void get_conference_info_from_call_log() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 
+	const shared_ptr<Address> from = Address::toCpp(marie->identity)->getSharedFromThis();
+	const shared_ptr<Address> to =
+	    Address::create("sip:video-conf-test@sip.linphone.org;conf-id=K4lHv;gr=60610d90-d695-0009-b3a1-331c5842bae0");
+
 	// Create a fake call log
-	auto callLog = CallLog::create(
-	    L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->getSharedFromThis(), LinphoneCallIncoming,
-	    linphone_address_clone(marie->identity),
-	    linphone_address_new(
-	        "sip:video-conf-test@sip.linphone.org;conf-id=K4lHv;gr=60610d90-d695-0009-b3a1-331c5842bae0"));
+	auto callLog =
+	    CallLog::create(L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->getSharedFromThis(), LinphoneCallIncoming, from, to);
 
 	callLog->setDuration(120);
 	callLog->setStatus(LinphoneCallSuccess);
@@ -52,14 +53,14 @@ static void get_conference_info_from_call_log() {
 	// Create a conference info
 	auto conferenceInfo = ConferenceInfo::create();
 
-	conferenceInfo->setOrganizer(IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(marie->identity)));
-	conferenceInfo->setUri(ConferenceAddress(
-	    "sip:video-conf-test@sip.linphone.org;gr=60610d90-d695-0009-b3a1-331c5842bae0;conf-id=K4lHv"));
+	conferenceInfo->setOrganizer(Address::toCpp(marie->identity)->getSharedFromThis());
+	conferenceInfo->setUri(
+	    Address::create("sip:video-conf-test@sip.linphone.org;gr=60610d90-d695-0009-b3a1-331c5842bae0;conf-id=K4lHv"));
 	conferenceInfo->setDateTime(std::time(nullptr));
 	conferenceInfo->setDuration(30);
 	conferenceInfo->setSubject("Test de vidéo conférence");
 	conferenceInfo->setDescription("Réunion pour parler de la vidéo conférence.");
-	conferenceInfo->addParticipant(IdentityAddress("sip:laure@sip.linphone.org"));
+	conferenceInfo->addParticipant(Address::create("sip:laure@sip.linphone.org"));
 
 	L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->reportConferenceCallEvent(EventLog::Type::ConferenceCallStarted, callLog,
 	                                                                  conferenceInfo);
@@ -73,12 +74,12 @@ static void get_conference_info_from_call_log() {
 static void get_existing_conference_info_from_call_log() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
 
+	const shared_ptr<Address> from = Address::toCpp(marie->identity)->getSharedFromThis();
+	const shared_ptr<Address> to =
+	    Address::create("sip:video-conf-test@sip.linphone.org;conf-id=K4lHv;gr=60610d90-d695-0009-b3a1-331c5842bae0");
 	// Create a fake call log
-	auto callLog = CallLog::create(
-	    L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->getSharedFromThis(), LinphoneCallIncoming,
-	    linphone_address_clone(marie->identity),
-	    linphone_address_new(
-	        "sip:video-conf-test@sip.linphone.org;conf-id=K4lHv;gr=60610d90-d695-0009-b3a1-331c5842bae0"));
+	auto callLog =
+	    CallLog::create(L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->getSharedFromThis(), LinphoneCallIncoming, from, to);
 
 	callLog->setDuration(120);
 	callLog->setStatus(LinphoneCallSuccess);
@@ -88,14 +89,14 @@ static void get_existing_conference_info_from_call_log() {
 	// Create a conference info
 	auto conferenceInfo = ConferenceInfo::create();
 
-	conferenceInfo->setOrganizer(IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(marie->identity)));
-	conferenceInfo->setUri(ConferenceAddress(
-	    "sip:video-conf-test@sip.linphone.org;gr=60610d90-d695-0009-b3a1-331c5842bae0;conf-id=K4lHv"));
+	conferenceInfo->setOrganizer(Address::toCpp(marie->identity)->getSharedFromThis());
+	conferenceInfo->setUri(
+	    Address::create("sip:video-conf-test@sip.linphone.org;conf-id=K4lHv;gr=60610d90-d695-0009-b3a1-331c5842bae0"));
 	conferenceInfo->setDateTime(std::time(nullptr));
 	conferenceInfo->setDuration(30);
 	conferenceInfo->setSubject("Test de vidéo conférence");
 	conferenceInfo->setDescription("Réunion pour parler de la vidéo conférence.");
-	conferenceInfo->addParticipant(IdentityAddress("sip:laure@sip.linphone.org"));
+	conferenceInfo->addParticipant(Address::create("sip:laure@sip.linphone.org"));
 
 	// First insert the conference info into DB
 	L_GET_PRIVATE_FROM_C_OBJECT(marie->lc)->mainDb->insertConferenceInfo(conferenceInfo);
@@ -112,12 +113,13 @@ static void get_existing_conference_info_from_call_log() {
 
 static void last_outgoing_call_without_conference() {
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
-	LinphoneAddress *paulineAddr = linphone_address_new("sip:pauline@sip.linphone.org");
-	linphone_address_set_display_name(paulineAddr, "PauPau");
 
+	const shared_ptr<Address> from = Address::toCpp(marie->identity)->getSharedFromThis();
+	const shared_ptr<Address> to = Address::create("sip:pauline@sip.linphone.org");
+	to->setDisplayName("PauPau");
 	// Create a fake call log
-	auto callLog = CallLog::create(L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->getSharedFromThis(), LinphoneCallOutgoing,
-	                               linphone_address_clone(marie->identity), linphone_address_clone(paulineAddr));
+	auto callLog =
+	    CallLog::create(L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->getSharedFromThis(), LinphoneCallOutgoing, from, to);
 
 	callLog->setDuration(60);
 	callLog->setStatus(LinphoneCallSuccess);
@@ -132,12 +134,11 @@ static void last_outgoing_call_without_conference() {
 	BC_ASSERT_STRING_EQUAL("PauPau", linphone_address_get_display_name(linphone_call_log_get_to_address(log)));
 	linphone_call_log_unref(log);
 
+	const shared_ptr<Address> to2 =
+	    Address::create("sip:video-conf-test@sip.linphone.org;conf-id=K4lHv;gr=60610d90-d695-0009-b3a1-331c5842bae0");
 	// Create a new fake call log to a conference
-	callLog = CallLog::create(
-	    L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->getSharedFromThis(), LinphoneCallOutgoing,
-	    linphone_address_clone(marie->identity),
-	    linphone_address_new(
-	        "sip:video-conf-test@sip.linphone.org;conf-id=K4lHv;gr=60610d90-d695-0009-b3a1-331c5842bae0"));
+	callLog =
+	    CallLog::create(L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->getSharedFromThis(), LinphoneCallOutgoing, from, to2);
 
 	callLog->setDuration(120);
 	callLog->setStatus(LinphoneCallSuccess);
@@ -147,14 +148,14 @@ static void last_outgoing_call_without_conference() {
 	// Create a conference info
 	auto conferenceInfo = ConferenceInfo::create();
 
-	conferenceInfo->setOrganizer(IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(marie->identity)));
-	conferenceInfo->setUri(ConferenceAddress(
-	    "sip:video-conf-test@sip.linphone.org;gr=60610d90-d695-0009-b3a1-331c5842bae0;conf-id=K4lHv"));
+	conferenceInfo->setOrganizer(Address::toCpp(marie->identity)->getSharedFromThis());
+	conferenceInfo->setUri(
+	    Address::create("sip:video-conf-test@sip.linphone.org;gr=60610d90-d695-0009-b3a1-331c5842bae0;conf-id=K4lHv"));
 	conferenceInfo->setDateTime(std::time(nullptr));
 	conferenceInfo->setDuration(30);
 	conferenceInfo->setSubject("Test de vidéo conférence");
 	conferenceInfo->setDescription("Réunion pour parler de la vidéo conférence.");
-	conferenceInfo->addParticipant(IdentityAddress("sip:laure@sip.linphone.org"));
+	conferenceInfo->addParticipant(Address::create("sip:laure@sip.linphone.org"));
 
 	// Report the call event without specifying the conference info
 	L_GET_CPP_PTR_FROM_C_OBJECT(marie->lc)->reportConferenceCallEvent(EventLog::Type::ConferenceCallEnded, callLog,
@@ -164,10 +165,9 @@ static void last_outgoing_call_without_conference() {
 
 	BC_ASSERT_PTR_NOT_NULL(lastCall);
 	if (lastCall != nullptr) {
-		BC_ASSERT_TRUE(linphone_address_equal(lastCall->getToAddress(), paulineAddr));
+		BC_ASSERT_TRUE(*lastCall->getToAddress() == *to);
 	}
 
-	linphone_address_unref(paulineAddr);
 	linphone_core_manager_destroy(marie);
 }
 
diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp
index fae27cba880c87e77e74159bab0fecc11cfb4001..06d07353172213837a5d5b00923e4349ec38c9ab 100644
--- a/tester/cpim-tester.cpp
+++ b/tester/cpim-tester.cpp
@@ -273,11 +273,11 @@ static void cpim_chat_message_modifier_base(bool useMultipart) {
 	linphone_core_set_im_encryption_engine(pauline->lc, pauline_imee);
 
 	char *paulineUri = linphone_address_as_string_uri_only(pauline->identity);
-	IdentityAddress paulineAddress(paulineUri);
+	std::shared_ptr<Address> paulineAddress = Address::create(paulineUri);
 	bctbx_free(paulineUri);
 
 	char *marieUri = linphone_address_as_string_uri_only(marie->identity);
-	IdentityAddress marieAddress(marieUri);
+	std::shared_ptr<Address> marieAddress = Address::create(marieUri);
 	bctbx_free(marieUri);
 
 	shared_ptr<AbstractChatRoom> marieRoom = marie->lc->cppPtr->getOrCreateBasicChatRoom(marieAddress, paulineAddress);
diff --git a/tester/group_chat_secure_tester.c b/tester/group_chat_secure_tester.c
index d47f0067f4fc03a1f7c183ffc9ca8aa82d7c486a..752bd951d1a93f78d427f3d9d9c9c3a78c713c62 100644
--- a/tester/group_chat_secure_tester.c
+++ b/tester/group_chat_secure_tester.c
@@ -2993,7 +2993,6 @@ static void group_chat_lime_x3dh_call_security_alert_curve(const int curveId) {
 	}
 
 end:
-
 	// Clean db from chat room
 	linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
 	linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
diff --git a/tester/ics-tester.cpp b/tester/ics-tester.cpp
index 15eec0b5a0120b298061500c098dd1bc46778309..0e40ef9889738b8f3d5a3e56a742f4b458be20f4 100644
--- a/tester/ics-tester.cpp
+++ b/tester/ics-tester.cpp
@@ -90,6 +90,7 @@ static void parse_rfc_example() {
 
 static void parse_folded_example() {
 	const string str = "BEGIN:VCALENDAR\r\n"
+	                   "METHOD:REQUEST\r\n"
 	                   "PRODID:-//xyz Corp//NONSGML PDA Calendar Version 1.0//EN\r\n"
 	                   "VERSION:2.0\r\n"
 	                   "BEGIN:VEVENT\r\n"
@@ -128,7 +129,7 @@ static void parse_folded_example() {
 				const auto &params = participant.second;
 				size_t no_params = 0;
 				bool found = false;
-				if (address == IdentityAddress("sip:jdoe@sip.example.org")) {
+				if (*address == *Address::create("sip:jdoe@sip.example.org")) {
 					no_params = 2;
 					for (const auto &param : params) {
 						const auto &name = param.first;
@@ -142,7 +143,7 @@ static void parse_folded_example() {
 							found = true;
 						}
 					}
-				} else if (address == IdentityAddress("sip:pwhite@sip.example.org")) {
+				} else if (*address == *Address::create("sip:pwhite@sip.example.org")) {
 					no_params = 1;
 					for (const auto &param : params) {
 						const auto &name = param.first;
@@ -153,7 +154,7 @@ static void parse_folded_example() {
 							found = true;
 						}
 					}
-				} else if (address == IdentityAddress("sip:tmurphy@sip.example.org")) {
+				} else if (*address == *Address::create("sip:tmurphy@sip.example.org")) {
 					// no_params = 2;
 					no_params = 1;
 					for (const auto &param : params) {
@@ -234,8 +235,8 @@ static void build_ics() {
 
 	auto confInfo = calendar.toConferenceInfo();
 
-	BC_ASSERT_TRUE(confInfo->getOrganizerAddress().isValid());
-	BC_ASSERT_TRUE(confInfo->getUri().isValid());
+	BC_ASSERT_TRUE(confInfo->getOrganizerAddress()->isValid());
+	BC_ASSERT_TRUE(confInfo->getUri()->isValid());
 	BC_ASSERT_EQUAL(confInfo->getParticipants().size(), 2, size_t, "%zu");
 	BC_ASSERT_EQUAL(confInfo->getDuration(), 165, int, "%d");
 	BC_ASSERT_EQUAL(confInfo->getIcsSequence(), 10, int, "%d");
@@ -368,13 +369,13 @@ static void send_conference_invitations(bool_t enable_encryption,
 			    marie->identity, linphone_conference_info_get_organizer(conf_info_from_original_content)));
 			BC_ASSERT_TRUE(linphone_address_weak_equal(
 			    conf_uri, linphone_conference_info_get_uri(conf_info_from_original_content)));
-			const bctbx_list_t *participants =
-			    linphone_conference_info_get_participants(conf_info_from_original_content);
+			bctbx_list_t *participants = linphone_conference_info_get_participants(conf_info_from_original_content);
 			if (add_participant_in_error) {
 				BC_ASSERT_EQUAL(bctbx_list_size(participants), 3, size_t, "%zu");
 			} else {
 				BC_ASSERT_EQUAL(bctbx_list_size(participants), 2, size_t, "%zu");
 			}
+			bctbx_list_free(participants);
 			BC_ASSERT_EQUAL(linphone_conference_info_get_duration(conf_info_from_original_content), 120, int, "%d");
 			BC_ASSERT_TRUE(linphone_conference_info_get_date_time(conf_info_from_original_content) == conf_time);
 			linphone_conference_info_unref(conf_info_from_original_content);
@@ -424,12 +425,13 @@ static void send_conference_invitations(bool_t enable_encryption,
 			                                           linphone_conference_info_get_organizer(conf_info_from_content)));
 			BC_ASSERT_TRUE(
 			    linphone_address_weak_equal(conf_uri, linphone_conference_info_get_uri(conf_info_from_content)));
-			const bctbx_list_t *participants = linphone_conference_info_get_participants(conf_info_from_content);
+			bctbx_list_t *participants = linphone_conference_info_get_participants(conf_info_from_content);
 			if (add_participant_in_error) {
 				BC_ASSERT_EQUAL(bctbx_list_size(participants), 3, size_t, "%zu");
 			} else {
 				BC_ASSERT_EQUAL(bctbx_list_size(participants), 2, size_t, "%zu");
 			}
+			bctbx_list_free(participants);
 			BC_ASSERT_EQUAL(linphone_conference_info_get_duration(conf_info_from_content), 120, int, "%d");
 			BC_ASSERT_TRUE(linphone_conference_info_get_date_time(conf_info_from_content) == conf_time);
 			linphone_conference_info_unref(conf_info_from_content);
diff --git a/tester/liblinphone_tester++.h b/tester/liblinphone_tester++.h
index 20ccddf543d547bcb5d6ade7484ccdb42c4f65ae..2ab463005a22ced4da37b1b2825d304886491350 100644
--- a/tester/liblinphone_tester++.h
+++ b/tester/liblinphone_tester++.h
@@ -62,8 +62,8 @@ public:
 	BorrowedMut<LinphoneProxyConfig> getDefaultProxyConfig() {
 		return borrowed_mut(linphone_core_get_default_proxy_config(mMgr->lc));
 	}
-	LinphonePrivate::IdentityAddress getIdentity() {
-		return *L_GET_CPP_PTR_FROM_C_OBJECT(mMgr->identity);
+	std::shared_ptr<LinphonePrivate::Address> getIdentity() {
+		return LinphonePrivate::Address::toCpp(mMgr->identity)->getSharedFromThis();
 	}
 	void setUseRfc2833ForDtmf(bool value) {
 		linphone_core_set_use_rfc2833_for_dtmf(mMgr->lc, value);
diff --git a/tester/local_conference_tester.cpp b/tester/local_conference_tester.cpp
index 3e9895798afd6ed2239c1316154cb35f80be75f4..566549320733fe76bdb1bc57e0255443744544b6 100644
--- a/tester/local_conference_tester.cpp
+++ b/tester/local_conference_tester.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2022 Belledonne Communications SARL.
+ * copyright (c) 2010-2022 belledonne communications sarl.
  *
  * This file is part of Liblinphone
  * (see https://gitlab.linphone.org/BC/public/liblinphone).
@@ -22,17 +22,15 @@
 
 #include "bctoolbox/crypto.h"
 #include "bctoolbox/ownership.hh"
-
 #include <bctoolbox/defs.h>
 
 #include "address/address.h"
-#include "address/identity-address.h"
-#include "bctoolbox/crypto.h"
 #include "c-wrapper/c-wrapper.h"
 #include "chat/chat-room/chat-room.h"
 #include "chat/chat-room/server-group-chat-room-p.h"
 #include "conference/participant.h"
 #include "core/core.h"
+#include "liblinphone_tester++.h"
 #include "liblinphone_tester.h"
 #include "linphone/api/c-chat-room-params.h"
 #include "linphone/api/c-chat-room.h"
@@ -42,11 +40,6 @@
 #include "shared_tester_functions.h"
 #include "tester_utils.h"
 
-#include "liblinphone_tester++.h"
-#include "liblinphone_tester.h"
-#include "shared_tester_functions.h"
-#include "tester_utils.h"
-
 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
 #pragma GCC diagnostic push
 #endif
@@ -121,8 +114,8 @@ public:
 		start(check_for_proxies);
 	}
 
-	void configureCoreForConference(const Address &factoryUri) {
-		_configure_core_for_conference(mMgr.get(), L_GET_C_BACK_PTR(&factoryUri));
+	void configureCoreForConference(const std::shared_ptr<Address> &factoryUri) {
+		_configure_core_for_conference(mMgr.get(), factoryUri->toC());
 	}
 	void setupMgrForConference(const char *conferenceVersion = nullptr) {
 		setup_mgr_for_conference(mMgr.get(), conferenceVersion);
@@ -164,11 +157,11 @@ class Focus;
 /*Core manager acting as a client*/
 class ClientConference : public ConfCoreManager {
 public:
-	ClientConference(std::string rc, Address factoryUri, bool encrypted = false)
+	ClientConference(std::string rc, std::shared_ptr<Address> factoryUri, bool encrypted = false)
 	    : ConfCoreManager(rc,
 	                      [this, factoryUri, encrypted] {
 		                      configureCoreForConference(factoryUri);
-		                      _configure_core_for_audio_video_conference(mMgr.get(), L_GET_C_BACK_PTR(&factoryUri));
+		                      _configure_core_for_audio_video_conference(mMgr.get(), factoryUri->toC());
 		                      setupMgrForConference();
 		                      LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
 		                      linphone_core_cbs_set_chat_room_state_changed(cbs, core_chat_room_state_changed);
@@ -235,8 +228,8 @@ public:
 
 	void registerAsParticipantDevice(ClientConference &otherMgr) {
 		const LinphoneAddress *cAddr = linphone_proxy_config_get_contact(otherMgr.getDefaultProxyConfig());
-		IdentityAddress participantDevice(*L_GET_CPP_PTR_FROM_C_OBJECT(cAddr));
-		IdentityAddress participant = participantDevice.getAddressWithoutGruu();
+		Address participantDevice = Address::toCpp(const_cast<LinphoneAddress *>(cAddr))->getUri();
+		Address participant = participantDevice.getUriWithoutGruu();
 		mParticipantDevices.insert({participant, participantDevice});
 		// to allow client conference to delete chatroom in its destructor
 		otherMgr.setFocus(borrowed_mut(this));
@@ -269,10 +262,11 @@ private:
 		    (Focus *)(((LinphoneCoreManager *)linphone_core_get_user_data(linphone_chat_room_get_core(cr)))->user_info);
 		char config_id[6];
 		belle_sip_random_token(config_id, sizeof(config_id));
-		const LinphoneAddress *cAddr = linphone_proxy_config_get_contact(focus->getDefaultProxyConfig());
-		Address conference_address = (*L_GET_CPP_PTR_FROM_C_OBJECT(cAddr));
-		conference_address.setUriParam("conf-id", config_id);
-		linphone_chat_room_set_conference_address(cr, L_GET_C_BACK_PTR(&conference_address));
+		LinphoneAddress *conference_address =
+		    linphone_address_clone(linphone_proxy_config_get_contact(focus->getDefaultProxyConfig()));
+		linphone_address_set_uri_param(conference_address, "conf-id", config_id);
+		linphone_chat_room_set_conference_address(cr, conference_address);
+		linphone_address_unref(conference_address);
 	}
 
 	static void
@@ -300,7 +294,7 @@ private:
 	                                                                      const LinphoneAddress *participantAddr) {
 		BC_ASSERT_PTR_NOT_NULL(participantAddr);
 		if (participantAddr) {
-			const IdentityAddress participant = *L_GET_CPP_PTR_FROM_C_OBJECT(participantAddr);
+			Address participant = Address::toCpp(const_cast<LinphoneAddress *>(participantAddr))->getUri();
 			BC_ASSERT_TRUE(participant.isValid());
 			if (participant.isValid()) {
 				Focus *focus =
@@ -309,7 +303,7 @@ private:
 				auto participantRange = focus->mParticipantDevices.equal_range(participant);
 				for (auto participantIt = participantRange.first; participantIt != participantRange.second;
 				     participantIt++) {
-					LinphoneAddress *deviceAddr = linphone_address_new(participantIt->second.asString().c_str());
+					LinphoneAddress *deviceAddr = linphone_address_new(participantIt->second.toString().c_str());
 					LinphoneParticipantDeviceIdentity *identity =
 					    linphone_factory_create_participant_device_identity(linphone_factory_get(), deviceAddr, "");
 					linphone_participant_device_identity_set_capability_descriptor(
@@ -317,8 +311,7 @@ private:
 					devices = bctbx_list_append(devices, identity);
 					linphone_address_unref(deviceAddr);
 				}
-				Address participantAddress(participant.asAddress().asString());
-				linphone_chat_room_set_participant_devices(cr, L_GET_C_BACK_PTR(&participantAddress), devices);
+				linphone_chat_room_set_participant_devices(cr, participant.toC(), devices);
 				bctbx_list_free_with_data(devices, (bctbx_list_free_func)belle_sip_object_unref);
 			}
 		}
@@ -344,11 +337,11 @@ private:
 		//		linphone_core_cbs_set_refer_received(cbs, linphone_conference_server_refer_received);
 		auto config = getDefaultProxyConfig();
 		linphone_proxy_config_edit(config);
-		linphone_proxy_config_set_conference_factory_uri(config, getIdentity().asString().c_str());
+		linphone_proxy_config_set_conference_factory_uri(config, getIdentity()->toString().c_str());
 		linphone_proxy_config_done(config);
 	}
 
-	std::multimap<IdentityAddress, IdentityAddress, std::less<IdentityAddress>> mParticipantDevices;
+	std::multimap<Address, Address> mParticipantDevices;
 };
 
 void sendEphemeralMessageInAdminMode(Focus &focus,
@@ -462,9 +455,9 @@ void sendEphemeralMessageInAdminMode(Focus &focus,
 static void group_chat_room_creation_server(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -475,12 +468,10 @@ static void group_chat_room_creation_server(void) {
 		coresList = bctbx_list_append(coresList, pauline.getLc());
 		coresList = bctbx_list_append(coresList, laure.getLc());
 
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		Address laureAddr(laure.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&laureAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		std::shared_ptr<Address> laureAddr = laure.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(laureAddr->toC()));
 
 		stats initialMarieStats = marie.getStats();
 		stats initialPaulineStats = pauline.getStats();
@@ -518,8 +509,7 @@ static void group_chat_room_creation_server(void) {
 		linphone_core_set_network_reachable(laure.getLc(), FALSE);
 		BC_ASSERT_FALSE(linphone_core_is_network_reachable(laure.getLc()));
 		CoreManagerAssert({focus, marie, pauline, laure}).waitUntil(std::chrono::seconds(1), [] { return false; });
-		LinphoneParticipant *laureParticipant =
-		    linphone_chat_room_find_participant(marieCr, L_GET_C_BACK_PTR(&laureAddr));
+		LinphoneParticipant *laureParticipant = linphone_chat_room_find_participant(marieCr, laureAddr->toC());
 		BC_ASSERT_PTR_NOT_NULL(laureParticipant);
 		linphone_chat_room_remove_participant(marieCr, laureParticipant);
 
@@ -571,8 +561,8 @@ static void group_chat_room_creation_server(void) {
 static void group_chat_room_server_deletion(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -580,9 +570,8 @@ static void group_chat_room_server_deletion(void) {
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		stats initialMarieStats = marie.getStats();
 		stats initialPaulineStats = pauline.getStats();
@@ -622,9 +611,8 @@ static void group_chat_room_server_deletion(void) {
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -646,8 +634,8 @@ static void group_chat_room_server_deletion(void) {
 static void group_chat_room_server_deletion_with_rmt_lst_event_handler(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -655,9 +643,8 @@ static void group_chat_room_server_deletion_with_rmt_lst_event_handler(void) {
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		stats initialMarieStats = marie.getStats();
 		stats initialPaulineStats = pauline.getStats();
@@ -723,9 +710,8 @@ static void group_chat_room_server_deletion_with_rmt_lst_event_handler(void) {
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -752,8 +738,8 @@ static void group_chat_room_server_deletion_with_rmt_lst_event_handler(void) {
 static void group_chat_room_server_admin_managed_messages_base(bool_t encrypted) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress(), encrypted);
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress(), encrypted);
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -767,9 +753,8 @@ static void group_chat_room_server_admin_managed_messages_base(bool_t encrypted)
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		stats chloe_stat = focus.getStats();
 		stats marie_stat = marie.getStats();
@@ -825,9 +810,8 @@ static void group_chat_room_server_admin_managed_messages_base(bool_t encrypted)
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -856,8 +840,8 @@ static void group_chat_room_server_admin_managed_messages_unencrypted(void) {
 static void group_chat_room_server_admin_managed_messages_ephemeral_enabled_after_creation(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -869,9 +853,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_enabled_afte
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		stats chloe_stat = focus.getStats();
 		stats marie_stat = marie.getStats();
@@ -984,9 +967,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_enabled_afte
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -1013,8 +995,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_enabled_afte
 static void group_chat_room_server_admin_managed_messages_ephemeral_disabled_after_creation(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -1028,9 +1010,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_disabled_aft
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		stats chloe_stat = focus.getStats();
 		stats marie_stat = marie.getStats();
@@ -1195,9 +1176,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_disabled_aft
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -1224,8 +1204,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_disabled_aft
 static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_update(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
 
 		linphone_core_set_default_ephemeral_lifetime(marie.getLc(), 5);
 
@@ -1239,9 +1219,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_upd
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		stats marie_stat = marie.getStats();
 		stats pauline_stat = pauline.getStats();
@@ -1320,9 +1299,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_upd
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -1349,8 +1327,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_upd
 static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_toggle_using_different_methods(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -1364,9 +1342,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_tog
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		stats chloe_stat = focus.getStats();
 		stats marie_stat = marie.getStats();
@@ -1514,9 +1491,8 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_tog
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -1541,9 +1517,9 @@ static void group_chat_room_server_admin_managed_messages_ephemeral_lifetime_tog
 static void group_chat_room_bulk_notify_to_participant(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -1553,12 +1529,10 @@ static void group_chat_room_bulk_notify_to_participant(void) {
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
 		coresList = bctbx_list_append(coresList, michelle.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
-		Address michelleAddr(michelle.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&michelleAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
+		std::shared_ptr<Address> michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr->toC()));
 
 		stats initialMarieStats = marie.getStats();
 		stats initialPaulineStats = pauline.getStats();
@@ -1615,7 +1589,7 @@ static void group_chat_room_bulk_notify_to_participant(void) {
 		linphone_core_set_network_reachable(pauline.getLc(), FALSE);
 
 		// Adding Laure
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
 		coresList = bctbx_list_append(coresList, laure.getLc());
 		focus.registerAsParticipantDevice(laure);
 
@@ -1624,8 +1598,8 @@ static void group_chat_room_bulk_notify_to_participant(void) {
 		initialMichelleStats = michelle.getStats();
 		stats initialLaureStats = laure.getStats();
 
-		Address laureAddr(laure.getIdentity().asAddress());
-		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&laureAddr)));
+		std::shared_ptr<Address> laureAddr = laure.getIdentity();
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(laureAddr->toC()));
 		linphone_chat_room_add_participants(marieCr, participantsAddresses);
 
 		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure.getCMgr(), &initialLaureStats,
@@ -1702,14 +1676,13 @@ static void group_chat_room_bulk_notify_to_participant(void) {
 		// Marisip deletes Laure's device
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			std::shared_ptr<Participant> participant =
-			    chatRoom->findParticipant(*L_GET_CPP_PTR_FROM_C_OBJECT(laureLocalAddr));
+			    chatRoom->findParticipant(Address::toCpp(laureLocalAddr)->getSharedFromThis());
 			BC_ASSERT_PTR_NOT_NULL(participant);
 			if (participant) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
 				// Do not use laureLocalAddr because it has a GRUU
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -1781,9 +1754,8 @@ static void group_chat_room_bulk_notify_to_participant(void) {
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -1808,8 +1780,8 @@ static void group_chat_room_bulk_notify_to_participant(void) {
 static void group_chat_room_with_client_restart(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(michelle);
@@ -1818,9 +1790,8 @@ static void group_chat_room_with_client_restart(void) {
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, michelle.getLc());
 		bctbx_list_t *participantsAddresses = NULL;
-		Address michelleAddr(michelle.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&michelleAddr)));
+		std::shared_ptr<Address> michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr->toC()));
 
 		stats initialMarieStats = marie.getStats();
 		stats initialMichelleStats = michelle.getStats();
@@ -1866,7 +1837,7 @@ static void group_chat_room_with_client_restart(void) {
 		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 1, int, "%d");
 		BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(michelleCr), 1, int, "%d");
 
-		ClientConference michelle2("michelle_rc", focus.getIdentity().asAddress());
+		ClientConference michelle2("michelle_rc", focus.getIdentity());
 		stats initialMichelle2Stats = michelle2.getStats();
 		coresList = bctbx_list_append(coresList, michelle2.getLc());
 		focus.registerAsParticipantDevice(michelle2);
@@ -1953,9 +1924,8 @@ static void group_chat_room_with_client_restart(void) {
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -2007,12 +1977,12 @@ server_core_chat_room_state_changed_sip_error(LinphoneCore *core, LinphoneChatRo
 static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscribe_error, bool encrypted) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress(), encrypted);
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress(), encrypted);
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress(), encrypted);
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress(), encrypted);
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress(), encrypted);
-		ClientConference michelle2("michelle_rc", focus.getIdentity().asAddress(), encrypted);
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), encrypted);
+		ClientConference berthe("berthe_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle2("michelle_rc", focus.getIdentity(), encrypted);
 
 		stats initialFocusStats = focus.getStats();
 		stats initialMarieStats = marie.getStats();
@@ -2100,18 +2070,14 @@ static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscri
 		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(berthe.getLc()));
 
 		bctbx_list_t *participantsAddresses = NULL;
-		Address michelleAddr(michelle.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&michelleAddr)));
-		Address michelle2Addr(michelle2.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&michelle2Addr)));
-		Address bertheAddr(berthe.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&bertheAddr)));
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr->toC()));
+		std::shared_ptr<Address> michelle2Addr = michelle2.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelle2Addr->toC()));
+		std::shared_ptr<Address> bertheAddr = berthe.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(bertheAddr->toC()));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(paulineAddr->toC()));
 
 		const char *initialSubject = "Colleagues (characters: $ £ çà)";
 		int participantsAddressesSize = (int)bctbx_list_size(participantsAddresses);
@@ -2197,7 +2163,7 @@ static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscri
 		std::string msg_text = "message michelle blabla";
 		LinphoneChatMessage *msg = ClientConference::sendTextMsg(michelleCr, msg_text);
 		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([msg] {
-			return (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered);
+			return (msg && (linphone_chat_message_get_state(msg) == LinphoneChatMessageStateDelivered));
 		}));
 
 		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([paulineCr] {
@@ -2214,6 +2180,7 @@ static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscri
 		                              initialMichelleStats.number_of_LinphoneMessageDisplayed + 1, 3000));
 
 		if (invite_error || subscribe_error) {
+			ms_message("%s - Enabling network of core %s", __func__, linphone_core_get_identity(marie.getLc()));
 			linphone_core_set_network_reachable(marie.getLc(), TRUE);
 			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneRegistrationOk,
 			                             initialMarieStats.number_of_LinphoneRegistrationOk + 1,
@@ -2223,8 +2190,8 @@ static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscri
 		}
 
 		focus.registerAsParticipantDevice(laure);
-		Address laureAddr(laure.getIdentity().asAddress());
-		linphone_chat_room_add_participant(marieCr, linphone_address_ref(L_GET_C_BACK_PTR(&laureAddr)));
+		std::shared_ptr<Address> laureAddr = laure.getIdentity();
+		linphone_chat_room_add_participant(marieCr, linphone_address_ref(laureAddr->toC()));
 		LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(
 		    coresList, laure.getCMgr(), &initialPaulineStats, confAddr, initialSubject, 4, FALSE);
 
@@ -2300,6 +2267,11 @@ static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscri
 
 		LinphoneChatMessage *michelle2LastMsg = NULL;
 		if (!invite_error) {
+
+			BC_ASSERT_TRUE(
+			    CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([michelle2Cr] {
+				    return linphone_chat_room_get_history_size(michelle2Cr) == 2;
+			    }));
 			michelle2LastMsg = michelle2.getStats().last_received_chat_message;
 			BC_ASSERT_PTR_NOT_NULL(michelle2LastMsg);
 			if (michelle2LastMsg) {
@@ -2309,7 +2281,7 @@ static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscri
 		}
 
 		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([bertheCr] {
-			return linphone_chat_room_get_unread_messages_count(bertheCr) == 2;
+			return linphone_chat_room_get_history_size(bertheCr) == 2;
 		}));
 
 		LinphoneChatMessage *bertheLastMsg = berthe.getStats().last_received_chat_message;
@@ -2323,7 +2295,8 @@ static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscri
 		                             initialMichelleStats.number_of_LinphoneMessageDisplayed + 1,
 		                             liblinphone_tester_sip_timeout));
 		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneMessageDisplayed,
-		                             initialLaureStats.number_of_LinphoneMessageDisplayed + 1, 3000));
+		                             initialLaureStats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
 
 		linphone_chat_message_unref(msg);
 		msg = nullptr;
@@ -2583,9 +2556,8 @@ static void group_chat_room_with_sip_errors_base(bool invite_error, bool subscri
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -2627,10 +2599,10 @@ static void secure_group_chat_room_with_subscribe_error(void) {
 static void secure_group_chat_room_with_chat_room_deleted_before_server_restart(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress(), true);
-		ClientConference marie2("marie_rc", focus.getIdentity().asAddress(), true);
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress(), true);
-		ClientConference michelle2("michelle_rc", focus.getIdentity().asAddress(), true);
+		ClientConference marie("marie_rc", focus.getIdentity(), true);
+		ClientConference marie2("marie_rc", focus.getIdentity(), true);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), true);
+		ClientConference michelle2("michelle_rc", focus.getIdentity(), true);
 
 		stats initialFocusStats = focus.getStats();
 		stats initialMarieStats = marie.getStats();
@@ -2673,12 +2645,10 @@ static void secure_group_chat_room_with_chat_room_deleted_before_server_restart(
 		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(michelle2.getLc()));
 
 		bctbx_list_t *participantsAddresses = NULL;
-		Address michelleAddr(michelle.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&michelleAddr)));
-		Address michelle2Addr(michelle2.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&michelle2Addr)));
+		std::shared_ptr<Address> michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr->toC()));
+		std::shared_ptr<Address> michelle2Addr = michelle2.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelle2Addr->toC()));
 
 		const char *initialSubject = "Colleagues (characters: $ £ çà)";
 
@@ -2758,7 +2728,8 @@ static void secure_group_chat_room_with_chat_room_deleted_before_server_restart(
 		linphone_chat_room_mark_as_read(michelle2Cr);
 		linphone_chat_room_mark_as_read(marieCr);
 		BC_ASSERT_TRUE(wait_for_list(coresList, &marie2.getStats().number_of_LinphoneMessageDisplayed,
-		                             initialMarie2Stats.number_of_LinphoneMessageDisplayed + 1, 3000));
+		                             initialMarie2Stats.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
 
 		linphone_chat_message_unref(msg);
 		msg = nullptr;
@@ -2912,9 +2883,8 @@ static void secure_group_chat_room_with_chat_room_deleted_before_server_restart(
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -2941,9 +2911,9 @@ static void secure_group_chat_room_with_chat_room_deleted_before_server_restart(
 static void group_chat_room_add_participant_with_invalid_address(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -2953,15 +2923,12 @@ static void group_chat_room_add_participant_with_invalid_address(void) {
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
 		coresList = bctbx_list_append(coresList, michelle.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
-		Address invalidAddr;
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&invalidAddr)));
-		Address michelleAddr(michelle.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&michelleAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
+		std::shared_ptr<Address> invalidAddr = Address::create();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(invalidAddr->toC()));
+		std::shared_ptr<Address> michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr->toC()));
 
 		stats initialMarieStats = marie.getStats();
 		stats initialPaulineStats = pauline.getStats();
@@ -3022,7 +2989,7 @@ static void group_chat_room_add_participant_with_invalid_address(void) {
 		initialPaulineStats = pauline.getStats();
 		initialMichelleStats = michelle.getStats();
 
-		linphone_chat_room_add_participant(marieCr, linphone_address_ref(L_GET_C_BACK_PTR(&invalidAddr)));
+		linphone_chat_room_add_participant(marieCr, linphone_address_ref(invalidAddr->toC()));
 
 		BC_ASSERT_FALSE(wait_for_list(coresList, &marie.getStats().number_of_participants_added,
 		                              initialMarieStats.number_of_participants_added + 1, 5000));
@@ -3054,9 +3021,8 @@ static void group_chat_room_add_participant_with_invalid_address(void) {
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -3074,7 +3040,7 @@ static void group_chat_room_add_participant_with_invalid_address(void) {
 		linphone_proxy_config_set_conference_factory_uri(config, NULL);
 		linphone_proxy_config_done(config);
 
-		linphone_address_unref(L_GET_C_BACK_PTR(&invalidAddr));
+		linphone_address_unref(invalidAddr->toC());
 		bctbx_list_free(coresList);
 	}
 }
@@ -3082,15 +3048,14 @@ static void group_chat_room_add_participant_with_invalid_address(void) {
 static void group_chat_room_with_only_participant_with_invalid_address(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
-		Address invalidAddr;
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&invalidAddr)));
+		std::shared_ptr<Address> invalidAddr = Address::create();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(invalidAddr->toC()));
 
 		stats initialMarieStats = marie.getStats();
 
@@ -3129,8 +3094,8 @@ static void group_chat_room_with_only_participant_with_invalid_address(void) {
 static void one_to_one_chatroom_exhumed_while_offline(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -3138,9 +3103,8 @@ static void one_to_one_chatroom_exhumed_while_offline(void) {
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		stats initialMarieStats = marie.getStats();
 		stats initialPaulineStats = pauline.getStats();
@@ -3205,8 +3169,8 @@ static void one_to_one_chatroom_exhumed_while_offline(void) {
 		initialMarieStats = marie.getStats();
 		initialPaulineStats = pauline.getStats();
 
-		paulineAddr = pauline.getIdentity().asAddress();
-		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		paulineAddr = pauline.getIdentity();
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		marieCr = create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
 		                                       initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
@@ -3338,9 +3302,9 @@ static void multidomain_group_chat_room(void) {
 	Focus focusExampleDotOrg("chloe_rc");
 	Focus focusAuth1DotExampleDotOrg("arthur_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focusExampleDotOrg.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focusExampleDotOrg.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focusExampleDotOrg.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focusExampleDotOrg.getIdentity());
+		ClientConference pauline("pauline_rc", focusExampleDotOrg.getIdentity());
+		ClientConference michelle("michelle_rc", focusExampleDotOrg.getIdentity());
 
 		focusExampleDotOrg.registerAsParticipantDevice(marie);
 		focusExampleDotOrg.registerAsParticipantDevice(pauline);
@@ -3350,12 +3314,10 @@ static void multidomain_group_chat_room(void) {
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
 		coresList = bctbx_list_append(coresList, michelle.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
-		Address michelleAddr(michelle.getIdentity().asAddress());
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&michelleAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
+		std::shared_ptr<Address> michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr->toC()));
 
 		stats initialMarieStats = marie.getStats();
 		stats initialPaulineStats = pauline.getStats();
@@ -3410,7 +3372,7 @@ static void multidomain_group_chat_room(void) {
 		focusAuth1DotExampleDotOrg.registerAsParticipantDevice(michelle);
 
 		// change conference factory uri
-		Address focusAuth1DotExampleDotOrgFactoryAddress = focusAuth1DotExampleDotOrg.getIdentity().asAddress();
+		std::shared_ptr<Address> focusAuth1DotExampleDotOrgFactoryAddress = focusAuth1DotExampleDotOrg.getIdentity();
 		marie.configureCoreForConference(focusAuth1DotExampleDotOrgFactoryAddress);
 		pauline.configureCoreForConference(focusAuth1DotExampleDotOrgFactoryAddress);
 		michelle.configureCoreForConference(focusAuth1DotExampleDotOrgFactoryAddress);
@@ -3419,11 +3381,9 @@ static void multidomain_group_chat_room(void) {
 		initialMarieStats = marie.getStats();
 		initialPaulineStats = pauline.getStats();
 		initialMichelleStats = michelle.getStats();
-		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&michelleAddr)));
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr->toC()));
 
-		;
 		LinphoneChatRoom *marieCrfocusAuth1DotExampleDotOrg =
 		    create_chat_room_client_side(coresList, marie.getCMgr(), &initialMarieStats, participantsAddresses,
 		                                 initialSubject, FALSE, LinphoneChatRoomEphemeralModeDeviceManaged);
@@ -3480,9 +3440,9 @@ static void multidomain_group_chat_room(void) {
 		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive, 2,
 		                             liblinphone_tester_sip_timeout));
 
-		ClientConference laure("laure_tcp_rc", focusExampleDotOrg.getIdentity().asAddress());
+		ClientConference laure("laure_tcp_rc", focusExampleDotOrg.getIdentity());
 		coresList = bctbx_list_append(coresList, laure.getLc());
-		Address laureAddr(laure.getIdentity().asAddress());
+		std::shared_ptr<Address> laureAddr = laure.getIdentity();
 		focusExampleDotOrg.registerAsParticipantDevice(laure);
 
 		initialMarieStats = marie.getStats();
@@ -3490,7 +3450,7 @@ static void multidomain_group_chat_room(void) {
 		initialMichelleStats = michelle.getStats();
 		stats initialLaureStats = laure.getStats();
 
-		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&laureAddr)));
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(laureAddr->toC()));
 		linphone_chat_room_add_participants(marieCr, participantsAddresses);
 
 		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreationPending,
@@ -3530,7 +3490,7 @@ static void multidomain_group_chat_room(void) {
 		focusAuth1DotExampleDotOrg.registerAsParticipantDevice(laure);
 		laure.configureCoreForConference(focusAuth1DotExampleDotOrgFactoryAddress);
 
-		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&laureAddr)));
+		participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(laureAddr->toC()));
 		linphone_chat_room_add_participants(marieCrfocusAuth1DotExampleDotOrg, participantsAddresses);
 		BC_ASSERT_TRUE(wait_for_list(coresList, &laure.getStats().number_of_LinphoneConferenceStateCreationPending,
 		                             initialLaureStats.number_of_LinphoneConferenceStateCreationPending + 2,
@@ -3571,8 +3531,8 @@ static void multidomain_group_chat_room(void) {
 static void group_chat_room_server_ephemeral_mode_changed(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -3584,9 +3544,8 @@ static void group_chat_room_server_ephemeral_mode_changed(void) {
 		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
 		coresList = bctbx_list_append(coresList, marie.getLc());
 		coresList = bctbx_list_append(coresList, pauline.getLc());
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
 
 		stats chloe_stat = focus.getStats();
 		stats marie_stat = marie.getStats();
@@ -3731,9 +3690,8 @@ static void group_chat_room_server_ephemeral_mode_changed(void) {
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -3761,9 +3719,9 @@ static void group_chat_room_lime_server_message(bool encrypted) {
 	{ // to make sure focus is destroyed after clients.
 		linphone_core_enable_lime_x3dh(focus.getLc(), true);
 
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress(), encrypted);
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress(), encrypted);
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress(), encrypted);
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), encrypted);
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -3791,12 +3749,10 @@ static void group_chat_room_lime_server_message(bool encrypted) {
 			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(laure.getLc()));
 		}
 
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		Address laureAddr(laure.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&laureAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		std::shared_ptr<Address> laureAddr = laure.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(laureAddr->toC()));
 
 		// Marie creates a new group chat room
 		const char *initialSubject = "Colleagues";
@@ -3842,9 +3798,8 @@ static void group_chat_room_lime_server_message(bool encrypted) {
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -3872,9 +3827,9 @@ static void group_chat_room_lime_session_corrupted(void) {
 	{ // to make sure focus is destroyed after clients.
 		linphone_core_enable_lime_x3dh(focus.getLc(), true);
 
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress(), true);
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress(), true);
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress(), true);
+		ClientConference marie("marie_rc", focus.getIdentity(), true);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), true);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), true);
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -3903,12 +3858,10 @@ static void group_chat_room_lime_session_corrupted(void) {
 		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(pauline.getLc()));
 		BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(laure.getLc()));
 
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		Address laureAddr(laure.getIdentity().asAddress());
-		bctbx_list_t *participantsAddresses =
-		    bctbx_list_append(NULL, linphone_address_ref(L_GET_C_BACK_PTR(&paulineAddr)));
-		participantsAddresses =
-		    bctbx_list_append(participantsAddresses, linphone_address_ref(L_GET_C_BACK_PTR(&laureAddr)));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		std::shared_ptr<Address> laureAddr = laure.getIdentity();
+		bctbx_list_t *participantsAddresses = bctbx_list_append(NULL, linphone_address_ref(paulineAddr->toC()));
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(laureAddr->toC()));
 
 		// Marie creates a new group chat room
 		const char *initialSubject = "Colleagues";
@@ -4010,9 +3963,8 @@ static void group_chat_room_lime_session_corrupted(void) {
 		for (auto chatRoom : focus.getCore().getChatRooms()) {
 			for (auto participant : chatRoom->getParticipants()) {
 				//  force deletion by removing devices
-				Address participantAddress(participant->getAddress().asAddress());
-				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom),
-				                                           L_GET_C_BACK_PTR(&participantAddress), NULL);
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
 			}
 		}
 
@@ -4085,8 +4037,9 @@ static void check_conference_info(LinphoneCoreManager *mgr,
 		BC_ASSERT_TRUE(linphone_address_weak_equal(organizer->identity, linphone_conference_info_get_organizer(info)));
 		BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
 
-		const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+		bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
 		BC_ASSERT_EQUAL(bctbx_list_size(info_participants), no_members, size_t, "%zu");
+		bctbx_list_free(info_participants);
 
 		if (start_time > 0) {
 			BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(info), start_time, long long, "%lld");
@@ -4223,7 +4176,6 @@ static LinphoneAddress *create_conference_on_server(Focus &focus,
 			                             liblinphone_tester_sip_timeout));
 
 			updated_conf_info = linphone_conference_scheduler_get_info(conference_scheduler);
-			conference_address = linphone_address_clone(linphone_conference_info_get_uri(updated_conf_info));
 			goto end;
 		}
 		BC_ASSERT_TRUE(
@@ -4372,15 +4324,17 @@ static LinphoneAddress *create_conference_on_server(Focus &focus,
 							    linphone_conference_info_get_uri(conf_info_in_db),
 							    linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-							const bctbx_list_t *ics_participants =
+							bctbx_list_t *ics_participants =
 							    linphone_conference_info_get_participants(conf_info_from_original_content);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participant_expected_participant_number,
 							                size_t, "%zu");
+							bctbx_list_free(ics_participants);
 
-							const bctbx_list_t *ics_participants_db =
+							bctbx_list_t *ics_participants_db =
 							    linphone_conference_info_get_participants(conf_info_in_db);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants_db),
 							                participant_expected_participant_number, size_t, "%zu");
+							bctbx_list_free(ics_participants_db);
 
 							if (start_time > 0) {
 								BC_ASSERT_EQUAL(
@@ -4617,6 +4571,11 @@ static void wait_for_conference_streams(std::initializer_list<std::reference_wra
 					    device_present = (bctbx_list_size(devices) > 0);
 					    for (bctbx_list_t *itd = devices; itd; itd = bctbx_list_next(itd)) {
 						    LinphoneParticipantDevice *d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
+						    bool_t found = FALSE;
+						    for (const auto &p : members) {
+							    found |= linphone_address_weak_equal(p->identity,
+							                                         linphone_participant_device_get_address(d));
+						    }
 						    if (enable_video && ((mgr == focus) || call_video_enabled)) {
 							    // Video is available if the direction is sendrecv or sendonly
 							    LinphoneMediaDirection video_dir =
@@ -4629,8 +4588,13 @@ static void wait_for_conference_streams(std::initializer_list<std::reference_wra
 							    video_check &=
 							        !linphone_participant_device_get_stream_availability(d, LinphoneStreamTypeVideo);
 						    }
-						    device_present &=
-						        (linphone_participant_device_get_state(d) == LinphoneParticipantDeviceStatePresent);
+						    LinphoneParticipantDeviceState expected_state = LinphoneParticipantDeviceStateJoining;
+						    if (found) {
+							    expected_state = LinphoneParticipantDeviceStatePresent;
+						    } else {
+							    expected_state = LinphoneParticipantDeviceStateLeft;
+						    }
+						    device_present &= (linphone_participant_device_get_state(d) == expected_state);
 					    }
 
 					    if (devices) {
@@ -4865,7 +4829,7 @@ static void set_video_settings_in_conference(LinphoneCoreManager *focus,
 static void call_to_inexisting_conference_address(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
 
 		bctbx_list_t *coresList = NULL;
 		coresList = bctbx_list_append(coresList, focus.getLc());
@@ -4873,7 +4837,7 @@ static void call_to_inexisting_conference_address(void) {
 
 		focus.registerAsParticipantDevice(marie);
 
-		LinphoneAddress *confAddr = linphone_address_new(L_STRING_TO_C(focus.getIdentity().asString()));
+		LinphoneAddress *confAddr = linphone_address_new(L_STRING_TO_C(focus.getIdentity()->toString()));
 		linphone_address_set_uri_param(confAddr, "conf-id", "xxxxx");
 
 		stats marie_stat = marie.getStats();
@@ -4913,11 +4877,11 @@ static void create_conference_base(time_t start_time,
                                    bool_t network_restart) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -5540,9 +5504,8 @@ static void create_conference_base(time_t start_time,
 			BC_ASSERT_PTR_NOT_NULL(pauline_call);
 			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pauline_call);
 
-			Address paulineAddr(pauline.getIdentity().asAddress());
-			LinphoneCall *focus_call =
-			    linphone_core_get_call_by_remote_address2(focus.getLc(), L_GET_C_BACK_PTR(&paulineAddr));
+			std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+			LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineAddr->toC());
 			BC_ASSERT_PTR_NOT_NULL(focus_call);
 
 			LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(pauline.getLc());
@@ -6913,9 +6876,9 @@ static void create_simple_conference_with_audio_only_participant_enabling_video(
 static void create_conference_with_server_restart_base(bool_t organizer_first) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -7229,11 +7192,11 @@ static void create_conference_with_server_restart_participant_first(void) {
 static void create_conference_with_codec_mismatch_base(bool_t organizer_codec_mismatch) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -7592,11 +7555,11 @@ static void create_conference_dial_out_base(bool_t send_ics,
                                             bool_t participant_codec_mismatch) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -7611,7 +7574,7 @@ static void create_conference_dial_out_base(bool_t send_ics,
 		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), pauline.getCMgr(), laure.getCMgr(), michelle.getCMgr(),
 		                 berthe.getCMgr()}) {
 			if (participant_codec_mismatch) {
-				if (participant_codec_mismatch && (mgr == michelle.getCMgr())) {
+				if (mgr == michelle.getCMgr()) {
 					disable_all_audio_codecs_except_one(mgr->lc, "pcmu", -1);
 				} else {
 					disable_all_audio_codecs_except_one(mgr->lc, "pcma", -1);
@@ -7679,9 +7642,7 @@ static void create_conference_dial_out_base(bool_t send_ics,
 		                             liblinphone_tester_sip_timeout));
 
 		if (participant_codec_mismatch) {
-			if (participant_codec_mismatch) {
-				codec_mismatch_members.push_back(michelle.getCMgr());
-			}
+			codec_mismatch_members.push_back(michelle.getCMgr());
 
 			for (const auto &m : codec_mismatch_members) {
 				auto itConferenceMgrs = std::find(conferenceMgrs.begin(), conferenceMgrs.end(), m);
@@ -7813,12 +7774,11 @@ static void create_conference_dial_out_base(bool_t send_ics,
 						BC_ASSERT_TRUE(
 						    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
 
-						const bctbx_list_t *info_participants =
-						    linphone_conference_info_get_participants(call_log_info);
-
+						bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
 						// Original participants + Marie who joined the conference
 						BC_ASSERT_EQUAL(bctbx_list_size(info_participants), participant_conference_info_participants,
 						                size_t, "%zu");
+						bctbx_list_free(info_participants);
 
 						BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0,
 						                         long long, "%lld");
@@ -8012,9 +7972,8 @@ static void create_conference_dial_out_base(bool_t send_ics,
 				LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
 				BC_ASSERT_PTR_NOT_NULL(pauline_call);
 
-				Address paulineAddr(pauline.getIdentity().asAddress());
-				LinphoneCall *focus_call =
-				    linphone_core_get_call_by_remote_address2(focus.getLc(), L_GET_C_BACK_PTR(&paulineAddr));
+				std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+				LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineAddr->toC());
 				BC_ASSERT_PTR_NOT_NULL(focus_call);
 
 				LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(pauline.getLc());
@@ -8252,11 +8211,11 @@ static void create_simple_conference_dial_out_participant_codec_mismatch(void) {
 static void create_simple_conference_dial_out_organizer_codec_mismatch(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -8309,23 +8268,23 @@ static void create_simple_conference_dial_out_organizer_codec_mismatch(void) {
 
 		LinphoneAddress *confAddr =
 		    create_conference_on_server(focus, marie, participants, -1, -1, initialSubject, description, TRUE);
-		BC_ASSERT_PTR_NOT_NULL(confAddr);
+		BC_ASSERT_PTR_NULL(confAddr);
 
 		// Chat room creation to send ICS
+		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreationFailed,
+		                             focus_stat.number_of_LinphoneConferenceStateCreationFailed + 1,
+		                             liblinphone_tester_sip_timeout));
 		BC_ASSERT_FALSE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneConferenceStateCreated,
 		                              marie_stat.number_of_LinphoneConferenceStateCreated + 1,
 		                              liblinphone_tester_sip_timeout));
 		BC_ASSERT_FALSE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneCallIncomingReceived,
 		                              focus_stat.number_of_LinphoneCallIncomingReceived + 1,
 		                              liblinphone_tester_sip_timeout));
-		BC_ASSERT_FALSE(wait_for_list(coresList, &focus.getStats().number_of_LinphoneConferenceStateCreationFailed,
-		                              focus_stat.number_of_LinphoneConferenceStateCreationFailed + 1,
-		                              liblinphone_tester_sip_timeout));
 
 		LinphoneConference *fconference = linphone_core_search_conference_2(focus.getLc(), confAddr);
 		BC_ASSERT_PTR_NULL(fconference);
 
-		linphone_address_unref(confAddr);
+		if (confAddr) linphone_address_unref(confAddr);
 		bctbx_list_free(coresList);
 	}
 }
@@ -8333,11 +8292,11 @@ static void create_simple_conference_dial_out_organizer_codec_mismatch(void) {
 static void create_simple_conference_dial_out_with_some_calls_declined_base(LinphoneReason reason) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -8503,10 +8462,10 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 					BC_ASSERT_TRUE(
 					    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
 
-					const bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
-
+					bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
 					// Original participants + Marie who joined the conference
 					BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 5, size_t, "%zu");
+					bctbx_list_free(info_participants);
 
 					BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0,
 					                         long long, "%lld");
@@ -8669,20 +8628,20 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 				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);
+				bctbx_list_t *participants_list = linphone_conference_get_participant_list(pconference);
 				if (reason == LinphoneReasonBusy) {
 					no_participants += declining_participants.size();
 				}
-				BC_ASSERT_EQUAL(bctbx_list_size(participants), no_participants, size_t, "%zu");
+				BC_ASSERT_EQUAL(bctbx_list_size(participants_list), no_participants, size_t, "%zu");
 				BC_ASSERT_EQUAL(linphone_conference_get_participant_count(pconference),
 				                static_cast<int>(no_participants), int, "%0d");
-				for (bctbx_list_t *itp = participants; itp; itp = bctbx_list_next(itp)) {
+				for (bctbx_list_t *itp = participants_list; itp; itp = bctbx_list_next(itp)) {
 					LinphoneParticipant *p = (LinphoneParticipant *)bctbx_list_get_data(itp);
 					BC_ASSERT_TRUE(
 					    linphone_participant_is_admin(p) ==
 					    linphone_address_weak_equal(linphone_participant_get_address(p), marie.getCMgr()->identity));
 				}
-				bctbx_list_free_with_data(participants, (void (*)(void *))linphone_participant_unref);
+				bctbx_list_free_with_data(participants_list, (void (*)(void *))linphone_participant_unref);
 
 				if (mgr != focus.getCMgr()) {
 					check_conference_ssrc(fconference, pconference);
@@ -8711,9 +8670,8 @@ static void create_simple_conference_dial_out_with_some_calls_declined_base(Linp
 		LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
 		BC_ASSERT_PTR_NOT_NULL(pauline_call);
 
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		LinphoneCall *focus_call =
-		    linphone_core_get_call_by_remote_address2(focus.getLc(), L_GET_C_BACK_PTR(&paulineAddr));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineAddr->toC());
 		BC_ASSERT_PTR_NOT_NULL(focus_call);
 
 		LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(pauline.getLc());
@@ -8899,11 +8857,11 @@ create_conference_with_late_participant_addition_base(time_t start_time,
                                                       bool_t one_addition) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -9060,11 +9018,11 @@ create_conference_with_late_participant_addition_base(time_t start_time,
 					BC_ASSERT_TRUE(
 					    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
 
-					const bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
-
+					bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
 					// Original participants + Marie who joined the conference
 					BC_ASSERT_EQUAL(bctbx_list_size(info_participants), static_cast<int>(members.size()), size_t,
 					                "%zu");
+					bctbx_list_free(info_participants);
 
 					if (start_time > 0) {
 						BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(call_log_info), start_time,
@@ -9451,9 +9409,8 @@ create_conference_with_late_participant_addition_base(time_t start_time,
 		LinphoneCall *pauline_call = linphone_core_get_call_by_remote_address2(pauline.getLc(), confAddr);
 		BC_ASSERT_PTR_NOT_NULL(pauline_call);
 
-		Address paulineAddr(pauline.getIdentity().asAddress());
-		LinphoneCall *focus_call =
-		    linphone_core_get_call_by_remote_address2(focus.getLc(), L_GET_C_BACK_PTR(&paulineAddr));
+		std::shared_ptr<Address> paulineAddr = pauline.getIdentity();
+		LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineAddr->toC());
 		BC_ASSERT_PTR_NOT_NULL(focus_call);
 
 		LinphoneVideoActivationPolicy *pol = linphone_core_get_video_activation_policy(pauline.getLc());
@@ -9635,11 +9592,11 @@ static void create_simple_conference_dial_out_with_many_late_participant_additio
 static void simple_dial_out_conference_with_no_payloads(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -9797,9 +9754,9 @@ static void simple_dial_out_conference_with_no_payloads(void) {
 static void abort_call_to_ice_conference(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -10151,10 +10108,10 @@ static void edit_simple_conference_base(bool_t from_organizer,
                                         bool_t server_restart) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
 
 		LinphoneCoreManager *manager_editing = (from_organizer) ? marie.getCMgr() : laure.getCMgr();
 		linphone_core_enable_rtp_bundle(manager_editing->lc, enable_bundle_mode);
@@ -10462,8 +10419,9 @@ static void edit_simple_conference_base(bool_t from_organizer,
 				}
 
 				const auto ics_participant_number = ((add) ? 3 : 2) + ((join) ? 1 : 0);
-				const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+				bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
 				BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number, size_t, "%zu");
+				bctbx_list_free(ics_participants);
 
 				std::list<stats> participant_stats;
 				for (auto mgr :
@@ -10574,10 +10532,11 @@ static void edit_simple_conference_base(bool_t from_organizer,
 										    confAddr,
 										    linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-										const bctbx_list_t *ics_participants =
+										bctbx_list_t *ics_participants =
 										    linphone_conference_info_get_participants(conf_info_from_original_content);
 										BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), ics_participant_number,
 										                size_t, "%zu");
+										bctbx_list_free(ics_participants);
 
 										if (start_time > 0) {
 											BC_ASSERT_EQUAL((long long)linphone_conference_info_get_date_time(
@@ -10776,10 +10735,10 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 	{ // to make sure focus is destroyed after clients.
 		linphone_core_enable_lime_x3dh(focus.getLc(), true);
 
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress(), true);
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress(), true);
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress(), true);
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress(), true);
+		ClientConference marie("marie_rc", focus.getIdentity(), true);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), true);
+		ClientConference laure("laure_tcp_rc", focus.getIdentity(), true);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), true);
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -10866,8 +10825,9 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 		linphone_conference_info_add_participant(conf_info, michelle.getCMgr()->identity);
 		linphone_conference_info_remove_participant(conf_info, laure.getCMgr()->identity);
 
-		const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+		bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
 		BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participants.size(), size_t, "%zu");
+		bctbx_list_free(ics_participants);
 
 		std::list<stats> participant_stats;
 		for (auto mgr : {focus.getCMgr(), marie.getCMgr(), laure.getCMgr(), pauline.getCMgr(), michelle.getCMgr()}) {
@@ -10963,9 +10923,10 @@ static void conference_edition_with_simultaneous_participant_add_remove_base(boo
 							BC_ASSERT_TRUE(linphone_address_weak_equal(
 							    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-							const bctbx_list_t *ics_participants =
+							bctbx_list_t *ics_participants =
 							    linphone_conference_info_get_participants(conf_info_from_original_content);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), participants.size(), size_t, "%zu");
+							bctbx_list_free(ics_participants);
 
 							if (start_time > 0) {
 								BC_ASSERT_EQUAL(
@@ -11073,10 +11034,10 @@ static void conference_edition_with_organizer_codec_mismatch(void) {
 static void conference_cancelled_through_edit_base(bool_t server_restart) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -11224,9 +11185,10 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 							BC_ASSERT_TRUE(linphone_address_weak_equal(
 							    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-							const bctbx_list_t *ics_participants =
+							bctbx_list_t *ics_participants =
 							    linphone_conference_info_get_participants(conf_info_from_original_content);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 3, size_t, "%zu");
+							bctbx_list_free(ics_participants);
 
 							if (start_time > 0) {
 								BC_ASSERT_EQUAL(
@@ -11320,8 +11282,9 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 		linphone_conference_info_set_subject(conf_info, subject);
 		linphone_conference_info_set_description(conf_info, description2);
 
-		const bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
+		bctbx_list_t *ics_participants = linphone_conference_info_get_participants(conf_info);
 		BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 3, size_t, "%zu");
+		bctbx_list_free(ics_participants);
 
 		conference_scheduler = linphone_core_create_conference_scheduler(marie.getLc());
 		linphone_conference_scheduler_set_account(conference_scheduler, editing_account);
@@ -11420,9 +11383,10 @@ static void conference_cancelled_through_edit_base(bool_t server_restart) {
 							BC_ASSERT_TRUE(linphone_address_weak_equal(
 							    confAddr, linphone_conference_info_get_uri(conf_info_from_original_content)));
 
-							const bctbx_list_t *ics_participants =
+							bctbx_list_t *ics_participants =
 							    linphone_conference_info_get_participants(conf_info_from_original_content);
 							BC_ASSERT_EQUAL(bctbx_list_size(ics_participants), 0, size_t, "%zu");
+							bctbx_list_free(ics_participants);
 
 							if (start_time > 0) {
 								BC_ASSERT_EQUAL(
@@ -11519,9 +11483,9 @@ static void create_conference_with_server_restart_conference_cancelled(void) {
 static void conference_with_participant_added_outside_valid_time_slot (bool_t before_start) {
 	Focus focus("chloe_rc");
 	{//to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -11591,11 +11555,11 @@ static void conference_with_participants_added_before_start (void) {
 static void two_overlapping_conferences_base(bool_t same_organizer, bool_t dialout) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -12496,9 +12460,9 @@ static void create_simple_conference_merging_calls_base(bool_t enable_ice,
                                                         bool_t change_layout) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -13140,10 +13104,10 @@ static void create_simple_ice_conference_merging_calls(void) {
 static void create_simple_conference_with_update_deferred(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -13350,9 +13314,8 @@ static void create_simple_conference_with_update_deferred(void) {
 			const LinphoneCallParams *call_cparams = linphone_call_get_current_params(pauline_call);
 			BC_ASSERT_FALSE(linphone_call_params_video_enabled(call_cparams));
 		}
-		Address paulineIdentity(pauline.getIdentity().asAddress());
-		LinphoneCall *focus_call =
-		    linphone_core_get_call_by_remote_address2(focus.getLc(), L_GET_C_BACK_PTR(&paulineIdentity));
+		std::shared_ptr<Address> paulineIdentity = pauline.getIdentity();
+		LinphoneCall *focus_call = linphone_core_get_call_by_remote_address2(focus.getLc(), paulineIdentity->toC());
 		BC_ASSERT_PTR_NOT_NULL(focus_call);
 		if (focus_call) {
 			const LinphoneCallParams *call_lparams = linphone_call_get_params(focus_call);
@@ -13600,9 +13563,9 @@ static void create_simple_conference_with_update_deferred(void) {
 static void change_active_speaker(void) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress()); // audio only
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity()); // audio only
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		setup_conference_info_cbs(marie.getCMgr());
@@ -13862,9 +13825,9 @@ static void create_one_participant_conference_toggle_video_base(LinphoneConferen
                                                                 bool_t enable_stun) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 
@@ -14536,11 +14499,11 @@ static void one_participant_conference_toggles_video_active_speaker(void) {
 static void create_conference_with_active_call_base(bool_t dialout) {
 	Focus focus("chloe_rc");
 	{ // to make sure focus is destroyed after clients.
-		ClientConference marie("marie_rc", focus.getIdentity().asAddress());
-		ClientConference pauline("pauline_rc", focus.getIdentity().asAddress());
-		ClientConference laure("laure_tcp_rc", focus.getIdentity().asAddress());
-		ClientConference michelle("michelle_rc", focus.getIdentity().asAddress());
-		ClientConference berthe("berthe_rc", focus.getIdentity().asAddress());
+		ClientConference marie("marie_rc", focus.getIdentity());
+		ClientConference pauline("pauline_rc", focus.getIdentity());
+		ClientConference laure("laure_tcp_rc", focus.getIdentity());
+		ClientConference michelle("michelle_rc", focus.getIdentity());
+		ClientConference berthe("berthe_rc", focus.getIdentity());
 
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(pauline);
@@ -14666,8 +14629,9 @@ static void create_conference_with_active_call_base(bool_t dialout) {
 						                                           linphone_conference_info_get_organizer(info)));
 						BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
 
-						const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
+						bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
 						BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu");
+						bctbx_list_free(info_participants);
 
 						BC_ASSERT_NOT_EQUAL((long long)linphone_conference_info_get_date_time(info), 0, long long,
 						                    "%lld");
@@ -14729,10 +14693,10 @@ static void create_conference_with_active_call_base(bool_t dialout) {
 				                                           linphone_conference_info_get_organizer(info)));
 				BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
 
-				const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
-
+				bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
 				// Original participants + Marie who joined the conference
 				BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu");
+				bctbx_list_free(info_participants);
 
 				BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld");
 				const int duration_m = linphone_conference_info_get_duration(info);
@@ -14762,10 +14726,11 @@ static void create_conference_with_active_call_base(bool_t dialout) {
 					BC_ASSERT_TRUE(
 					    linphone_address_weak_equal(linphone_conference_info_get_uri(call_log_info), confAddr));
 
-					const bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
-
+					bctbx_list_t *info_participants = linphone_conference_info_get_participants(call_log_info);
 					// Original participants + Marie who joined the conference
 					BC_ASSERT_EQUAL(bctbx_list_size(info_participants), 4, size_t, "%zu");
+					bctbx_list_free(info_participants);
+
 					BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(call_log_info), 0,
 					                         long long, "%lld");
 					const int duration_m = linphone_conference_info_get_duration(call_log_info);
@@ -15093,10 +15058,10 @@ static void create_conference_with_active_call_base(bool_t dialout) {
 				                                           linphone_conference_info_get_organizer(info)));
 				BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, linphone_conference_info_get_uri(info)));
 
-				const bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
-
+				bctbx_list_t *info_participants = linphone_conference_info_get_participants(info);
 				// Original participants + Marie who joined the conference
 				BC_ASSERT_EQUAL(bctbx_list_size(info_participants), (dialout) ? 4 : 5, size_t, "%zu");
+				bctbx_list_free(info_participants);
 
 				BC_ASSERT_GREATER_STRICT((long long)linphone_conference_info_get_date_time(info), 0, long long, "%lld");
 				const int duration_m = linphone_conference_info_get_duration(info);
diff --git a/tester/log_collection_tester.c b/tester/log_collection_tester.c
index f96ff7be492b6dcf304ccdc6e8de323c3b6748c3..62405e0ed2fe0a78808312b481654d793608d9fb 100644
--- a/tester/log_collection_tester.c
+++ b/tester/log_collection_tester.c
@@ -23,25 +23,24 @@
 #endif
 #include <time.h>
 
+#ifdef __ANDROID__
+#include "android/api-level.h"
+#endif
+
 #include <bctoolbox/defs.h>
 
 #include "liblinphone_tester.h"
 #include "linphone/core.h"
 #include "tester_utils.h"
-#include <time.h>
 
 #ifdef HAVE_ZLIB
 #include <zlib.h>
 #endif
 
-#ifdef __ANDROID__
-#include "android/api-level.h"
-#endif
-
 /*getline is POSIX 2008, not available on many systems.*/
 
 /*It is declared since NDK14 unified headers, that can be detected by the presence of __ANDROID_API_O__ define*/
-#if (defined(__ANDROID__) && __ANDROID_API__ < 18) || defined(_WIN32) || defined(__QNX__)
+#if ((defined(__ANDROID__) && __ANDROID_API__ < 18) || defined(_WIN32) || defined(__QNX__))
 /* This code is public domain -- Will Hartung 4/9/09 */
 static ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
 	char *bufptr = NULL;
@@ -129,7 +128,7 @@ static LinphoneCoreManager *setup(LinphoneLogCollectionState log_collection_stat
 	return marie;
 }
 
-#if HAVE_ZLIB
+#ifdef HAVE_ZLIB
 
 /*returns uncompressed log file*/
 static FILE *gzuncompress(const char *filepath) {
@@ -187,7 +186,7 @@ static time_t check_file(BCTBX_UNUSED(LinphoneCoreManager *mgr)) {
 		time_t time_prev = 0;
 #endif
 
-#if HAVE_ZLIB
+#ifdef HAVE_ZLIB
 		// 0) if zlib is enabled, we must decompress the file first
 		file = gzuncompress(filepath);
 #else
diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp
index 1240e01e4012d541102a3b17a12ba474fb3a222d..3e2fb6fc050f335879a35c702c0f6bc1b1f28d6c 100644
--- a/tester/main-db-tester.cpp
+++ b/tester/main-db-tester.cpp
@@ -81,44 +81,49 @@ static void get_messages_count(void) {
 	MainDbProvider provider;
 	const MainDb &mainDb = provider.getMainDb();
 	BC_ASSERT_EQUAL(mainDb.getChatMessageCount(), 5157, int, "%d");
-	BC_ASSERT_EQUAL(mainDb.getChatMessageCount(ConferenceId(IdentityAddress("sip:test-3@sip.linphone.org"),
-	                                                        IdentityAddress("sip:test-1@sip.linphone.org"))),
-	                861, int, "%d");
+	BC_ASSERT_EQUAL(
+	    mainDb.getChatMessageCount(ConferenceId(Address::create("sip:test-3@sip.linphone.org")->getSharedFromThis(),
+	                                            Address::create("sip:test-1@sip.linphone.org"))),
+	    861, int, "%d");
 }
 
 static void get_unread_messages_count(void) {
 	MainDbProvider provider;
 	const MainDb &mainDb = provider.getMainDb();
 	BC_ASSERT_EQUAL(mainDb.getUnreadChatMessageCount(), 2, int, "%d");
-	BC_ASSERT_EQUAL(mainDb.getUnreadChatMessageCount(ConferenceId(IdentityAddress("sip:test-3@sip.linphone.org"),
-	                                                              IdentityAddress("sip:test-1@sip.linphone.org"))),
+	BC_ASSERT_EQUAL(mainDb.getUnreadChatMessageCount(
+	                    ConferenceId(Address::create("sip:test-3@sip.linphone.org")->getSharedFromThis(),
+	                                 Address::create("sip:test-1@sip.linphone.org"))),
 	                0, int, "%d");
 }
 
 static void get_history(void) {
 	MainDbProvider provider;
 	const MainDb &mainDb = provider.getMainDb();
+	BC_ASSERT_EQUAL(
+	    (int)mainDb
+	        .getHistoryRange(ConferenceId(Address::create("sip:test-4@sip.linphone.org")->getSharedFromThis(),
+	                                      Address::create("sip:test-1@sip.linphone.org")),
+	                         0, -1, MainDb::Filter::ConferenceChatMessageFilter)
+	        .size(),
+	    54, int, "%d");
+	BC_ASSERT_EQUAL(
+	    (int)mainDb
+	        .getHistoryRange(ConferenceId(Address::create("sip:test-7@sip.linphone.org")->getSharedFromThis(),
+	                                      Address::create("sip:test-7@sip.linphone.org")),
+	                         0, -1, MainDb::Filter::ConferenceCallFilter)
+	        .size(),
+	    0, int, "%d");
+	BC_ASSERT_EQUAL(
+	    (int)mainDb
+	        .getHistoryRange(ConferenceId(Address::create("sip:test-1@sip.linphone.org")->getSharedFromThis(),
+	                                      Address::create("sip:test-1@sip.linphone.org")),
+	                         0, -1, MainDb::Filter::ConferenceChatMessageFilter)
+	        .size(),
+	    804, int, "%d");
 	BC_ASSERT_EQUAL((int)mainDb
-	                    .getHistoryRange(ConferenceId(IdentityAddress("sip:test-4@sip.linphone.org"),
-	                                                  IdentityAddress("sip:test-1@sip.linphone.org")),
-	                                     0, -1, MainDb::Filter::ConferenceChatMessageFilter)
-	                    .size(),
-	                54, int, "%d");
-	BC_ASSERT_EQUAL((int)mainDb
-	                    .getHistoryRange(ConferenceId(IdentityAddress("sip:test-7@sip.linphone.org"),
-	                                                  IdentityAddress("sip:test-7@sip.linphone.org")),
-	                                     0, -1, MainDb::Filter::ConferenceCallFilter)
-	                    .size(),
-	                0, int, "%d");
-	BC_ASSERT_EQUAL((int)mainDb
-	                    .getHistoryRange(ConferenceId(IdentityAddress("sip:test-1@sip.linphone.org"),
-	                                                  IdentityAddress("sip:test-1@sip.linphone.org")),
-	                                     0, -1, MainDb::Filter::ConferenceChatMessageFilter)
-	                    .size(),
-	                804, int, "%d");
-	BC_ASSERT_EQUAL((int)mainDb
-	                    .getHistory(ConferenceId(IdentityAddress("sip:test-1@sip.linphone.org"),
-	                                             IdentityAddress("sip:test-1@sip.linphone.org")),
+	                    .getHistory(ConferenceId(Address::create("sip:test-1@sip.linphone.org")->getSharedFromThis(),
+	                                             Address::create("sip:test-1@sip.linphone.org")),
 	                                100, MainDb::Filter::ConferenceChatMessageFilter)
 	                    .size(),
 	                100, int, "%d");
@@ -128,7 +133,8 @@ static void get_conference_notified_events(void) {
 	MainDbProvider provider;
 	const MainDb &mainDb = provider.getMainDb();
 	list<shared_ptr<EventLog>> events = mainDb.getConferenceNotifiedEvents(
-	    ConferenceId(IdentityAddress("sip:test-44@sip.linphone.org"), IdentityAddress("sip:test-1@sip.linphone.org")),
+	    ConferenceId(Address::create("sip:test-44@sip.linphone.org")->getSharedFromThis(),
+	                 Address::create("sip:test-1@sip.linphone.org")),
 	    1);
 	BC_ASSERT_EQUAL((int)events.size(), 3, int, "%d");
 	if (events.size() != 3) return;
@@ -141,9 +147,9 @@ static void get_conference_notified_events(void) {
 	{
 		shared_ptr<ConferenceParticipantEvent> participantEvent =
 		    static_pointer_cast<ConferenceParticipantEvent>(event);
-		BC_ASSERT_TRUE(participantEvent->getConferenceId().getPeerAddress().asString() ==
+		BC_ASSERT_TRUE(participantEvent->getConferenceId().getPeerAddress()->toString() ==
 		               "sip:test-44@sip.linphone.org");
-		BC_ASSERT_TRUE(participantEvent->getParticipantAddress().asString() == "sip:test-11@sip.linphone.org");
+		BC_ASSERT_TRUE(participantEvent->getParticipantAddress()->toString() == "sip:test-11@sip.linphone.org");
 		BC_ASSERT_TRUE(participantEvent->getNotifyId() == 2);
 	}
 
@@ -152,10 +158,10 @@ static void get_conference_notified_events(void) {
 	{
 		shared_ptr<ConferenceParticipantDeviceEvent> deviceEvent =
 		    static_pointer_cast<ConferenceParticipantDeviceEvent>(event);
-		BC_ASSERT_TRUE(deviceEvent->getConferenceId().getPeerAddress().asString() == "sip:test-44@sip.linphone.org");
-		BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asString() == "sip:test-11@sip.linphone.org");
+		BC_ASSERT_TRUE(deviceEvent->getConferenceId().getPeerAddress()->toString() == "sip:test-44@sip.linphone.org");
+		BC_ASSERT_TRUE(deviceEvent->getParticipantAddress()->toString() == "sip:test-11@sip.linphone.org");
 		BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 3);
-		BC_ASSERT_TRUE(deviceEvent->getDeviceAddress().asString() == "sip:test-47@sip.linphone.org");
+		BC_ASSERT_TRUE(deviceEvent->getDeviceAddress()->toString() == "sip:test-47@sip.linphone.org");
 	}
 
 	event = *++it;
@@ -163,10 +169,10 @@ static void get_conference_notified_events(void) {
 	{
 		shared_ptr<ConferenceParticipantDeviceEvent> deviceEvent =
 		    static_pointer_cast<ConferenceParticipantDeviceEvent>(event);
-		BC_ASSERT_TRUE(deviceEvent->getConferenceId().getPeerAddress().asString() == "sip:test-44@sip.linphone.org");
-		BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asString() == "sip:test-11@sip.linphone.org");
+		BC_ASSERT_TRUE(deviceEvent->getConferenceId().getPeerAddress()->toString() == "sip:test-44@sip.linphone.org");
+		BC_ASSERT_TRUE(deviceEvent->getParticipantAddress()->toString() == "sip:test-11@sip.linphone.org");
 		BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 4);
-		BC_ASSERT_TRUE(deviceEvent->getDeviceAddress().asString() == "sip:test-47@sip.linphone.org");
+		BC_ASSERT_TRUE(deviceEvent->getDeviceAddress()->toString() == "sip:test-47@sip.linphone.org");
 	}
 }
 
diff --git a/tester/message_tester.c b/tester/message_tester.c
index 17411daf44523a7c96deb778aae824f745ff54c6..43d843d4855a389c1218e5ce3694cee342048ed9 100644
--- a/tester/message_tester.c
+++ b/tester/message_tester.c
@@ -18,9 +18,12 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "bctoolbox/crypto.h"
 #include <bctoolbox/defs.h>
+#include <bctoolbox/vfs.h>
+
+#include <belle-sip/object.h>
 
-#include "bctoolbox/crypto.h"
 #include "liblinphone_tester.h"
 #include "lime.h"
 #include "linphone/core.h"
@@ -28,8 +31,6 @@
 #include "linphone/wrapper_utils.h"
 #include "shared_tester_functions.h"
 #include "tester_utils.h"
-#include <bctoolbox/vfs.h>
-#include <belle-sip/object.h>
 
 #ifdef _MSC_VER
 #pragma warning(disable : 4996)
diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp
index cba0bf61a48a0cc232158beb5641133d950f5263..574576622f58b15d138c24480c08ecaa7dbdce8e 100644
--- a/tester/multipart-tester.cpp
+++ b/tester/multipart-tester.cpp
@@ -144,10 +144,10 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer,
 	LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc");
 
 	char *paulineUriStr = linphone_address_as_string_uri_only(pauline->identity);
-	IdentityAddress paulineAddress(paulineUriStr);
+	std::shared_ptr<Address> paulineAddress = Address::create(paulineUriStr);
 	bctbx_free(paulineUriStr);
 	char *marieUri = linphone_address_as_string_uri_only(marie->identity);
-	IdentityAddress marieAddress(marieUri);
+	std::shared_ptr<Address> marieAddress = Address::create(marieUri);
 	bctbx_free(marieUri);
 	shared_ptr<AbstractChatRoom> marieRoom = marie->lc->cppPtr->getOrCreateBasicChatRoom(marieAddress, paulineAddress);
 	marieRoom->allowMultipart(true);
diff --git a/tester/presence_tester.c b/tester/presence_tester.c
index 604a9ca8f927dea392cf2f7886e05a067f84b0bf..ed5d0eb37215d0b51875c749e387ae7559490ef8 100644
--- a/tester/presence_tester.c
+++ b/tester/presence_tester.c
@@ -59,7 +59,6 @@ static bool_t subscribe_to_callee_presence(LinphoneCoreManager *caller_mgr, Linp
 	linphone_friend_cbs_unref(cbs);
 
 	linphone_core_add_friend(caller_mgr->lc, friend);
-
 	result = wait_for(caller_mgr->lc, callee_mgr->lc, &caller_mgr->stat.number_of_LinphonePresenceActivityOnline,
 	                  initial_caller.number_of_LinphonePresenceActivityOnline + 1);
 	/*without proxy, callee cannot subscribe to caller
diff --git a/tester/proxy_config_tester.c b/tester/proxy_config_tester.c
index 286aecedd5c0078cff9ea3f849ca2088e9565b76..7d85b0e9b65d351a8bce017ba007be045885f510 100644
--- a/tester/proxy_config_tester.c
+++ b/tester/proxy_config_tester.c
@@ -298,6 +298,8 @@ static void multiple_route(void) {
 
 	linphone_proxy_config_set_routes(marie_cfg, new_routes);
 
+	bctbx_list_free_with_data(new_routes, bctbx_free);
+
 	const bctbx_list_t *routes = linphone_proxy_config_get_routes(marie_cfg);
 	BC_ASSERT_PTR_NOT_NULL(routes);
 	BC_ASSERT_EQUAL((int)bctbx_list_size(routes), 2, int, "%d"); // 2 are good, 2 are bad
diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c
index 76c054ad35daf35cb890d92610a66e5769e709d2..a2a1c2dec2020287c684c716af8426b2452ea067 100644
--- a/tester/quality_reporting_tester.c
+++ b/tester/quality_reporting_tester.c
@@ -149,8 +149,14 @@ static void quality_reporting_not_used_without_config(void) {
 
 	if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) {
 		// Marie has stats collection enabled but Pauline has not
-		BC_ASSERT_TRUE(linphone_proxy_config_quality_reporting_enabled(linphone_call_get_dest_proxy(call_marie)));
-		BC_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(linphone_call_get_dest_proxy(call_pauline)));
+
+		const LinphoneAccount *marie_account = linphone_call_get_dest_account(call_marie);
+		const LinphoneAccountParams *marie_account_params = linphone_account_get_params(marie_account);
+		BC_ASSERT_TRUE(linphone_account_params_quality_reporting_enabled(marie_account_params));
+
+		const LinphoneAccount *pauline_account = linphone_call_get_dest_account(call_pauline);
+		const LinphoneAccountParams *pauline_account_params = linphone_account_get_params(pauline_account);
+		BC_ASSERT_FALSE(linphone_account_params_quality_reporting_enabled(pauline_account_params));
 
 		// This field should be already filled
 		quality_reports = linphone_quality_reporting_get_reports(
@@ -291,10 +297,11 @@ static void quality_reporting_interval_report(void) {
 
 	if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) {
 		linphone_reporting_set_on_report_send(call_marie, on_report_send_mandatory);
-		LinphoneProxyConfig *config = linphone_call_get_dest_proxy(call_marie);
-		linphone_proxy_config_edit(config);
-		linphone_proxy_config_set_quality_reporting_interval(config, 1);
-		linphone_proxy_config_done(config);
+		LinphoneAccount *account = linphone_call_get_dest_account(call_marie);
+		LinphoneAccountParams *account_params = linphone_account_params_clone(linphone_account_get_params(account));
+		linphone_account_params_set_quality_reporting_interval(account_params, 1);
+		linphone_account_set_params(account, account_params);
+		linphone_account_params_unref(account_params);
 
 		BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc));
 		BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc));
@@ -429,10 +436,11 @@ static void quality_reporting_interval_report_video_and_rtt_base(bool_t enable_v
 	if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, marie_params,
 	                                            pauline_params)) {
 		linphone_reporting_set_on_report_send(call_marie, on_report_send_mandatory);
-		LinphoneProxyConfig *config = linphone_call_get_dest_proxy(call_marie);
-		linphone_proxy_config_edit(config);
-		linphone_proxy_config_set_quality_reporting_interval(config, 3);
-		linphone_proxy_config_done(config);
+		LinphoneAccount *account = linphone_call_get_dest_account(call_marie);
+		LinphoneAccountParams *account_params = linphone_account_params_clone(linphone_account_get_params(account));
+		linphone_account_params_set_quality_reporting_interval(account_params, 3);
+		linphone_account_set_params(account, account_params);
+		linphone_account_params_unref(account_params);
 
 		BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, NULL, 0, 3000));
 		BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(call_pauline)) ==
diff --git a/tester/remote-provisioning-tester.cpp b/tester/remote-provisioning-tester.cpp
index f5ff95b803ea6338070059c707faef6a8bffedbc..4dd89abb9ef26077b312e536077b4f651b88b42e 100644
--- a/tester/remote-provisioning-tester.cpp
+++ b/tester/remote-provisioning-tester.cpp
@@ -20,11 +20,11 @@
 
 #include "bctoolbox/defs.h"
 
+#include "c-wrapper/c-wrapper.h"
 #include "liblinphone_tester.h"
 #include "linphone/core.h"
-#include "tester_utils.h"
-
 #include "private_functions.h"
+#include "tester_utils.h"
 
 #ifdef HAVE_FLEXIAPI
 #include "linphone/FlexiAPIClient.hh"
diff --git a/tester/shared_tester_functions.cpp b/tester/shared_tester_functions.cpp
index 0cc198cdde6a83240ef856aea846cd7d64dcb986..3ef4e00caee9383a983bf39ccb80f604917c0d25 100644
--- a/tester/shared_tester_functions.cpp
+++ b/tester/shared_tester_functions.cpp
@@ -705,7 +705,7 @@ void linphone_conference_info_check_participant(const LinphoneConferenceInfo *co
                                                 LinphoneAddress *address,
                                                 int sequence_number) {
 	const auto &sequence = LinphonePrivate::ConferenceInfo::toCpp(conference_info)
-	                           ->getParticipantParam(*L_GET_CPP_PTR_FROM_C_OBJECT(address), "X-SEQ");
+	                           ->getParticipantParam(Address::toCpp(address)->getSharedFromThis(), "X-SEQ");
 	BC_ASSERT_TRUE(!sequence.empty());
 	if (!sequence.empty()) {
 		const int sequenceNumber = std::atoi(sequence.c_str());
diff --git a/tester/tester.c b/tester/tester.c
index bb6544f07f0a9dd67e17600ebeb845d7aaf5d0c4..ee97e6ea8899c56377f6d18e7f7cf85592adec1a 100644
--- a/tester/tester.c
+++ b/tester/tester.c
@@ -18,20 +18,21 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "belle-sip/sipstack.h"
-#include "liblinphone_tester.h"
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <bctoolbox/defs.h>
+#include <bctoolbox/tester.h>
+#include <bctoolbox/vfs.h>
+
+#include "belle-sip/sipstack.h"
 
+#include "liblinphone_tester.h"
 #include "linphone/core.h"
 #include "linphone/logging.h"
 #include "logging-private.h"
 #include "shared_tester_functions.h"
 #include "tester_utils.h"
-#include <bctoolbox/tester.h>
-#include <bctoolbox/vfs.h>
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -1219,6 +1220,7 @@ static void check_participant_added_to_conference(bctbx_list_t *lcs,
 				LinphoneAddress *m_uri = linphone_address_new(linphone_core_get_identity(m->lc));
 				LinphoneConference *remote_conference =
 				    linphone_core_search_conference(m->lc, NULL, m_uri, local_conference_address, NULL);
+				BC_ASSERT_PTR_NOT_NULL(remote_conference);
 				linphone_address_unref(m_uri);
 				int no_participants =
 				    (int)bctbx_list_size(participants) + 1 - (linphone_conference_is_in(conference) ? 1 : 2);
@@ -3159,6 +3161,7 @@ void messages_received(LinphoneCore *lc, BCTBX_UNUSED(LinphoneChatRoom *room), c
 	int count = (int)bctbx_list_size(messages);
 	counters->number_of_LinphoneAggregatedMessagesReceived += count;
 }
+
 void message_received(LinphoneCore *lc, BCTBX_UNUSED(LinphoneChatRoom *room), LinphoneChatMessage *msg) {
 	char *from = linphone_address_as_string(linphone_chat_message_get_from_address(msg));
 	stats *counters;
diff --git a/tester/vcard_tester.c b/tester/vcard_tester.c
index 69e90d597a806e221ba848c8ebc10a55a0888697..88930019c05713ae1e30948197f93b2ecf74add1 100644
--- a/tester/vcard_tester.c
+++ b/tester/vcard_tester.c
@@ -18,18 +18,17 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <bctoolbox/defs.h>
-
-#include "linphone/core.h"
-
 #ifdef VCARD_ENABLED
+#include <time.h>
+
+#include <bctoolbox/defs.h>
+#include <bctoolbox/map.h>
 
 #include "carddav.h"
 #include "liblinphone_tester.h"
+#include "linphone/core.h"
 #include "tester_utils.h"
-#include <bctoolbox/map.h>
 
-#include <time.h>
 #define CARDDAV_SERVER "http://dav.example.org/baikal/html/card.php/addressbooks/tester/default"
 #define ME_VCF "http://dav.example.org/baikal/html/card.php/addressbooks/tester/default/me.vcf"
 #define ME_VCF_2 "/baikal/html/card.php/addressbooks/tester/default/me.vcf"
diff --git a/tester/wrapper_cpp_tester.cpp b/tester/wrapper_cpp_tester.cpp
index eefaa992934f01554d75613c3fc401edb26e697b..df6337bf552d8077286f6fe055765f549bf5c227 100644
--- a/tester/wrapper_cpp_tester.cpp
+++ b/tester/wrapper_cpp_tester.cpp
@@ -17,14 +17,12 @@
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
-
 #include <fstream>
 #include <iostream>
 #include <list>
 
-#include <linphone++/linphone.hh>
-
 #include "bctoolbox/logging.h"
+
 #include "c-wrapper/c-wrapper.h"
 #include "c-wrapper/internal/c-tools.h"
 #include "liblinphone_tester.h"
@@ -32,6 +30,7 @@
 #include "linphone/wrapper_utils.h"
 #include "payload-type/payload-type.h"
 #include "tester_utils.h"
+#include <linphone++/linphone.hh>
 
 static void create_chat_room() {
 	// Init from C
diff --git a/tools/xml2lpc_test.c b/tools/xml2lpc_test.c
index 2b95b8a4218c1ed448270a0b3ef1f5b26d43a36a..579221370d68a164c3fba4ba778c92f8b2fb6f3d 100644
--- a/tools/xml2lpc_test.c
+++ b/tools/xml2lpc_test.c
@@ -23,7 +23,6 @@
 #include "bctoolbox/defs.h"
 
 #include "xml2lpc.h"
-#include <stdio.h>
 
 void cb_function(BCTBX_UNUSED(void *ctx), xml2lpc_log_level level, const char *msg, va_list list) {
 	const char *header = "";