From c31c49bef36fae9c767df513b22970df1c8d6817 Mon Sep 17 00:00:00 2001
From: Simon Morlat <simon.morlat@linphone.org>
Date: Fri, 6 Oct 2023 16:10:53 +0200
Subject: [PATCH] Add new video codec priority policy, that gives preference to
 hardware codecs on mobile platforms, in order to preserve battery and improve
 framerate.

---
 coreapi/linphonecore.c                        | 130 +++++++++------
 coreapi/quality_reporting.c                   |  33 ++--
 coreapi/tester_utils.h                        |   2 +
 coreapi/update_check.c                        |   6 +-
 daemon/commands/audio-codec-get.cc            |  14 +-
 daemon/commands/audio-codec-move.cc           |  22 +--
 daemon/commands/audio-codec-set.cc            |  42 +++--
 daemon/commands/audio-codec-toggle.cc         |  15 +-
 daemon/daemon.cc                              |  55 ++++---
 daemon/daemon.h                               |   9 +-
 include/CMakeLists.txt                        |   1 +
 include/linphone/api/c-alert.h                |   3 +-
 include/linphone/api/c-payload-type.h         |  10 ++
 include/linphone/api/c-signal-information.h   |   3 +-
 include/linphone/api/c-types.h                |  96 +----------
 include/linphone/call_params.h                |  37 +----
 include/linphone/core.h                       |  46 ++++--
 include/linphone/enums/c-enums.h              | 139 ++++++++++++++++
 src/c-wrapper/api/c-account.cpp               |   4 +-
 src/c-wrapper/api/c-call-params.cpp           |  27 +--
 src/c-wrapper/api/c-chat-message.cpp          |   2 +-
 src/c-wrapper/api/c-core.cpp                  |  40 +++--
 src/c-wrapper/api/c-payload-type.cpp          |  10 ++
 src/c-wrapper/c-wrapper.h                     |   2 -
 .../params/media-session-params-p.h           |  18 +-
 .../params/media-session-params.cpp           |  24 +--
 src/conference/params/media-session-params.h  |  14 +-
 src/conference/session/audio-mixer.cpp        |   5 +-
 src/conference/session/ms2-stream.cpp         |   6 +-
 src/conference/session/streams-group.cpp      |   2 +-
 src/conference/session/streams.h              |   2 +-
 src/conference/session/video-mixer.cpp        |   4 +-
 src/core/core-p.h                             |   3 +
 src/core/core.cpp                             |  65 ++++++++
 src/core/core.h                               |   3 +
 src/payload-type/payload-type.cpp             |  11 ++
 src/payload-type/payload-type.h               |   2 +
 src/sal/offeranswer.cpp                       |   9 +
 src/signal-information/signal-information.h   |   1 +
 src/utils/payload-type-handler.h              |   1 +
 tester/audio_bypass_tester.c                  |   5 +-
 tester/call_single_tester.c                   |   4 +-
 tester/local_conference_tester_functions.cpp  |  14 +-
 tester/offeranswer_tester.cpp                 | 154 ++++++++++++++++--
 tester/session_timers_tester.c                |   4 +-
 45 files changed, 719 insertions(+), 380 deletions(-)
 create mode 100644 include/linphone/enums/c-enums.h

diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index c190f2f50a..26795f7053 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -1943,7 +1943,10 @@ static void sip_config_read(LinphoneCore *lc) {
 	lc->sal->useDates(!!linphone_config_get_int(lc->config, "sip", "put_date", 0));
 	lc->sal->enableSipUpdateMethod(!!linphone_config_get_int(lc->config, "sip", "sip_update", 1));
 	lc->sip_conf.vfu_with_info = !!linphone_config_get_int(lc->config, "sip", "vfu_with_info", 1);
-	linphone_core_set_sip_transport_timeout(lc, linphone_config_get_int(lc->config, "sip", "transport_timeout", 63000));
+	/* The linux kernel TCP connection timeout is 63 seconds, which is fairly long.
+	 * We decide that 15 seconds is long enough to connect to a single node, given that we want
+	 * to switch to alternate nodes provided in the SRV records within a reasonnable timeframe.*/
+	linphone_core_set_sip_transport_timeout(lc, linphone_config_get_int(lc->config, "sip", "transport_timeout", 15000));
 	lc->sal->setSupportedTags(
 	    linphone_config_get_string(lc->config, "sip", "supported", "replaces, outbound, gruu, path"));
 	LinphoneSupportLevel level_100rel = linphone_core_get_tag_100rel_support_level(lc);
@@ -2038,14 +2041,14 @@ static void rtp_config_read(LinphoneCore *lc) {
 		linphone_core_enable_video_multicast(lc, !!tmp_int);
 }
 
-static PayloadType *find_payload(
+static OrtpPayloadType *find_payload(
     const bctbx_list_t *default_list, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp) {
-	PayloadType *candidate = NULL;
-	PayloadType *it;
+	OrtpPayloadType *candidate = NULL;
+	OrtpPayloadType *it;
 	const bctbx_list_t *elem;
 
 	for (elem = default_list; elem != NULL; elem = elem->next) {
-		it = (PayloadType *)elem->data;
+		it = (OrtpPayloadType *)elem->data;
 		if (it != NULL && strcasecmp(mime_type, it->mime_type) == 0 &&
 		    (clock_rate == it->clock_rate || clock_rate <= 0) && (channels == it->channels || channels <= 0)) {
 			if ((recv_fmtp && it->recv_fmtp && strstr(recv_fmtp, it->recv_fmtp) != NULL) ||
@@ -2066,10 +2069,11 @@ static PayloadType *find_payload(
 	return candidate;
 }
 
-static PayloadType *find_payload_type_from_list(const char *type, int rate, int channels, const bctbx_list_t *from) {
+static OrtpPayloadType *
+find_payload_type_from_list(const char *type, int rate, int channels, const bctbx_list_t *from) {
 	const bctbx_list_t *elem;
 	for (elem = from; elem != NULL; elem = elem->next) {
-		PayloadType *pt = (PayloadType *)elem->data;
+		OrtpPayloadType *pt = (OrtpPayloadType *)elem->data;
 		if ((strcasecmp(type, payload_type_get_mime(pt)) == 0) &&
 		    (rate == LINPHONE_FIND_PAYLOAD_IGNORE_RATE || rate == pt->clock_rate) &&
 		    (channels == LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS || channels == pt->channels)) {
@@ -2098,11 +2102,11 @@ static bool_t linphone_core_codec_supported(LinphoneCore *lc, SalStreamType type
 	return ms_factory_codec_supported(lc->factory, mime);
 }
 
-static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, PayloadType **ret) {
+static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, OrtpPayloadType **ret) {
 	char codeckey[50];
 	const char *mime, *fmtp;
 	int rate, channels, enabled, bitrate;
-	PayloadType *pt;
+	OrtpPayloadType *pt;
 	LpConfig *config = lc->config;
 
 	*ret = NULL;
@@ -2151,7 +2155,7 @@ static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, Payload
 	return TRUE;
 }
 
-static SalStreamType payload_type_get_stream_type(const PayloadType *pt) {
+static SalStreamType payload_type_get_stream_type(const OrtpPayloadType *pt) {
 	switch (pt->type) {
 		case PAYLOAD_AUDIO_PACKETIZED:
 		case PAYLOAD_AUDIO_CONTINUOUS:
@@ -2172,12 +2176,12 @@ static SalStreamType payload_type_get_stream_type(const PayloadType *pt) {
  * the supported codecs are added automatically. This 'l' list is entirely rewritten.*/
 static bctbx_list_t *add_missing_supported_codecs(LinphoneCore *lc, const bctbx_list_t *default_list, bctbx_list_t *l) {
 	const bctbx_list_t *elem;
-	::PayloadType *last_seen = NULL;
+	OrtpPayloadType *last_seen = NULL;
 
 	for (elem = default_list; elem != NULL; elem = elem->next) {
 		bctbx_list_t *elem2 = bctbx_list_find(l, elem->data);
 		if (!elem2) {
-			PayloadType *pt = (PayloadType *)elem->data;
+			OrtpPayloadType *pt = (OrtpPayloadType *)elem->data;
 			/*this codec from default list should be inserted in the list, with respect to the default_list order*/
 
 			if (!linphone_core_codec_supported(lc, payload_type_get_stream_type(pt), pt->mime_type)) continue;
@@ -2191,7 +2195,7 @@ static bctbx_list_t *add_missing_supported_codecs(LinphoneCore *lc, const bctbx_
 			ms_message("Supported codec %s/%i fmtp=%s automatically added to codec list.", pt->mime_type,
 			           pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : "");
 		} else {
-			last_seen = (PayloadType *)elem2->data;
+			last_seen = (OrtpPayloadType *)elem2->data;
 		}
 	}
 	return l;
@@ -2223,10 +2227,10 @@ handle_missing_codecs(LinphoneCore *lc, const bctbx_list_t *default_list, bctbx_
 	return l;
 }
 
-static bctbx_list_t *codec_append_if_new(bctbx_list_t *l, PayloadType *pt) {
+static bctbx_list_t *codec_append_if_new(bctbx_list_t *l, OrtpPayloadType *pt) {
 	bctbx_list_t *elem;
 	for (elem = l; elem != NULL; elem = elem->next) {
-		PayloadType *ept = (PayloadType *)elem->data;
+		OrtpPayloadType *ept = (OrtpPayloadType *)elem->data;
 		if (pt == ept) return l;
 	}
 	l = bctbx_list_append(l, pt);
@@ -2235,10 +2239,12 @@ static bctbx_list_t *codec_append_if_new(bctbx_list_t *l, PayloadType *pt) {
 
 static void codecs_config_read(LinphoneCore *lc) {
 	int i;
-	PayloadType *pt;
+	OrtpPayloadType *pt;
 	bctbx_list_t *audio_codecs = NULL;
 	bctbx_list_t *video_codecs = NULL;
 	bctbx_list_t *text_codecs = NULL;
+	int videoCodecsPriorityPolicy =
+	    linphone_config_get_int(linphone_core_get_config(lc), "video", "codec_priority_policy", -1);
 
 	lc->codecs_conf.dyn_pt = 96;
 
@@ -2261,6 +2267,17 @@ static void codecs_config_read(LinphoneCore *lc) {
 			video_codecs = codec_append_if_new(video_codecs, pt);
 		}
 	}
+	if (videoCodecsPriorityPolicy == -1) {
+		if (video_codecs != NULL) {
+			/* videoCodecsPriorityPolicy is unset, but there are video codecs listed in the configuration.
+			 * For backward compatibility, then force the priority policy to be LinphoneCodecPriorityPolicyBasic.
+			 */
+			videoCodecsPriorityPolicy = LinphoneCodecPriorityPolicyBasic;
+		} else {
+			/* Otherwise, the default is LinphoneCodecPriorityPolicyAuto */
+			videoCodecsPriorityPolicy = LinphoneCodecPriorityPolicyAuto;
+		}
+	}
 
 	video_codecs = handle_missing_codecs(lc, lc->default_video_codecs, video_codecs, MSVideo);
 
@@ -2275,6 +2292,7 @@ static void codecs_config_read(LinphoneCore *lc) {
 	linphone_core_set_video_codecs(lc, video_codecs);
 	linphone_core_set_text_codecs(lc, text_codecs);
 	linphone_core_update_allocated_audio_bandwidth(lc);
+	linphone_core_set_video_codec_priority_policy(lc, (LinphoneCodecPriorityPolicy)videoCodecsPriorityPolicy);
 }
 
 static void build_video_devices_table(LinphoneCore *lc) {
@@ -2485,13 +2503,13 @@ const char *linphone_core_get_version(void) {
 }
 
 static void linphone_core_register_payload_type(LinphoneCore *lc,
-                                                const PayloadType *const_pt,
+                                                const OrtpPayloadType *const_pt,
                                                 const char *recv_fmtp,
                                                 bool_t enabled) {
 	bctbx_list_t **codec_list = const_pt->type == PAYLOAD_VIDEO  ? &lc->default_video_codecs
 	                            : const_pt->type == PAYLOAD_TEXT ? &lc->default_text_codecs
 	                                                             : &lc->default_audio_codecs;
-	PayloadType *pt = payload_type_clone(const_pt);
+	OrtpPayloadType *pt = payload_type_clone(const_pt);
 	int number = -1;
 	payload_type_set_enable(pt, enabled);
 	if (recv_fmtp != NULL) payload_type_set_recv_fmtp(pt, recv_fmtp);
@@ -2509,7 +2527,7 @@ static void linphone_core_register_static_payloads(LinphoneCore *lc) {
 	RtpProfile *prof = &av_profile;
 	int i;
 	for (i = 0; i < RTP_PROFILE_MAX_PAYLOADS; ++i) {
-		PayloadType *pt = rtp_profile_get_payload(prof, i);
+		OrtpPayloadType *pt = rtp_profile_get_payload(prof, i);
 		if (pt) {
 #ifndef VIDEO_ENABLED
 			if (pt->type == PAYLOAD_VIDEO) continue;
@@ -7772,43 +7790,47 @@ int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, r
 }
 
 void _linphone_core_codec_config_write(LinphoneCore *lc) {
-	if (linphone_core_ready(lc)) {
-		PayloadType *pt;
-		codecs_config_t *config = &lc->codecs_conf;
-		bctbx_list_t *node;
-		char key[50];
-		int index;
-		index = 0;
-		for (node = config->audio_codecs; node != NULL; node = bctbx_list_next(node)) {
-			pt = (PayloadType *)(node->data);
-			sprintf(key, "audio_codec_%i", index);
-			linphone_config_set_string(lc->config, key, "mime", pt->mime_type);
-			linphone_config_set_int(lc->config, key, "rate", pt->clock_rate);
-			if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE)
-				linphone_config_set_int(lc->config, key, "bitrate", pt->normal_bitrate);
-			linphone_config_set_int(lc->config, key, "channels", pt->channels);
-			linphone_config_set_int(lc->config, key, "enabled", payload_type_enabled(pt));
-			linphone_config_set_string(lc->config, key, "recv_fmtp", pt->recv_fmtp);
-			index++;
-		}
+	OrtpPayloadType *pt;
+	codecs_config_t *config = &lc->codecs_conf;
+	bctbx_list_t *node;
+	char key[50];
+	int index;
+
+	if (!linphone_core_ready(lc)) return;
+
+	linphone_config_set_int(lc->config, "video", "codec_priority_policy",
+	                        linphone_core_get_video_codec_priority_policy(lc));
+
+	index = 0;
+	for (node = config->audio_codecs; node != NULL; node = bctbx_list_next(node)) {
+		pt = (OrtpPayloadType *)(node->data);
 		sprintf(key, "audio_codec_%i", index);
-		linphone_config_clean_section(lc->config, key);
-
-		index = 0;
-		for (node = config->video_codecs; node != NULL; node = bctbx_list_next(node)) {
-			pt = (PayloadType *)(node->data);
-			sprintf(key, "video_codec_%i", index);
-			linphone_config_set_string(lc->config, key, "mime", pt->mime_type);
-			linphone_config_set_int(lc->config, key, "rate", pt->clock_rate);
-			if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE)
-				linphone_config_set_int(lc->config, key, "bitrate", pt->normal_bitrate);
-			linphone_config_set_int(lc->config, key, "enabled", payload_type_enabled(pt));
-			linphone_config_set_string(lc->config, key, "recv_fmtp", pt->recv_fmtp);
-			index++;
-		}
+		linphone_config_set_string(lc->config, key, "mime", pt->mime_type);
+		linphone_config_set_int(lc->config, key, "rate", pt->clock_rate);
+		if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE)
+			linphone_config_set_int(lc->config, key, "bitrate", pt->normal_bitrate);
+		linphone_config_set_int(lc->config, key, "channels", pt->channels);
+		linphone_config_set_int(lc->config, key, "enabled", payload_type_enabled(pt));
+		linphone_config_set_string(lc->config, key, "recv_fmtp", pt->recv_fmtp);
+		index++;
+	}
+	sprintf(key, "audio_codec_%i", index);
+	linphone_config_clean_section(lc->config, key);
+
+	index = 0;
+	for (node = config->video_codecs; node != NULL; node = bctbx_list_next(node)) {
+		pt = (OrtpPayloadType *)(node->data);
 		sprintf(key, "video_codec_%i", index);
-		linphone_config_clean_section(lc->config, key);
-	}
+		linphone_config_set_string(lc->config, key, "mime", pt->mime_type);
+		linphone_config_set_int(lc->config, key, "rate", pt->clock_rate);
+		if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE)
+			linphone_config_set_int(lc->config, key, "bitrate", pt->normal_bitrate);
+		linphone_config_set_int(lc->config, key, "enabled", payload_type_enabled(pt));
+		linphone_config_set_string(lc->config, key, "recv_fmtp", pt->recv_fmtp);
+		index++;
+	}
+	sprintf(key, "video_codec_%i", index);
+	linphone_config_clean_section(lc->config, key);
 }
 
 static void codecs_config_uninit(LinphoneCore *lc) {
diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c
index 44b85ed0a8..fe434f4089 100644
--- a/coreapi/quality_reporting.c
+++ b/coreapi/quality_reporting.c
@@ -547,8 +547,8 @@ void linphone_reporting_update_ip(LinphoneCall *call) {
 
 void linphone_reporting_update_media_info(LinphoneCall *call, int stats_type) {
 	MediaStream *stream = NULL;
-	const ::PayloadType *local_payload = NULL;
-	const ::PayloadType *remote_payload = NULL;
+	const LinphonePayloadType *local_payload = NULL;
+	const LinphonePayloadType *remote_payload = NULL;
 	const LinphoneCallParams *current_params = linphone_call_get_current_params(call);
 	std::shared_ptr<CallLog> log = Call::toCpp(call)->getLog();
 	reporting_session_report_t *report = log->getQualityReporting()->reports[stats_type];
@@ -595,15 +595,15 @@ void linphone_reporting_update_media_info(LinphoneCall *call, int stats_type) {
 	/*yet we use the same payload config for local and remote, since this is the largest use case*/
 	if (stats_type == LINPHONE_CALL_STATS_AUDIO && Call::toCpp(call)->getMediaStream(LinphoneStreamTypeAudio)) {
 		stream = Call::toCpp(call)->getMediaStream(LinphoneStreamTypeAudio);
-		local_payload = linphone_call_params_get_used_audio_codec(current_params);
+		local_payload = linphone_call_params_get_used_audio_payload_type(current_params);
 		remote_payload = local_payload;
 	} else if (stats_type == LINPHONE_CALL_STATS_VIDEO && Call::toCpp(call)->getMediaStream(LinphoneStreamTypeVideo)) {
 		stream = Call::toCpp(call)->getMediaStream(LinphoneStreamTypeVideo);
-		local_payload = linphone_call_params_get_used_video_codec(current_params);
+		local_payload = linphone_call_params_get_used_video_payload_type(current_params);
 		remote_payload = local_payload;
 	} else if (stats_type == LINPHONE_CALL_STATS_TEXT && Call::toCpp(call)->getMediaStream(LinphoneStreamTypeText)) {
 		stream = Call::toCpp(call)->getMediaStream(LinphoneStreamTypeText);
-		local_payload = linphone_call_params_get_used_text_codec(current_params);
+		local_payload = linphone_call_params_get_used_text_payload_type(current_params);
 		remote_payload = local_payload;
 	}
 
@@ -628,19 +628,22 @@ void linphone_reporting_update_media_info(LinphoneCall *call, int stats_type) {
 	STR_REASSIGN(report->dialog_id, ms_strdup_printf("%s;%u", dialogId.c_str(), report->info.local_addr.ssrc));
 
 	if (local_payload != NULL) {
-		report->local_metrics.session_description.payload_type = local_payload->type;
-		if (local_payload->mime_type != NULL)
-			STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type));
-		report->local_metrics.session_description.sample_rate = local_payload->clock_rate;
-		if (local_payload->recv_fmtp != NULL)
-			STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp));
+		report->local_metrics.session_description.payload_type = linphone_payload_type_get_type(local_payload);
+		STR_REASSIGN(report->local_metrics.session_description.payload_desc,
+		             ms_strdup(linphone_payload_type_get_mime_type(local_payload)));
+		report->local_metrics.session_description.sample_rate = linphone_payload_type_get_clock_rate(local_payload);
+		if (linphone_payload_type_get_recv_fmtp(local_payload) != NULL)
+			STR_REASSIGN(report->local_metrics.session_description.fmtp,
+			             ms_strdup(linphone_payload_type_get_recv_fmtp(local_payload)));
 	}
 
 	if (remote_payload != NULL) {
-		report->remote_metrics.session_description.payload_type = remote_payload->type;
-		STR_REASSIGN(report->remote_metrics.session_description.payload_desc, ms_strdup(remote_payload->mime_type));
-		report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate;
-		STR_REASSIGN(report->remote_metrics.session_description.fmtp, ms_strdup(remote_payload->recv_fmtp));
+		report->remote_metrics.session_description.payload_type = linphone_payload_type_get_type(remote_payload);
+		STR_REASSIGN(report->remote_metrics.session_description.payload_desc,
+		             ms_strdup(linphone_payload_type_get_mime_type(remote_payload)));
+		report->remote_metrics.session_description.sample_rate = linphone_payload_type_get_clock_rate(remote_payload);
+		STR_REASSIGN(report->remote_metrics.session_description.fmtp,
+		             ms_strdup(linphone_payload_type_get_recv_fmtp(remote_payload)));
 	}
 }
 
diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h
index 537ed2bfb4..8a127130bf 100644
--- a/coreapi/tester_utils.h
+++ b/coreapi/tester_utils.h
@@ -391,6 +391,8 @@ LINPHONE_PUBLIC bool_t linphone_tunnel_is_tunnel_rtp_transport(const LinphoneTun
 LINPHONE_PUBLIC void linphone_config_simulate_crash_during_sync(LinphoneConfig *lpconfig, bool_t value);
 LINPHONE_PUBLIC void linphone_config_simulate_read_failure(bool_t value);
 
+LINPHONE_PUBLIC void linphone_payload_type_set_priority_bonus(LinphonePayloadType *pt, bool_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/coreapi/update_check.c b/coreapi/update_check.c
index 3862076058..ae65f9a944 100644
--- a/coreapi/update_check.c
+++ b/coreapi/update_check.c
@@ -129,10 +129,10 @@ void linphone_core_check_for_update(LinphoneCore *lc, const char *current_versio
 		belle_generic_uri_t *uri;
 		char *version_check_url;
 		LinphoneUpdateCheck *update;
-		MSList *item;
-		MSList *platform_tags = ms_factory_get_platform_tags(linphone_core_get_ms_factory(lc));
+		bctbx_list_t *item;
+		bctbx_list_t *platform_tags = ms_factory_get_platform_tags(linphone_core_get_ms_factory(lc));
 
-		for (item = platform_tags; item != NULL; item = ms_list_next(item)) {
+		for (item = platform_tags; item != NULL; item = item->next) {
 			const char *tag = (const char *)item->data;
 			if (strcmp(tag, "win32") == 0) platform = "windows";
 			else if (strcmp(tag, "apple") == 0) platform = "macosx";
diff --git a/daemon/commands/audio-codec-get.cc b/daemon/commands/audio-codec-get.cc
index 03cc045a29..d6f66416c3 100644
--- a/daemon/commands/audio-codec-get.cc
+++ b/daemon/commands/audio-codec-get.cc
@@ -56,7 +56,7 @@ void AudioCodecGetCommand::exec(Daemon *app, const string &args) {
 	bool found = false;
 	istringstream ist(args);
 	ostringstream ost;
-	PayloadType *pt = NULL;
+	LinphonePayloadType *pt = NULL;
 
 	if (ist.peek() == EOF) {
 		found = list = true;
@@ -68,26 +68,28 @@ void AudioCodecGetCommand::exec(Daemon *app, const string &args) {
 			app->sendResponse(Response("Incorrect mime type format.", Response::Error));
 			return;
 		}
-		pt = parser.getPayloadType();
+		if (parser.getPayloadType()) pt = linphone_payload_type_ref(parser.getPayloadType());
 	}
 
 	int index = 0;
-	for (const bctbx_list_t *node = linphone_core_get_audio_codecs(app->getCore()); node != NULL;
-	     node = bctbx_list_next(node)) {
-		PayloadType *payload = reinterpret_cast<PayloadType *>(node->data);
+	bctbx_list_t *payloadTypes = linphone_core_get_audio_payload_types(app->getCore());
+	for (const bctbx_list_t *node = payloadTypes; node != NULL; node = bctbx_list_next(node)) {
+		LinphonePayloadType *payload = static_cast<LinphonePayloadType *>(node->data);
 		if (list) {
 			ost << PayloadTypeResponse(app->getCore(), payload, index).getBody() << "\n";
-		} else if (pt == payload) {
+		} else if (pt && linphone_payload_type_weak_equals(pt, payload)) {
 			ost << PayloadTypeResponse(app->getCore(), payload, index).getBody();
 			found = true;
 			break;
 		}
 		++index;
 	}
+	bctbx_list_free_with_data(payloadTypes, (bctbx_list_free_func)linphone_payload_type_unref);
 
 	if (!found) {
 		app->sendResponse(Response("Audio codec not found.", Response::Error));
 	} else {
 		app->sendResponse(Response(ost.str(), Response::Ok));
 	}
+	if (pt) linphone_payload_type_unref(pt);
 }
diff --git a/daemon/commands/audio-codec-move.cc b/daemon/commands/audio-codec-move.cc
index 556e179fd0..4c8aa7af99 100644
--- a/daemon/commands/audio-codec-move.cc
+++ b/daemon/commands/audio-codec-move.cc
@@ -68,7 +68,7 @@ void AudioCodecMoveCommand::exec(Daemon *app, const string &args) {
 		app->sendResponse(Response("Incorrect mime type format.", Response::Error));
 		return;
 	}
-	PayloadType *selected_payload = NULL;
+	LinphonePayloadType *selected_payload = NULL;
 	selected_payload = parser.getPayloadType();
 
 	if (selected_payload == NULL) {
@@ -84,24 +84,26 @@ void AudioCodecMoveCommand::exec(Daemon *app, const string &args) {
 	}
 
 	int i = 0;
-	bctbx_list_t *mslist = NULL;
-	for (const bctbx_list_t *node = linphone_core_get_audio_codecs(app->getCore()); node != NULL;
-	     node = bctbx_list_next(node)) {
-		PayloadType *payload = reinterpret_cast<PayloadType *>(node->data);
+	bctbx_list_t *orig_list = linphone_core_get_audio_payload_types(app->getCore());
+	bctbx_list_t *new_list = NULL;
+	for (bctbx_list_t *node = orig_list; node != NULL; node = bctbx_list_next(node)) {
+		LinphonePayloadType *payload = reinterpret_cast<LinphonePayloadType *>(node->data);
 		if (i == index) {
-			mslist = bctbx_list_append(mslist, selected_payload);
+			new_list = bctbx_list_append(new_list, linphone_payload_type_ref(selected_payload));
 			++i;
 		}
-		if (selected_payload != payload) {
-			mslist = bctbx_list_append(mslist, payload);
+		if (!linphone_payload_type_weak_equals(selected_payload, linphone_payload_type_ref(payload))) {
+			new_list = bctbx_list_append(new_list, payload);
 			++i;
 		}
 	}
 	if (i <= index) {
 		index = i;
-		mslist = bctbx_list_append(mslist, selected_payload);
+		new_list = bctbx_list_append(new_list, linphone_payload_type_ref(selected_payload));
 	}
-	linphone_core_set_audio_codecs(app->getCore(), mslist);
+	linphone_core_set_audio_payload_types(app->getCore(), new_list);
+	bctbx_list_free_with_data(orig_list, (bctbx_list_free_func)linphone_payload_type_unref);
+	bctbx_list_free_with_data(new_list, (bctbx_list_free_func)linphone_payload_type_unref);
 
 	app->sendResponse(PayloadTypeResponse(app->getCore(), selected_payload, index));
 }
diff --git a/daemon/commands/audio-codec-set.cc b/daemon/commands/audio-codec-set.cc
index 3b40f839a4..eb868b150b 100644
--- a/daemon/commands/audio-codec-set.cc
+++ b/daemon/commands/audio-codec-set.cc
@@ -67,16 +67,20 @@ AudioCodecSetCommand::AudioCodecSetCommand()
 	                                                                                   "Enabled: false"));
 }
 
-static PayloadType *findPayload(LinphoneCore *lc, int payload_type, int *index) {
+static LinphonePayloadType *findPayload(LinphoneCore *lc, int payload_type, int *index) {
+	bctbx_list_t *payloadTypes = linphone_core_get_audio_payload_types(lc);
+	LinphonePayloadType *ret = nullptr;
 	if (index) *index = 0;
-	for (const bctbx_list_t *node = linphone_core_get_audio_codecs(lc); node != NULL; node = bctbx_list_next(node)) {
-		PayloadType *payload = reinterpret_cast<PayloadType *>(node->data);
+	for (const bctbx_list_t *node = payloadTypes; node != NULL; node = bctbx_list_next(node)) {
+		LinphonePayloadType *payload = static_cast<LinphonePayloadType *>(node->data);
 		if (index) (*index)++;
-		if (payload_type == payload_type_get_number(payload)) {
-			return payload;
+		if (payload_type == linphone_payload_type_get_number(payload)) {
+			ret = linphone_payload_type_ref(payload);
+			break;
 		}
 	}
-	return NULL;
+	bctbx_list_free_with_data(payloadTypes, (bctbx_list_free_func)linphone_payload_type_unref);
+	return ret;
 }
 
 void AudioCodecSetCommand::exec(Daemon *app, const string &args) {
@@ -104,37 +108,46 @@ void AudioCodecSetCommand::exec(Daemon *app, const string &args) {
 	ist >> value;
 	if (value.length() > 255) value.resize(255);
 
-	PayloadType *payload = parser.getPayloadType();
+	LinphonePayloadType *payload = nullptr;
+	if (parser.getPayloadType()) {
+		payload =
+		    linphone_core_get_payload_type(app->getCore(), linphone_payload_type_get_mime_type(parser.getPayloadType()),
+		                                   linphone_payload_type_get_clock_rate(parser.getPayloadType()),
+		                                   linphone_payload_type_get_channels(parser.getPayloadType()));
+	}
 	if (payload) {
 		bool handled = false;
 		if (param.compare("clock_rate") == 0) {
 			if (value.length() > 0) {
-				payload->clock_rate = atoi(value.c_str());
-				handled = true;
+				// setting the clock rate is not supported by liblinphone. What's the purpose of doing this ?'
+				// linphone_payload_type_set_clock_rate(payload, atoi(value.c_str()));
+				handled = false;
 			}
 		} else if (param.compare("recv_fmtp") == 0) {
-			payload_type_set_recv_fmtp(payload, value.c_str());
+			linphone_payload_type_set_recv_fmtp(payload, value.c_str());
 			handled = true;
 		} else if (param.compare("send_fmtp") == 0) {
-			payload_type_set_send_fmtp(payload, value.c_str());
+			linphone_payload_type_set_send_fmtp(payload, value.c_str());
 			handled = true;
 		} else if (param.compare("number") == 0) {
 			if (value.length() > 0) {
 				int idx = atoi(value.c_str());
-				PayloadType *conflict = NULL;
+				LinphonePayloadType *conflict = NULL;
 				if (idx != -1) {
 					conflict = findPayload(app->getCore(), atoi(value.c_str()), NULL);
 				}
 				if (conflict) {
 					app->sendResponse(Response("New payload type number is already used.", Response::Error));
+					linphone_payload_type_unref(conflict);
 				} else {
-					payload_type_set_number(payload, idx);
+					linphone_payload_type_set_number(payload, idx);
 					app->sendResponse(PayloadTypeResponse(app->getCore(), payload, parser.getPosition()));
 				}
+				linphone_payload_type_unref(payload);
 				return;
 			}
 		} else if (param.compare("bitrate") == 0) {
-			linphone_core_set_payload_type_bitrate(app->getCore(), payload, atoi(value.c_str()));
+			linphone_payload_type_set_normal_bitrate(payload, atoi(value.c_str()));
 			handled = true;
 		}
 		if (handled) {
@@ -142,6 +155,7 @@ void AudioCodecSetCommand::exec(Daemon *app, const string &args) {
 		} else {
 			app->sendResponse(Response("Invalid codec parameter.", Response::Error));
 		}
+		linphone_payload_type_unref(payload);
 		return;
 	}
 	app->sendResponse(Response("Audio codec not found.", Response::Error));
diff --git a/daemon/commands/audio-codec-toggle.cc b/daemon/commands/audio-codec-toggle.cc
index 35653cc28f..c5c891ef3a 100644
--- a/daemon/commands/audio-codec-toggle.cc
+++ b/daemon/commands/audio-codec-toggle.cc
@@ -34,7 +34,7 @@ void AudioCodecToggleCommand::exec(Daemon *app, const string &args) {
 		app->sendResponse(Response("Missing parameter.", Response::Error));
 	} else {
 		string mime_type;
-		PayloadType *pt = NULL;
+		LinphonePayloadType *pt = NULL;
 		ist >> mime_type;
 		PayloadTypeParser parser(app->getCore(), mime_type, true);
 		if (!parser.successful()) {
@@ -44,20 +44,21 @@ void AudioCodecToggleCommand::exec(Daemon *app, const string &args) {
 		if (!parser.all()) pt = parser.getPayloadType();
 
 		int index = 0;
-		for (const bctbx_list_t *node = linphone_core_get_audio_codecs(app->getCore()); node != NULL;
-		     node = bctbx_list_next(node)) {
-			PayloadType *payload = reinterpret_cast<PayloadType *>(node->data);
+		bctbx_list_t *l = linphone_core_get_audio_payload_types(app->getCore());
+		for (const bctbx_list_t *node = l; node != NULL; node = bctbx_list_next(node)) {
+			LinphonePayloadType *payload = static_cast<LinphonePayloadType *>(node->data);
 			if (parser.all()) {
-				linphone_core_enable_payload_type(app->getCore(), payload, mEnable);
+				linphone_payload_type_enable(payload, mEnable);
 			} else {
-				if (pt == payload) {
-					linphone_core_enable_payload_type(app->getCore(), payload, mEnable);
+				if (linphone_payload_type_weak_equals(payload, pt)) {
+					linphone_payload_type_enable(payload, mEnable);
 					app->sendResponse(PayloadTypeResponse(app->getCore(), payload, index));
 					return;
 				}
 			}
 			++index;
 		}
+		bctbx_list_free_with_data(l, (bctbx_list_free_func)linphone_payload_type_unref);
 		if (parser.all()) {
 			AudioCodecGetCommand getCommand;
 			getCommand.exec(app, "");
diff --git a/daemon/daemon.cc b/daemon/daemon.cc
index c4dd918ca9..eaaf9deadc 100644
--- a/daemon/daemon.cc
+++ b/daemon/daemon.cc
@@ -190,10 +190,10 @@ CallStatsEvent::CallStatsEvent(Daemon *daemon, LinphoneCall *call, const Linphon
 	printCallStatsHelper(ostr, stats, prefix);
 
 	if (linphone_call_stats_get_type(stats) == LINPHONE_CALL_STATS_AUDIO) {
-		const PayloadType *audioCodec = linphone_call_params_get_used_audio_codec(callParams);
+		const LinphonePayloadType *audioCodec = linphone_call_params_get_used_audio_payload_type(callParams);
 		ostr << PayloadTypeResponse(linphone_call_get_core(call), audioCodec, -1, prefix, false).getBody() << "\n";
 	} else {
-		const PayloadType *videoCodec = linphone_call_params_get_used_video_codec(callParams);
+		const LinphonePayloadType *videoCodec = linphone_call_params_get_used_video_payload_type(callParams);
 		ostr << PayloadTypeResponse(linphone_call_get_core(call), videoCodec, -1, prefix, false).getBody() << "\n";
 	}
 
@@ -227,21 +227,25 @@ CallPlayingStatsEvent::CallPlayingStatsEvent(BCTBX_UNUSED(Daemon *daemon), int i
 	setBody(ostr.str());
 }
 
-PayloadTypeResponse::PayloadTypeResponse(
-    LinphoneCore *core, const PayloadType *payloadType, int index, const string &prefix, bool enabled_status) {
+PayloadTypeResponse::PayloadTypeResponse(BCTBX_UNUSED(LinphoneCore *core),
+                                         const LinphonePayloadType *payloadType,
+                                         int index,
+                                         const string &prefix,
+                                         bool enabled_status) {
 	ostringstream ostr;
 	if (payloadType != NULL) {
 		if (index >= 0) ostr << prefix << "Index: " << index << "\n";
-		ostr << prefix << "Payload-type-number: " << payload_type_get_number(payloadType) << "\n";
-		ostr << prefix << "Clock-rate: " << payloadType->clock_rate << "\n";
-		ostr << prefix << "Bitrate: " << payloadType->normal_bitrate << "\n";
-		ostr << prefix << "Mime: " << payloadType->mime_type << "\n";
-		ostr << prefix << "Channels: " << payloadType->channels << "\n";
-		ostr << prefix << "Recv-fmtp: " << ((payloadType->recv_fmtp) ? payloadType->recv_fmtp : "") << "\n";
-		ostr << prefix << "Send-fmtp: " << ((payloadType->send_fmtp) ? payloadType->send_fmtp : "") << "\n";
+		const char *recv_fmtp = linphone_payload_type_get_recv_fmtp(payloadType);
+		const char *send_fmtp = linphone_payload_type_get_send_fmtp(payloadType);
+		ostr << prefix << "Payload-type-number: " << linphone_payload_type_get_number(payloadType) << "\n";
+		ostr << prefix << "Clock-rate: " << linphone_payload_type_get_clock_rate(payloadType) << "\n";
+		ostr << prefix << "Bitrate: " << linphone_payload_type_get_normal_bitrate(payloadType) << "\n";
+		ostr << prefix << "Mime: " << linphone_payload_type_get_mime_type(payloadType) << "\n";
+		ostr << prefix << "Channels: " << linphone_payload_type_get_channels(payloadType) << "\n";
+		ostr << prefix << "Recv-fmtp: " << (recv_fmtp ? recv_fmtp : "") << "\n";
+		ostr << prefix << "Send-fmtp: " << (send_fmtp ? send_fmtp : "") << "\n";
 		if (enabled_status)
-			ostr << prefix
-			     << "Enabled: " << (linphone_core_payload_type_enabled(core, payloadType) == TRUE ? "true" : "false")
+			ostr << prefix << "Enabled: " << (linphone_payload_type_enabled(payloadType) == TRUE ? "true" : "false")
 			     << "\n";
 		setBody(ostr.str().c_str());
 	}
@@ -263,16 +267,29 @@ PayloadTypeParser::PayloadTypeParser(LinphoneCore *core, const string &mime_type
 			mSuccesful = false;
 			return;
 		}
-		mPayloadType = linphone_core_find_payload_type(core, type, rate, channels);
-		if (mPayloadType) mPosition = bctbx_list_index(linphone_core_get_audio_codecs(core), mPayloadType);
+		mPayloadType = linphone_core_get_payload_type(core, type, rate, channels);
+		if (mPayloadType) {
+			bctbx_list_t *codecs = linphone_core_get_audio_payload_types(core);
+			bctbx_list_t *elem;
+			int index = 0;
+			for (elem = codecs; elem != NULL; elem = elem->next, ++index) {
+				if (linphone_payload_type_weak_equals((LinphonePayloadType *)elem->data, mPayloadType)) {
+					mPosition = index;
+					break;
+				}
+			}
+			bctbx_list_free_with_data(codecs, (bctbx_list_free_func)linphone_payload_type_unref);
+		}
 	} else if (number != -1) {
-		const bctbx_list_t *elem;
-		for (elem = linphone_core_get_audio_codecs(core); elem != NULL; elem = elem->next) {
-			if (number == payload_type_get_number((PayloadType *)elem->data)) {
-				mPayloadType = (PayloadType *)elem->data;
+		bctbx_list_t *codecs = linphone_core_get_audio_payload_types(core);
+		bctbx_list_t *elem;
+		for (elem = codecs; elem != NULL; elem = elem->next) {
+			if (number == linphone_payload_type_get_number((LinphonePayloadType *)elem->data)) {
+				mPayloadType = linphone_payload_type_ref((LinphonePayloadType *)elem->data);
 				break;
 			}
 		}
+		bctbx_list_free_with_data(codecs, (bctbx_list_free_func)linphone_payload_type_unref);
 	}
 }
 
diff --git a/daemon/daemon.h b/daemon/daemon.h
index 808b4f3f9d..aa98fb5af3 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -203,7 +203,7 @@ public:
 class PayloadTypeResponse : public Response {
 public:
 	PayloadTypeResponse(LinphoneCore *core,
-	                    const PayloadType *payloadType,
+	                    const LinphonePayloadType *payloadType,
 	                    int index = -1,
 	                    const std::string &prefix = std::string(),
 	                    bool enabled_status = true);
@@ -212,13 +212,16 @@ public:
 class PayloadTypeParser {
 public:
 	PayloadTypeParser(LinphoneCore *core, const std::string &mime_type, bool accept_all = false);
+	~PayloadTypeParser() {
+		if (mPayloadType) linphone_payload_type_unref(mPayloadType);
+	}
 	inline bool all() {
 		return mAll;
 	}
 	inline bool successful() {
 		return mSuccesful;
 	}
-	inline PayloadType *getPayloadType() const {
+	inline LinphonePayloadType *getPayloadType() const {
 		return mPayloadType;
 	}
 	inline int getPosition() const {
@@ -228,7 +231,7 @@ public:
 private:
 	bool mAll;
 	bool mSuccesful;
-	PayloadType *mPayloadType;
+	LinphonePayloadType *mPayloadType;
 	int mPosition;
 };
 
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 575238b1ce..a4cfce8998 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -125,6 +125,7 @@ set(C_API_HEADER_FILES
 )
 
 set(ENUMS_HEADER_FILES
+	c-enums.h
 	call-enums.h
 	chat-message-enums.h
 	chat-room-enums.h
diff --git a/include/linphone/api/c-alert.h b/include/linphone/api/c-alert.h
index 0564085178..8e8ebc57de 100644
--- a/include/linphone/api/c-alert.h
+++ b/include/linphone/api/c-alert.h
@@ -21,6 +21,7 @@
 #define _L_C_ALERT_H_
 
 #include "linphone/api/c-types.h"
+#include "linphone/enums/c-enums.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -124,4 +125,4 @@ LINPHONE_PUBLIC void linphone_alert_notify_on_terminated(LinphoneAlert *alert);
 }
 #endif
 
-#endif //_L_C_ALERT_H_
\ No newline at end of file
+#endif //_L_C_ALERT_H_
diff --git a/include/linphone/api/c-payload-type.h b/include/linphone/api/c-payload-type.h
index 2b5197a022..ba13dd013f 100644
--- a/include/linphone/api/c-payload-type.h
+++ b/include/linphone/api/c-payload-type.h
@@ -181,6 +181,16 @@ LINPHONE_PUBLIC bool_t linphone_payload_type_is_vbr(const LinphonePayloadType *p
  */
 LINPHONE_PUBLIC bool_t linphone_payload_type_is_usable(const LinphonePayloadType *payload_type);
 
+/**
+ * Compare two payload types, and returns true if they are equal.
+ * Parameters (fmtp strings) are not compared, hence the name 'weak equals'.
+ * @param payload_type the #LinphonePayloadType object @notnil
+ * @param other_payload_type another #LinphonePayloadType object @notnil
+ * @return TRUE if the payload types are "almost" equals.
+ */
+LINPHONE_PUBLIC bool_t linphone_payload_type_weak_equals(const LinphonePayloadType *payload_type,
+                                                         const LinphonePayloadType *other_payload_type);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/linphone/api/c-signal-information.h b/include/linphone/api/c-signal-information.h
index 0abd1c1477..18fa1e46b3 100644
--- a/include/linphone/api/c-signal-information.h
+++ b/include/linphone/api/c-signal-information.h
@@ -21,6 +21,7 @@
 #define _L_C_SIGNAL_INFORMATION_H_
 
 #include "linphone/api/c-types.h"
+#include "linphone/enums/c-enums.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -98,4 +99,4 @@ LINPHONE_PUBLIC void linphone_signal_information_set_signal_unit(LinphoneSignalI
 }
 #endif
 
-#endif //_L_C_SIGNAL_INFORMATION_H_
\ No newline at end of file
+#endif //_L_C_SIGNAL_INFORMATION_H_
diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h
index 2d96128cc7..b52e4136f3 100644
--- a/include/linphone/api/c-types.h
+++ b/include/linphone/api/c-types.h
@@ -661,107 +661,15 @@ typedef struct _LinphoneAlert LinphoneAlert;
  * @ingroup alert
  */
 typedef struct _LinphoneAlertCbs LinphoneAlertCbs;
-/**
- * @brief All kinds of alerts
- * @ingroup alert
- */
-typedef enum _LinphoneAlertTypes {
-
-	/** Camera is not working. No other information
-	 * @note Use the key "camera_misfunction_interval" in the section "alerts::camera" to set the interval
-	 * at which the problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSCameraMisfunction,
-	/** Camera is capturing low framerate. Information supplied : float framerate;
-	 *  @note Use the key "low_framerate_interval" in the section "alerts::camera" to set or get the interval at which
-	 * the problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSCameraLowFramerate,
-	/** Video decoding has stopped for a given period (10 s by default). No other information.
-	 *  @note Use the key "video_stalled_interval" in the section "alerts::camera" to set or get the interval at which
-	 * the problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSVideoStalled,
-	/** A received media stream suffers from high loss or late rate. Information provided is:
-	 * - loss-rate (float)
-	 * - late-rate (float)
-	 * - media-type (string) with values {audio, video, text}
-	 *  @note Use the key "loss_rate_interval" in the section "alerts::network" to set or get the interval at which
-	the problem is checked in a #LinphoneConfig.
-	*/
-	LinphoneAlertQoSHighLossLateRate,
-	/** A report of high loss rate is received from remote party. Information provided: loss-rate (float).
-	 *  @note Use the key "remote_loss_rate_interval" in the section "alerts::network" to set or get the interval at
-	 * which the problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSHighRemoteLossRate,
-	/** Packet Burst phenomenon
-	 *  @note Use the key "burst_occured_interval" in the section "alerts::network" to set or get the interval at which
-	 * the problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSBurstOccured,
-	/** Loss rate is significant but retransmissions fail to arrive on time.
-	 * Information provided: nack-performance (float) the fraction of lost packets recovered thanks to nack-triggered
-	 * retransmissions.
-	 *  @note Use the key "nack_check_interval" in the section "alerts::network" to set or get the interval at which the
-	 * problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSRetransmissionFailures,
-	/** Low bandwidth detected. Information provided: bandwidth (float) in kbit/s.
-	 *  @note Use the key "download_bandwidth_interval" in the section "alerts::video" to set or get the interval at
-	 * which the problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSLowDownloadBandwidthEstimation,
-	/** Low quality (bitrate) video received. Information provided: bitrate (float) in kbit/s, width (integer), int
-	 * height (integer).
-	 *  @note Use the key "low_quality_received_interval" in the section "alerts::video" to set or get the interval at
-	 * which the problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSLowQualityReceivedVideo,
-	/** Low quality video is being sent. Information provided: bitrate (float)in kbit/s, width (integer), height
-	 * (integer).
-	 * @note Use the key "quality_sent_interval" in the section "alerts::camera" to set or get the interval at which
-	 * the problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSLowQualitySentVideo,
-	/** The operating system reports a low radio signal (wifi or mobile)
-	 * @note Use the key "low_signal_interval" in the section "alerts::network" to set or get the interval at which the
-	 * problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSLowSignal,
-	/** The operating system reports a loss of radio signal (wifi or mobile).
-	 * Information provided: rssi-value (float), signal-type (string) with values {"wifi", "mobile", "other"}.
-	 * @note Use the key "lost_signal_interval" in the section "alerts::network" to set or get the interval at which
-	 * the problem is checked in a #LinphoneConfig.
-	 */
-	LinphoneAlertQoSLostSignal
-
-} LinphoneAlertType;
+
 // -----------------------------------------------------------------------------
 // SignalInformation
 // -----------------------------------------------------------------------------
 /**
  * @brief Object to get signal (wifi/4G etc...) informations.
- * @ingroup signalInformation
+ * @ingroup alert
  */
 typedef struct _LinphoneSignalInformation LinphoneSignalInformation;
-/**
- * All signal types that a device can use.
- * @ingroup signalInformation
- */
-typedef enum _LinphoneSignalType {
-	LinphoneSignalTypeWifi = 0,
-	LinphoneSignalTypeMobile = 1,
-	LinphoneSignalTypeOther = 2
-} LinphoneSignalType;
-/**
- * All signal units that a device can use.
- * @ingroup signalInformation
- */
-typedef enum _LinphoneSignalStrengthUnit {
-	LinphoneSignalStrengthUnitRssi = 0,
-	LinphoneSignalStrengthUnitDbm = 1,
-} LinphoneSignalStrengthUnit;
 
 #ifdef __cplusplus
 }
diff --git a/include/linphone/call_params.h b/include/linphone/call_params.h
index 344a27874b..3b643e6501 100644
--- a/include/linphone/call_params.h
+++ b/include/linphone/call_params.h
@@ -331,7 +331,7 @@ LINPHONE_PUBLIC const char *linphone_call_params_get_session_name(const Linphone
  * @return The selected #LinphonePayloadType. NULL is returned if no audio payload type has been selected by the call.
  *@maybenil
  **/
-LINPHONE_PUBLIC LinphonePayloadType *
+LINPHONE_PUBLIC const LinphonePayloadType *
 linphone_call_params_get_used_audio_payload_type(const LinphoneCallParams *call_params);
 
 /**
@@ -340,17 +340,16 @@ linphone_call_params_get_used_audio_payload_type(const LinphoneCallParams *call_
  * @return The selected #LinphonePayloadType. NULL is returned if no video payload type has been selected by the call.
  *@maybenil
  **/
-LINPHONE_PUBLIC LinphonePayloadType *
+LINPHONE_PUBLIC const LinphonePayloadType *
 linphone_call_params_get_used_video_payload_type(const LinphoneCallParams *call_params);
 
-LINPHONE_PUBLIC const OrtpPayloadType *linphone_call_params_get_used_fec_codec(const LinphoneCallParams *call_params);
 /**
  * Get the text payload type that has been selected by a call.
  * @param call_params The #LinphoneCallParams object. @notnil
  * @return The selected #LinphonePayloadType. NULL is returned if no text payload type has been selected by the call.
  *@maybenil
  **/
-LINPHONE_PUBLIC LinphonePayloadType *
+LINPHONE_PUBLIC const LinphonePayloadType *
 linphone_call_params_get_used_text_payload_type(const LinphoneCallParams *call_params);
 
 /**
@@ -835,36 +834,6 @@ linphone_call_params_get_received_video_size(const LinphoneCallParams *call_para
 LINPHONE_PUBLIC LINPHONE_DEPRECATED MSVideoSize
 linphone_call_params_get_sent_video_size(const LinphoneCallParams *call_params);
 
-/**
- * Get the audio payload type that has been selected by a call.
- * @param call_params The #LinphoneCallParams object. @notnil
- * @return The selected payload type. NULL is returned if no audio payload type has been seleced by the call.
- * @deprecated 31/03/2017 Use linphone_call_params_get_used_audio_payload_type() instead.
- * @donotwrap
- **/
-LINPHONE_PUBLIC LINPHONE_DEPRECATED const OrtpPayloadType *
-linphone_call_params_get_used_audio_codec(const LinphoneCallParams *call_params);
-
-/**
- * Get the video payload type that has been selected by a call.
- * @param call_params The #LinphoneCallParams object. @notnil
- * @return The selected payload type. NULL is returned if no video payload type has been seleced by the call.
- * @deprecated 31/03/2017 Use linphone_call_params_get_used_video_payload_type() instead.
- * @donotwrap
- **/
-LINPHONE_PUBLIC LINPHONE_DEPRECATED const OrtpPayloadType *
-linphone_call_params_get_used_video_codec(const LinphoneCallParams *call_params);
-
-/**
- * Get the text payload type that has been selected by a call.
- * @param call_params The #LinphoneCallParams object. @notnil
- * @return The selected payload type. NULL is returned if no text payload type has been seleced by the call.
- * @deprecated 31/03/2017 Use linphone_call_params_get_used_text_payload_type() instead.
- * @donotwrap
- **/
-LINPHONE_PUBLIC LINPHONE_DEPRECATED const OrtpPayloadType *
-linphone_call_params_get_used_text_codec(const LinphoneCallParams *call_params);
-
 /**
  * Set the #LinphoneProxyConfig to use for the call
  *
diff --git a/include/linphone/core.h b/include/linphone/core.h
index ea26994ce4..af424cd09c 100644
--- a/include/linphone/core.h
+++ b/include/linphone/core.h
@@ -66,6 +66,8 @@
 // For migration purpose.
 #include "linphone/api/c-api.h"
 
+#include "linphone/enums/c-enums.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -2044,7 +2046,8 @@ LINPHONE_PUBLIC void linphone_core_set_upload_ptime(LinphoneCore *core, int ptim
 LINPHONE_PUBLIC int linphone_core_get_upload_ptime(LinphoneCore *core);
 
 /**
- * Set the SIP transport timeout.
+ * Set the SIP transport timeout, which represents the maximum time permitted to establish a
+ * connection to a SIP server.
  * @param core #LinphoneCore object. @notnil
  * @param timeout_ms The SIP transport timeout in milliseconds.
  * @ingroup media_parameters
@@ -2052,7 +2055,8 @@ LINPHONE_PUBLIC int linphone_core_get_upload_ptime(LinphoneCore *core);
 LINPHONE_PUBLIC void linphone_core_set_sip_transport_timeout(LinphoneCore *core, int timeout_ms);
 
 /**
- * Get the SIP transport timeout.
+ * Get the SIP transport timeout, which represents the maximum time permitted to establish a
+ * connection to a SIP server.
  * @param core #LinphoneCore object. @notnil
  * @return The SIP transport timeout in milliseconds.
  * @ingroup media_parameters
@@ -2123,8 +2127,7 @@ LINPHONE_PUBLIC void linphone_core_set_dns_servers(LinphoneCore *core, const bct
 /**
  * Return the list of the available audio payload types.
  * @param core The core. @notnil
- * @return A freshly allocated list of the available payload types. The list
- * must be destroyed with bctbx_list_free() after usage. The elements of the list haven't to be unref.
+ * @return A freshly allocated list of the available payload types.
  * @bctbx_list{LinphonePayloadType} @maybenil @tobefreed
  * @ingroup media_parameters
  */
@@ -2142,15 +2145,18 @@ LINPHONE_PUBLIC void linphone_core_set_audio_payload_types(LinphoneCore *core, c
 /**
  * Return the list of the available video payload types.
  * @param core The core. @notnil
- * @return A freshly allocated list of the available payload types. The list
- * must be destroyed with bctbx_list_free() after usage. The elements of the
- * list haven't to be unref. @bctbx_list{LinphonePayloadType} @maybenil
+ * @return A freshly allocated list of the available payload types.  @bctbx_list{LinphonePayloadType} @maybenil
+ * @tobefreed
  * @ingroup media_parameters
  */
 LINPHONE_PUBLIC bctbx_list_t *linphone_core_get_video_payload_types(LinphoneCore *core);
 
 /**
  * Redefine the list of the available video payload types.
+ * Calling this function if the video codec priority policy is LinphoneCodecPriorityPolicyAuto
+ * turns video codec priority policy to basic scheme, since application is not supposed to control
+ * the order of video codecs when LinphoneCodecPriorityPolicyAuto is selected, by definition.
+ * (see linphone_core_set_video_codec_priority_policy() )
  * @param core The core. @notnil
  * @param payload_types The new list of codecs. The core does not take
  * ownership on it. \bctbx_list{LinphonePayloadType} @maybenil
@@ -2158,6 +2164,28 @@ LINPHONE_PUBLIC bctbx_list_t *linphone_core_get_video_payload_types(LinphoneCore
  */
 LINPHONE_PUBLIC void linphone_core_set_video_payload_types(LinphoneCore *core, const bctbx_list_t *payload_types);
 
+/**
+ * Set the priority policy for video codecs (payload types).
+ * Since version 5.3, the default value is #LinphoneCodecPriorityPolicyAuto unless the core's
+ * configuration file describes a list of video payload type to use.
+ * This is to preserve backward compatibility for upgrading applications.
+ * See #LinphoneCodecPriorityPolicy for more details.
+ * @param core, the core @notnil
+ * @param policy the #LinphoneCodecPriorityPolicy to apply
+ * @ingroup media_parameters
+ */
+LINPHONE_PUBLIC void linphone_core_set_video_codec_priority_policy(LinphoneCore *core,
+                                                                   LinphoneCodecPriorityPolicy policy);
+
+/**
+ * Get the current priority policy for video codecs (payload types).
+ *
+ * See #LinphoneCodecPriorityPolicy for more details.
+ * @param core, the core @notnil
+ * @return the current #LinphoneCodecPriorityPolicy
+ **/
+LINPHONE_PUBLIC LinphoneCodecPriorityPolicy linphone_core_get_video_codec_priority_policy(const LinphoneCore *core);
+
 /**
  * Return the list of the available text payload types.
  * @param core The core. @notnil
@@ -2206,9 +2234,7 @@ LINPHONE_PUBLIC bool_t linphone_core_generic_comfort_noise_enabled(const Linphon
  * @param rate can be #LINPHONE_FIND_PAYLOAD_IGNORE_RATE
  * @param channels  number of channels, can be #LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS
  * @return Returns NULL if not found. If a #LinphonePayloadType is returned, it must be released with
- * linphone_payload_type_unref() after using it. @maybenil
- * @warning The returned payload type is allocated as a floating reference i.e. the reference counter is initialized to
- * 0.
+ * linphone_payload_type_unref() after using it. @maybenil @tobefreed
  */
 LINPHONE_PUBLIC LinphonePayloadType *
 linphone_core_get_payload_type(LinphoneCore *core, const char *type, int rate, int channels);
diff --git a/include/linphone/enums/c-enums.h b/include/linphone/enums/c-enums.h
new file mode 100644
index 0000000000..aaa7a588a7
--- /dev/null
+++ b/include/linphone/enums/c-enums.h
@@ -0,0 +1,139 @@
+/*
+ * 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_C_ENUMS_H_
+#define _L_C_ENUMS_H_
+
+/*
+ * Global enums, not bound to any object.
+ */
+
+/**
+ * @brief All kinds of alerts
+ * @ingroup alert
+ */
+typedef enum _LinphoneAlertTypes {
+
+	/** Camera is not working. No other information
+	 * @note Use the key "camera_misfunction_interval" in the section "alerts::camera" to set the interval
+	 * at which the problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSCameraMisfunction,
+	/** Camera is capturing low framerate. Information supplied : float framerate;
+	 *  @note Use the key "low_framerate_interval" in the section "alerts::camera" to set or get the interval at which
+	 * the problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSCameraLowFramerate,
+	/** Video decoding has stopped for a given period (10 s by default). No other information.
+	 *  @note Use the key "video_stalled_interval" in the section "alerts::camera" to set or get the interval at which
+	 * the problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSVideoStalled,
+	/** A received media stream suffers from high loss or late rate. Information provided is:
+	 * - loss-rate (float)
+	 * - late-rate (float)
+	 * - media-type (string) with values {audio, video, text}
+	 *  @note Use the key "loss_rate_interval" in the section "alerts::network" to set or get the interval at which
+	the problem is checked in a #LinphoneConfig.
+	*/
+	LinphoneAlertQoSHighLossLateRate,
+	/** A report of high loss rate is received from remote party. Information provided: loss-rate (float).
+	 *  @note Use the key "remote_loss_rate_interval" in the section "alerts::network" to set or get the interval at
+	 * which the problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSHighRemoteLossRate,
+	/** Packet Burst phenomenon
+	 *  @note Use the key "burst_occured_interval" in the section "alerts::network" to set or get the interval at which
+	 * the problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSBurstOccured,
+	/** Loss rate is significant but retransmissions fail to arrive on time.
+	 * Information provided: nack-performance (float) the fraction of lost packets recovered thanks to nack-triggered
+	 * retransmissions.
+	 *  @note Use the key "nack_check_interval" in the section "alerts::network" to set or get the interval at which the
+	 * problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSRetransmissionFailures,
+	/** Low bandwidth detected. Information provided: bandwidth (float) in kbit/s.
+	 *  @note Use the key "download_bandwidth_interval" in the section "alerts::video" to set or get the interval at
+	 * which the problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSLowDownloadBandwidthEstimation,
+	/** Low quality (bitrate) video received. Information provided: bitrate (float) in kbit/s, width (integer), int
+	 * height (integer).
+	 *  @note Use the key "low_quality_received_interval" in the section "alerts::video" to set or get the interval at
+	 * which the problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSLowQualityReceivedVideo,
+	/** Low quality video is being sent. Information provided: bitrate (float)in kbit/s, width (integer), height
+	 * (integer).
+	 * @note Use the key "quality_sent_interval" in the section "alerts::camera" to set or get the interval at which
+	 * the problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSLowQualitySentVideo,
+	/** The operating system reports a low radio signal (wifi or mobile)
+	 * @note Use the key "low_signal_interval" in the section "alerts::network" to set or get the interval at which the
+	 * problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSLowSignal,
+	/** The operating system reports a loss of radio signal (wifi or mobile).
+	 * Information provided: rssi-value (float), signal-type (string) with values {"wifi", "mobile", "other"}.
+	 * @note Use the key "lost_signal_interval" in the section "alerts::network" to set or get the interval at which
+	 * the problem is checked in a #LinphoneConfig.
+	 */
+	LinphoneAlertQoSLostSignal
+
+} LinphoneAlertType;
+
+/**
+ * All signal types that a device can use.
+ * @ingroup signalInformation
+ */
+typedef enum _LinphoneSignalType {
+	LinphoneSignalTypeWifi = 0,
+	LinphoneSignalTypeMobile = 1,
+	LinphoneSignalTypeOther = 2
+} LinphoneSignalType;
+/**
+ * All signal units that a device can use.
+ * @ingroup signalInformation
+ */
+typedef enum _LinphoneSignalStrengthUnit {
+	LinphoneSignalStrengthUnitRssi = 0,
+	LinphoneSignalStrengthUnitDbm = 1,
+} LinphoneSignalStrengthUnit;
+
+/**
+ * Codec priority policies.
+ * This enum represents different policies for managing offered codec lists during calls, as well as the offer-answer
+ * logic. Currently, policies can be applied only for video codecs.
+ * @ingroup media_parameters
+ */
+typedef enum _LinphoneCodecPriorityPolicy {
+	LinphoneCodecPriorityPolicyBasic =
+	    0, /**< In this mode, codecs have initial default ordering, that can be changed by the application
+	         The answerer of a call accepts codecs with the order given in the offer. */
+	LinphoneCodecPriorityPolicyAuto =
+	    1 /**< In this mode, the codec list is managed by the #LinphoneCore according to hardware capabilities
+	          in the goal of optimizing video quality and user experience. The answerer of call
+	          may re-order the offerer's list in its answer in order to give preference to certain codecs.*/
+} LinphoneCodecPriorityPolicy;
+
+#endif
diff --git a/src/c-wrapper/api/c-account.cpp b/src/c-wrapper/api/c-account.cpp
index e1facbcc24..7e9a5d89c5 100644
--- a/src/c-wrapper/api/c-account.cpp
+++ b/src/c-wrapper/api/c-account.cpp
@@ -316,11 +316,11 @@ char *linphone_account_normalize_phone_number(const LinphoneAccount *account, co
 	if (account) {
 		const LinphoneAccountParams *accountParams = linphone_account_get_params(account);
 		dial_prefix = linphone_account_params_get_international_prefix(accountParams);
-		dial_escape_plus = linphone_account_params_get_dial_escape_plus_enabled(accountParams);
+		dial_escape_plus = linphone_account_params_dial_escape_plus_enabled(accountParams);
 	} else {
 		LinphoneAccountParams *accountParams = linphone_account_params_new(NULL);
 		dial_prefix = linphone_account_params_get_international_prefix(accountParams);
-		dial_escape_plus = linphone_account_params_get_dial_escape_plus_enabled(accountParams);
+		dial_escape_plus = linphone_account_params_dial_escape_plus_enabled(accountParams);
 		linphone_account_params_unref(accountParams);
 	}
 
diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp
index 5d9cc9d290..2fa745243d 100644
--- a/src/c-wrapper/api/c-call-params.cpp
+++ b/src/c-wrapper/api/c-call-params.cpp
@@ -344,45 +344,30 @@ const char *linphone_call_params_get_session_name(const LinphoneCallParams *para
 	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(params)->getSessionName());
 }
 
-LinphonePayloadType *linphone_call_params_get_used_audio_payload_type(const LinphoneCallParams *params) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedAudioPayloadType();
+const LinphonePayloadType *linphone_call_params_get_used_audio_payload_type(const LinphoneCallParams *params) {
+	return bellesip::toC(L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedAudioPayloadType());
 }
 
-LinphonePayloadType *linphone_call_params_get_used_video_payload_type(const LinphoneCallParams *params) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedVideoPayloadType();
+const LinphonePayloadType *linphone_call_params_get_used_video_payload_type(const LinphoneCallParams *params) {
+	return bellesip::toC(L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedVideoPayloadType());
 }
 
-LinphonePayloadType *linphone_call_params_get_used_text_payload_type(const LinphoneCallParams *params) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedRealtimeTextPayloadType();
-}
-
-const OrtpPayloadType *linphone_call_params_get_used_audio_codec(const LinphoneCallParams *params) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedAudioCodec();
+const LinphonePayloadType *linphone_call_params_get_used_text_payload_type(const LinphoneCallParams *params) {
+	return bellesip::toC(L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedRealtimeTextPayloadType());
 }
 
 void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec) {
 	L_GET_PRIVATE_FROM_C_OBJECT(params)->setUsedAudioCodec(codec);
 }
 
-const OrtpPayloadType *linphone_call_params_get_used_video_codec(const LinphoneCallParams *params) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedVideoCodec();
-}
-
 void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec) {
 	L_GET_PRIVATE_FROM_C_OBJECT(params)->setUsedVideoCodec(codec);
 }
 
-const OrtpPayloadType *linphone_call_params_get_used_fec_codec(const LinphoneCallParams *params) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedFecCodec();
-}
 void linphone_call_params_set_used_fec_codec(LinphoneCallParams *params, OrtpPayloadType *codec) {
 	L_GET_PRIVATE_FROM_C_OBJECT(params)->setUsedFecCodec(codec);
 }
 
-const OrtpPayloadType *linphone_call_params_get_used_text_codec(const LinphoneCallParams *params) {
-	return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedRealtimeTextCodec();
-}
-
 void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec) {
 	L_GET_PRIVATE_FROM_C_OBJECT(params)->setUsedRealtimeTextCodec(codec);
 }
diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp
index 895a936b39..4480f9f7b8 100644
--- a/src/c-wrapper/api/c-chat-message.cpp
+++ b/src/c-wrapper/api/c-chat-message.cpp
@@ -621,7 +621,7 @@ void linphone_chat_message_start_file_download(LinphoneChatMessage *msg,
                                                void *ud) {
 	msg->message_state_changed_cb = status_cb;
 	msg->message_state_changed_user_data = ud;
-	linphone_chat_message_download_file(msg);
+	L_GET_PRIVATE_FROM_C_OBJECT(msg)->downloadFile();
 }
 
 const char *linphone_chat_message_get_call_id(const LinphoneChatMessage *msg) {
diff --git a/src/c-wrapper/api/c-core.cpp b/src/c-wrapper/api/c-core.cpp
index 14bc66cd9a..8caa9e1284 100644
--- a/src/c-wrapper/api/c-core.cpp
+++ b/src/c-wrapper/api/c-core.cpp
@@ -102,8 +102,8 @@ const char *linphone_core_get_linphone_specs(const LinphoneCore *lc) {
 	return linphone_config_get_string(linphone_core_get_config(lc), "sip", "linphone_specs", NULL);
 }
 
-//Deprecated
-void linphone_core_set_linphone_specs (LinphoneCore *lc, const char *specs) {
+// Deprecated
+void linphone_core_set_linphone_specs(LinphoneCore *lc, const char *specs) {
 	L_GET_CPP_PTR_FROM_C_OBJECT(lc)->setSpecs(L_C_TO_STRING(specs));
 }
 
@@ -111,15 +111,15 @@ void linphone_core_set_linphone_specs_list(LinphoneCore *lc, const bctbx_list_t
 	L_GET_CPP_PTR_FROM_C_OBJECT(lc)->setSpecs(L_GET_CPP_LIST_FROM_C_LIST(specs, const char *, string));
 }
 
-void linphone_core_add_linphone_spec (LinphoneCore *lc, const char *spec) {
+void linphone_core_add_linphone_spec(LinphoneCore *lc, const char *spec) {
 	L_GET_CPP_PTR_FROM_C_OBJECT(lc)->addSpec(L_C_TO_STRING(spec));
 }
 
-void linphone_core_remove_linphone_spec (LinphoneCore *lc, const char *spec) {
+void linphone_core_remove_linphone_spec(LinphoneCore *lc, const char *spec) {
 	L_GET_CPP_PTR_FROM_C_OBJECT(lc)->removeSpec(L_C_TO_STRING(spec));
 }
 
-bctbx_list_t *linphone_core_get_linphone_specs_list (LinphoneCore *lc) {
+bctbx_list_t *linphone_core_get_linphone_specs_list(LinphoneCore *lc) {
 	return L_GET_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getSpecsList());
 }
 
@@ -140,10 +140,12 @@ void linphone_core_ensure_registered(LinphoneCore *lc) {
 }
 
 void linphone_core_process_push_notification(LinphoneCore *lc, const char *call_id) {
+	CoreLogContextualizer logContextualizer(lc);
 	L_GET_CPP_PTR_FROM_C_OBJECT(lc)->pushNotificationReceived(call_id, "", false);
 }
 
 void linphone_core_push_notification_received(LinphoneCore *lc, const char *payload, const char *call_id) {
+	CoreLogContextualizer logContextualizer(lc);
 	L_GET_CPP_PTR_FROM_C_OBJECT(lc)->pushNotificationReceived(call_id, payload, false);
 }
 
@@ -151,11 +153,13 @@ void linphone_core_push_notification_received_2(LinphoneCore *lc,
                                                 const char *payload,
                                                 const char *call_id,
                                                 bool_t is_core_starting) {
+	CoreLogContextualizer logContextualizer(lc);
 	L_GET_CPP_PTR_FROM_C_OBJECT(lc)->pushNotificationReceived(call_id, payload, is_core_starting);
 }
 
-LinphonePushNotificationMessage * linphone_core_get_new_message_from_callid(LinphoneCore *lc, const char *call_id) {
-	std::shared_ptr<PushNotificationMessage> cppMsg = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getPushNotificationMessage(L_C_TO_STRING(call_id));
+LinphonePushNotificationMessage *linphone_core_get_new_message_from_callid(LinphoneCore *lc, const char *call_id) {
+	std::shared_ptr<PushNotificationMessage> cppMsg =
+	    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getPushNotificationMessage(L_C_TO_STRING(call_id));
 	if (!cppMsg) return NULL;
 
 	LinphonePushNotificationMessage *msg = (LinphonePushNotificationMessage *)cppMsg->toC();
@@ -167,9 +171,11 @@ LinphonePushNotificationMessage * linphone_core_get_new_message_from_callid(Linp
 }
 
 /* Uses the chat_room_addr instead of the call_id like linphone_core_get_new_message_from_callid to get the chatroom.
-Using the call_id to get the chat room require to add a new param to chat room objects where the conference address is already here */
-LinphoneChatRoom * linphone_core_get_new_chat_room_from_conf_addr(LinphoneCore *lc , const char *chat_room_addr) {
-	std::shared_ptr<ChatRoom> cppChatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getPushNotificationChatRoom(L_C_TO_STRING(chat_room_addr));
+Using the call_id to get the chat room require to add a new param to chat room objects where the conference address is
+already here */
+LinphoneChatRoom *linphone_core_get_new_chat_room_from_conf_addr(LinphoneCore *lc, const char *chat_room_addr) {
+	std::shared_ptr<ChatRoom> cppChatRoom =
+	    L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getPushNotificationChatRoom(L_C_TO_STRING(chat_room_addr));
 	LinphoneChatRoom *chatRoom = L_GET_C_BACK_PTR(cppChatRoom);
 
 	return chatRoom;
@@ -284,6 +290,7 @@ LinphoneLdap *linphone_core_create_ldap_with_params(LinphoneCore *core, Linphone
 }
 
 void linphone_core_clear_ldaps(LinphoneCore *core) {
+	CoreLogContextualizer logContextualizer(core);
 	auto list = L_GET_CPP_PTR_FROM_C_OBJECT(core)->getLdapList();
 	for (auto ldap : list) {
 		L_GET_CPP_PTR_FROM_C_OBJECT(core)->removeLdap(ldap);
@@ -291,14 +298,17 @@ void linphone_core_clear_ldaps(LinphoneCore *core) {
 }
 
 void linphone_core_add_ldap(LinphoneCore *core, LinphoneLdap *ldap) {
+	CoreLogContextualizer logContextualizer(core);
 	L_GET_CPP_PTR_FROM_C_OBJECT(core)->addLdap(Ldap::toCpp(ldap)->getSharedFromThis());
 }
 
 void linphone_core_remove_ldap(LinphoneCore *core, LinphoneLdap *ldap) {
+	CoreLogContextualizer logContextualizer(core);
 	L_GET_CPP_PTR_FROM_C_OBJECT(core)->removeLdap(Ldap::toCpp(ldap)->getSharedFromThis());
 }
 
 bctbx_list_t *linphone_core_get_ldap_list(LinphoneCore *lc) {
+	CoreLogContextualizer logContextualizer(lc);
 	return Ldap::getCListFromCppList(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getLdapList());
 }
 
@@ -309,3 +319,13 @@ bool_t linphone_core_get_chat_messages_aggregation_enabled(LinphoneCore *core) {
 void linphone_core_set_chat_messages_aggregation_enabled(LinphoneCore *core, bool_t enabled) {
 	linphone_config_set_bool(linphone_core_get_config(core), "sip", "chat_messages_aggregation", enabled);
 }
+
+void linphone_core_set_video_codec_priority_policy(LinphoneCore *core, LinphoneCodecPriorityPolicy policy) {
+	CoreLogContextualizer logContextualizer(core);
+	L_GET_CPP_PTR_FROM_C_OBJECT(core)->setVideoCodecPriorityPolicy(policy);
+}
+
+LinphoneCodecPriorityPolicy linphone_core_get_video_codec_priority_policy(const LinphoneCore *core) {
+	CoreLogContextualizer logContextualizer(core);
+	return L_GET_CPP_PTR_FROM_C_OBJECT(core)->getVideoCodecPriorityPolicy();
+}
diff --git a/src/c-wrapper/api/c-payload-type.cpp b/src/c-wrapper/api/c-payload-type.cpp
index 573ce9d066..c6c0decfe1 100644
--- a/src/c-wrapper/api/c-payload-type.cpp
+++ b/src/c-wrapper/api/c-payload-type.cpp
@@ -112,3 +112,13 @@ bool_t linphone_payload_type_is_vbr(const LinphonePayloadType *payload_type) {
 bool_t linphone_payload_type_is_usable(const LinphonePayloadType *payload_type) {
 	return LinphonePrivate::PayloadType::toCpp(payload_type)->isUsable();
 }
+
+bool_t linphone_payload_type_weak_equals(const LinphonePayloadType *payload_type,
+                                         const LinphonePayloadType *other_payload_type) {
+	return LinphonePrivate::PayloadType::toCpp(payload_type)
+	    ->weakEquals(*LinphonePrivate::PayloadType::toCpp(other_payload_type));
+}
+
+void linphone_payload_type_set_priority_bonus(LinphonePayloadType *payload_type, bool_t value) {
+	return LinphonePrivate::PayloadType::toCpp(payload_type)->setPriorityBonus(value);
+}
diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h
index f62f81d580..1ebafdab34 100644
--- a/src/c-wrapper/c-wrapper.h
+++ b/src/c-wrapper/c-wrapper.h
@@ -195,7 +195,6 @@ 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),
@@ -212,7 +211,6 @@ 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),
diff --git a/src/conference/params/media-session-params-p.h b/src/conference/params/media-session-params-p.h
index 8dba90d3ff..f2013875b0 100644
--- a/src/conference/params/media-session-params-p.h
+++ b/src/conference/params/media-session-params-p.h
@@ -25,6 +25,8 @@
 
 #include "media-session-params.h"
 
+#include "payload-type/payload-type.h"
+
 // =============================================================================
 
 extern LinphoneCallParams *linphone_call_params_new_for_wrapper(void);
@@ -96,16 +98,16 @@ public:
 	}
 	void setSentVideoDefinition(LinphoneVideoDefinition *value);
 	void setUsedAudioCodec(OrtpPayloadType *pt) {
-		usedAudioCodec = pt;
+		usedAudioCodec = PayloadType::create(nullptr, pt);
 	}
 	void setUsedVideoCodec(OrtpPayloadType *pt) {
-		usedVideoCodec = pt;
+		usedVideoCodec = PayloadType::create(nullptr, pt);
 	}
 	void setUsedRealtimeTextCodec(OrtpPayloadType *pt) {
-		usedRealtimeTextCodec = pt;
+		usedRealtimeTextCodec = PayloadType::create(nullptr, pt);
 	}
 	void setUsedFecCodec(OrtpPayloadType *pt) {
-		usedFecCodec = pt;
+		usedFecCodec = PayloadType::create(nullptr, pt);
 	}
 	SalCustomSdpAttribute *getCustomSdpAttributes() const;
 	void setCustomSdpAttributes(const SalCustomSdpAttribute *csa);
@@ -117,22 +119,22 @@ public:
 	int audioBandwidthLimit = 0;
 	LinphoneMediaDirection audioDirection = LinphoneMediaDirectionSendRecv;
 	bool audioMulticastEnabled = false;
-	::PayloadType *usedAudioCodec = nullptr;
+	std::shared_ptr<PayloadType> usedAudioCodec;
 
 	bool videoEnabled = false;
 	LinphoneMediaDirection videoDirection = LinphoneMediaDirectionSendRecv;
 	bool videoMulticastEnabled = false;
-	::PayloadType *usedVideoCodec = nullptr;
+	std::shared_ptr<PayloadType> usedVideoCodec;
 	float receivedFps = 0.f;
 	LinphoneVideoDefinition *receivedVideoDefinition = nullptr;
 	float sentFps = 0.f;
 	LinphoneVideoDefinition *sentVideoDefinition = nullptr;
 
 	bool fecEnabled = false;
-	::PayloadType *usedFecCodec = nullptr;
+	std::shared_ptr<PayloadType> usedFecCodec;
 
 	unsigned int realtimeTextKeepaliveInterval = 25000;
-	::PayloadType *usedRealtimeTextCodec = nullptr;
+	std::shared_ptr<PayloadType> usedRealtimeTextCodec;
 	int videoDownloadBandwidth = 0;
 
 	bool realtimeTextEnabled = false;
diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp
index ca049fa764..5615808e1c 100644
--- a/src/conference/params/media-session-params.cpp
+++ b/src/conference/params/media-session-params.cpp
@@ -339,16 +339,11 @@ LinphoneMediaDirection MediaSessionParams::getAudioDirection() const {
 	return d->audioDirection;
 }
 
-const OrtpPayloadType *MediaSessionParams::getUsedAudioCodec() const {
+std::shared_ptr<const PayloadType> MediaSessionParams::getUsedAudioPayloadType() const {
 	L_D();
 	return d->usedAudioCodec;
 }
 
-LinphonePayloadType *MediaSessionParams::getUsedAudioPayloadType() const {
-	L_D();
-	return d->usedAudioCodec ? linphone_payload_type_new(nullptr, d->usedAudioCodec) : nullptr;
-}
-
 void MediaSessionParams::setAudioBandwidthLimit(int value) {
 	L_D();
 	d->audioBandwidthLimit = value;
@@ -396,16 +391,11 @@ LinphoneVideoDefinition *MediaSessionParams::getSentVideoDefinition() const {
 	return d->sentVideoDefinition;
 }
 
-const OrtpPayloadType *MediaSessionParams::getUsedVideoCodec() const {
+std::shared_ptr<const PayloadType> MediaSessionParams::getUsedVideoPayloadType() const {
 	L_D();
 	return d->usedVideoCodec;
 }
 
-LinphonePayloadType *MediaSessionParams::getUsedVideoPayloadType() const {
-	L_D();
-	return d->usedVideoCodec ? linphone_payload_type_new(nullptr, d->usedVideoCodec) : nullptr;
-}
-
 LinphoneMediaDirection MediaSessionParams::getVideoDirection() const {
 	L_D();
 	return d->videoDirection;
@@ -441,7 +431,8 @@ bool MediaSessionParams::fecEnabled() const {
 	L_D();
 	return d->fecEnabled;
 }
-const OrtpPayloadType *MediaSessionParams::getUsedFecCodec() const {
+
+std::shared_ptr<const PayloadType> MediaSessionParams::getUsedFecCodec() const {
 	L_D();
 	return d->usedFecCodec;
 }
@@ -457,16 +448,11 @@ void MediaSessionParams::setRealtimeTextKeepaliveInterval(unsigned int interval)
 	d->realtimeTextKeepaliveInterval = interval;
 }
 
-const OrtpPayloadType *MediaSessionParams::getUsedRealtimeTextCodec() const {
+std::shared_ptr<const PayloadType> MediaSessionParams::getUsedRealtimeTextPayloadType() const {
 	L_D();
 	return d->usedRealtimeTextCodec;
 }
 
-LinphonePayloadType *MediaSessionParams::getUsedRealtimeTextPayloadType() const {
-	L_D();
-	return d->usedRealtimeTextCodec ? linphone_payload_type_new(nullptr, d->usedRealtimeTextCodec) : nullptr;
-}
-
 bool MediaSessionParams::realtimeTextEnabled() const {
 	L_D();
 	return d->realtimeTextEnabled;
diff --git a/src/conference/params/media-session-params.h b/src/conference/params/media-session-params.h
index 599c1d8e4c..932ac6233d 100644
--- a/src/conference/params/media-session-params.h
+++ b/src/conference/params/media-session-params.h
@@ -21,10 +21,9 @@
 #ifndef _L_MEDIA_SESSION_PARAMS_H_
 #define _L_MEDIA_SESSION_PARAMS_H_
 
-#include <ortp/payloadtype.h>
-
 #include "call-session-params.h"
 #include "call/audio-device/audio-device.h"
+#include "payload-type/payload-type.h"
 #include "utils/general-internal.h"
 
 // =============================================================================
@@ -71,8 +70,7 @@ public:
 	void enableAudioMulticast(bool value);
 	int getAudioBandwidthLimit() const;
 	LinphoneMediaDirection getAudioDirection() const;
-	const OrtpPayloadType *getUsedAudioCodec() const;
-	LinphonePayloadType *getUsedAudioPayloadType() const;
+	std::shared_ptr<const PayloadType> getUsedAudioPayloadType() const;
 	void setAudioBandwidthLimit(int value);
 	void setAudioDirection(SalStreamDir direction);
 	void setAudioDirection(LinphoneMediaDirection direction);
@@ -83,8 +81,7 @@ public:
 	LinphoneVideoDefinition *getReceivedVideoDefinition() const;
 	float getSentFps() const;
 	LinphoneVideoDefinition *getSentVideoDefinition() const;
-	const OrtpPayloadType *getUsedVideoCodec() const;
-	LinphonePayloadType *getUsedVideoPayloadType() const;
+	std::shared_ptr<const PayloadType> getUsedVideoPayloadType() const;
 	LinphoneMediaDirection getVideoDirection() const;
 	void setVideoDirection(SalStreamDir direction);
 	void setVideoDirection(LinphoneMediaDirection direction);
@@ -93,12 +90,11 @@ public:
 
 	void enableFec(bool value);
 	bool fecEnabled() const;
-	const OrtpPayloadType *getUsedFecCodec() const;
+	std::shared_ptr<const PayloadType> getUsedFecCodec() const;
 
 	void enableRealtimeText(bool value);
 	void setRealtimeTextKeepaliveInterval(unsigned int interval);
-	const OrtpPayloadType *getUsedRealtimeTextCodec() const;
-	LinphonePayloadType *getUsedRealtimeTextPayloadType() const;
+	std::shared_ptr<const PayloadType> getUsedRealtimeTextPayloadType() const;
 	bool realtimeTextEnabled() const;
 	unsigned int realtimeTextKeepaliveInterval() const;
 
diff --git a/src/conference/session/audio-mixer.cpp b/src/conference/session/audio-mixer.cpp
index 86f26db58f..dc0eab8d5a 100644
--- a/src/conference/session/audio-mixer.cpp
+++ b/src/conference/session/audio-mixer.cpp
@@ -94,7 +94,7 @@ void MS2AudioMixer::disconnectEndpoint(BCTBX_UNUSED(Stream *as), MSAudioEndpoint
 
 RtpProfile *MS2AudioMixer::sMakeDummyProfile(int samplerate) {
 	RtpProfile *prof = rtp_profile_new("dummy");
-	PayloadType *pt = payload_type_clone(&payload_type_l16_mono);
+	OrtpPayloadType *pt = payload_type_clone(&payload_type_l16_mono);
 	pt->clock_rate = samplerate;
 	rtp_profile_set_payload(prof, 0, pt);
 	return prof;
@@ -153,7 +153,8 @@ void MS2AudioMixer::enableMic(bool value) {
 	if (mLocalEndpoint) {
 		bool coreMicrophoneEnabled = !!linphone_core_mic_enabled(mSession.getCore().getCCore());
 		if (!coreMicrophoneEnabled) {
-			lWarning() << "Microphone of the local participant of conference will be muted because the microphone is disabled in the core settings";
+			lWarning() << "Microphone of the local participant of conference will be muted because the microphone is "
+			              "disabled in the core settings";
 		}
 		bool enabled = (value && coreMicrophoneEnabled);
 		bctbx_message("AudioMixer[%p]: mic of local participnt is [%s].", this, enabled ? "enabled" : "disabled");
diff --git a/src/conference/session/ms2-stream.cpp b/src/conference/session/ms2-stream.cpp
index 0601592bf9..9e3da2d974 100644
--- a/src/conference/session/ms2-stream.cpp
+++ b/src/conference/session/ms2-stream.cpp
@@ -1068,10 +1068,10 @@ void MS2Stream::updateDestinations(const OfferAnswerContext &params) {
 
 bool MS2Stream::canIgnorePtimeChange(const OfferAnswerContext &params) {
 	const auto &resultStreamDesc = params.getResultStreamDescription();
-	const PayloadType *pt = getMediaSessionPrivate().getCurrentParams()->getUsedAudioCodec();
-	if (pt != nullptr && pt->send_fmtp != NULL) {
+	auto pt = getMediaSessionPrivate().getCurrentParams()->getUsedAudioPayloadType();
+	if (pt && !pt->getSendFmtp().empty()) {
 		char tmp[30];
-		if (fmtp_get_value(pt->send_fmtp, "ptime", tmp, sizeof(tmp))) {
+		if (fmtp_get_value(pt->getSendFmtp().c_str(), "ptime", tmp, sizeof(tmp))) {
 			return resultStreamDesc.getChosenConfiguration().ptime == atoi(tmp);
 		}
 	}
diff --git a/src/conference/session/streams-group.cpp b/src/conference/session/streams-group.cpp
index 43ed6d27ff..b91f3282b0 100644
--- a/src/conference/session/streams-group.cpp
+++ b/src/conference/session/streams-group.cpp
@@ -295,7 +295,7 @@ MediaSessionPrivate &StreamsGroup::getMediaSessionPrivate() const {
 	return *getMediaSession().getPrivate();
 }
 
-int StreamsGroup::updateAllocatedAudioBandwidth(const PayloadType *pt, int maxbw) {
+int StreamsGroup::updateAllocatedAudioBandwidth(const OrtpPayloadType *pt, int maxbw) {
 	mAudioBandwidth = PayloadTypeHandler::getAudioPayloadTypeBandwidth(pt, maxbw);
 	lInfo() << "Audio bandwidth for StreamsGroup [" << this << "] is " << mAudioBandwidth;
 	return mAudioBandwidth;
diff --git a/src/conference/session/streams.h b/src/conference/session/streams.h
index 7a80e089a2..8ee753f834 100644
--- a/src/conference/session/streams.h
+++ b/src/conference/session/streams.h
@@ -537,7 +537,7 @@ public:
 	Core &getCore() const;
 
 protected:
-	int updateAllocatedAudioBandwidth(const PayloadType *pt, int maxbw);
+	int updateAllocatedAudioBandwidth(const OrtpPayloadType *pt, int maxbw);
 	int getVideoBandwidth(const std::shared_ptr<SalMediaDescription> &md, const SalStreamDescription &desc);
 	void zrtpStarted(Stream *mainZrtpStream);
 	void propagateEncryptionChanged();
diff --git a/src/conference/session/video-mixer.cpp b/src/conference/session/video-mixer.cpp
index bce09ad094..a8a4939084 100644
--- a/src/conference/session/video-mixer.cpp
+++ b/src/conference/session/video-mixer.cpp
@@ -96,7 +96,7 @@ void MS2VideoMixer::setFocus(StreamsGroup *sg) {
 RtpProfile *MS2VideoMixer::sMakeDummyProfile() {
 	RtpProfile *prof = rtp_profile_new("dummy video");
 	LinphonePayloadType *pt = linphone_core_get_payload_type(mSession.getCCore(), "VP8", 90000, -1);
-	PayloadType *ortp_pt = payload_type_clone(linphone_payload_type_get_ortp_pt(pt));
+	OrtpPayloadType *ortp_pt = payload_type_clone(linphone_payload_type_get_ortp_pt(pt));
 	rtp_profile_set_payload(prof, sVP8PayloadTypeNumber, ortp_pt);
 	linphone_payload_type_unref(pt);
 	return prof;
@@ -122,7 +122,7 @@ void MS2VideoMixer::createLocalMember(bool isThumbnail) {
 	if (!mLocalDummyProfile) mLocalDummyProfile = sMakeDummyProfile();
 	MSMediaStreamIO io;
 	int outputBandwidth = getOutputBandwidth() * 1000;
-	PayloadType *pt;
+	OrtpPayloadType *pt;
 
 	memset(&io, 0, sizeof(io));
 
diff --git a/src/core/core-p.h b/src/core/core-p.h
index e125beb206..9e2934a391 100644
--- a/src/core/core-p.h
+++ b/src/core/core-p.h
@@ -187,6 +187,8 @@ public:
 
 	/* centralized method to write down all NatPolicy used by Accounts or Core */
 	void writeNatPolicyConfigurations();
+	void reorderVideoCodecList();
+	int getCodecPriority(const OrtpPayloadType *pt) const;
 	static const Utils::Version conferenceProtocolVersion;
 	static const Utils::Version groupChatProtocolVersion;
 	static const Utils::Version ephemeralProtocolVersion;
@@ -228,6 +230,7 @@ private:
 
 	std::list<std::shared_ptr<Ldap>> mLdapServers; // Persistent list of LDAP servers
 	std::string logLabel;
+	LinphoneCodecPriorityPolicy videoCodecPriorityPolicy = LinphoneCodecPriorityPolicyAuto;
 
 	L_DECLARE_PUBLIC(Core);
 };
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 75aeecb89e..2bb5c2128c 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -81,6 +81,7 @@
 // TODO: Remove me later.
 #include "c-wrapper/c-wrapper.h"
 #include "private.h"
+#include <utils/payload-type-handler.h>
 
 #define LINPHONE_DB "linphone.db"
 #define LINPHONE_CALL_HISTORY_DB "call-history.db"
@@ -630,6 +631,55 @@ void CorePrivate::updateVideoDevice() {
 	}
 }
 
+int CorePrivate::getCodecPriority(const OrtpPayloadType *pt) const {
+	static constexpr int priorityBonusScore = 50;
+	static const std::map<string, int> priorityMap = {{"AV1", 50}, {"H265", 40}, {"H264", 30}, {"VP8", 20}};
+	auto it = priorityMap.find(pt->mime_type);
+
+	if (it != priorityMap.end()) {
+		// lInfo() << pt->mime_type << " has priority " << it->second << " with bonus: " << ((pt->flags &
+		// PAYLOAD_TYPE_PRIORITY_BONUS) ? "yes" : "no");
+		return it->second + ((pt->flags & PAYLOAD_TYPE_PRIORITY_BONUS) ? priorityBonusScore : 0);
+	}
+	return 1000; // return highest priority for unknown codecs, for convenience for whose who want to write plugins.
+}
+
+void CorePrivate::reorderVideoCodecList() {
+	bctbx_list_t *videoCodecList = getCCore()->codecs_conf.video_codecs;
+	bctbx_list_t *elem;
+	std::list<OrtpPayloadType *> newList;
+
+	for (elem = videoCodecList; elem != nullptr; elem = elem->next) {
+		OrtpPayloadType *pt = (OrtpPayloadType *)elem->data;
+		if (videoCodecPriorityPolicy == LinphoneCodecPriorityPolicyAuto) {
+#if defined(__ANDROID__) || (defined(__APPLE__) && TARGET_OS_IPHONE)
+			MSFilterDesc *encoderDesc = ms_factory_get_encoder(getCCore()->factory, pt->mime_type);
+			if (encoderDesc && (encoderDesc->flags & MS_FILTER_IS_HW_ACCELERATED)) {
+				payload_type_set_flag(pt, PAYLOAD_TYPE_PRIORITY_BONUS);
+			} else {
+				payload_type_unset_flag(pt, PAYLOAD_TYPE_PRIORITY_BONUS);
+			}
+#endif
+			newList.push_back(pt);
+		} else
+			payload_type_unset_flag(
+			    pt, PAYLOAD_TYPE_PRIORITY_BONUS); // no notion of bonus in LinphoneCodecPriorityPolicyBasic.
+	}
+	if (videoCodecPriorityPolicy == LinphoneCodecPriorityPolicyAuto) {
+		lInfo() << "Sorting video codec list, new list is:";
+		newList.sort([this](const OrtpPayloadType *pt1, const OrtpPayloadType *pt2) -> bool {
+			return getCodecPriority(pt1) > getCodecPriority(pt2);
+		});
+		bctbx_list_free(videoCodecList);
+		videoCodecList = nullptr;
+		for (auto pt : newList) {
+			lInfo() << pt->mime_type;
+			videoCodecList = bctbx_list_append(videoCodecList, pt);
+		}
+		getCCore()->codecs_conf.video_codecs = videoCodecList;
+	}
+}
+
 // =============================================================================
 
 Core::Core() : Object(*new CorePrivate) {
@@ -2148,4 +2198,19 @@ const std::string &Core::getLabel() const {
 	return d->logLabel;
 }
 
+void Core::setVideoCodecPriorityPolicy(LinphoneCodecPriorityPolicy policy) {
+	L_D();
+	if (linphone_core_ready(getCCore())) {
+		linphone_config_set_int(linphone_core_get_config(getCCore()), "video", "codec_priority_policy", (int)policy);
+	}
+	bool changed = policy != d->videoCodecPriorityPolicy;
+	d->videoCodecPriorityPolicy = policy;
+	if (changed) d->reorderVideoCodecList();
+}
+
+LinphoneCodecPriorityPolicy Core::getVideoCodecPriorityPolicy() const {
+	L_D();
+	return d->videoCodecPriorityPolicy;
+}
+
 LINPHONE_END_NAMESPACE
diff --git a/src/core/core.h b/src/core/core.h
index 8a8b52621d..1b3a4634ed 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -381,6 +381,9 @@ public:
 	void setLabel(const std::string &label);
 	const std::string &getLabel() const;
 
+	void setVideoCodecPriorityPolicy(LinphoneCodecPriorityPolicy policy);
+	LinphoneCodecPriorityPolicy getVideoCodecPriorityPolicy() const;
+
 private:
 	Core();
 
diff --git a/src/payload-type/payload-type.cpp b/src/payload-type/payload-type.cpp
index 7ea6c5c482..f62b14ac27 100644
--- a/src/payload-type/payload-type.cpp
+++ b/src/payload-type/payload-type.cpp
@@ -240,6 +240,11 @@ void PayloadType::setSendFmtp(const string &sendFmtp) {
 	payload_type_set_send_fmtp(mPt, send_fmtp_c);
 }
 
+void PayloadType::setPriorityBonus(bool value) {
+	if (value) payload_type_set_flag(mPt, PAYLOAD_TYPE_PRIORITY_BONUS);
+	else payload_type_unset_flag(mPt, PAYLOAD_TYPE_PRIORITY_BONUS);
+}
+
 int PayloadType::getType() const {
 	return mPt->type;
 }
@@ -352,4 +357,10 @@ bool PayloadType::isUsable() const {
 	return linphone_core_is_payload_type_usable_for_bandwidth(cCore, mPt, maxbw);
 }
 
+bool PayloadType::weakEquals(const PayloadType &other) const {
+	if (mPt == nullptr || other.mPt == nullptr) return false;
+	return mPt->type == other.mPt->type && mPt->clock_rate == other.mPt->clock_rate &&
+	       strcasecmp(mPt->mime_type, other.mPt->mime_type) == 0 && mPt->channels == other.mPt->channels;
+}
+
 LINPHONE_END_NAMESPACE
diff --git a/src/payload-type/payload-type.h b/src/payload-type/payload-type.h
index 893671f75f..02a1941153 100644
--- a/src/payload-type/payload-type.h
+++ b/src/payload-type/payload-type.h
@@ -72,6 +72,8 @@ public:
 	bool isEnabled() const;
 	bool isVbr() const;
 	bool isUsable() const;
+	void setPriorityBonus(bool value);
+	bool weakEquals(const PayloadType &other) const;
 
 private:
 	OrtpPayloadType *mPt;
diff --git a/src/sal/offeranswer.cpp b/src/sal/offeranswer.cpp
index dfed5f5893..beea448a69 100644
--- a/src/sal/offeranswer.cpp
+++ b/src/sal/offeranswer.cpp
@@ -305,6 +305,15 @@ std::list<OrtpPayloadType *> OfferAnswerEngine::matchPayloads(MSFactory *factory
 			payload_type_set_flag(cloned_p1, PAYLOAD_TYPE_FROZEN_NUMBER);
 			res.push_back(cloned_p1);
 		}
+	} else {
+		/* case of generating an answer */
+		/* resort result list to put high-priority codecs first */
+		res.sort([](const PayloadType *p1, const PayloadType *p2) -> bool {
+			if (p1->flags & PAYLOAD_TYPE_PRIORITY_BONUS && !(p2->flags & PAYLOAD_TYPE_PRIORITY_BONUS)) {
+				return true;
+			}
+			return false;
+		});
 	}
 	return res;
 }
diff --git a/src/signal-information/signal-information.h b/src/signal-information/signal-information.h
index 06ea3d5c08..4086f67749 100644
--- a/src/signal-information/signal-information.h
+++ b/src/signal-information/signal-information.h
@@ -21,6 +21,7 @@
 #define SIGNAL_INFORMATION_H
 
 #include "linphone/api/c-types.h"
+#include "linphone/enums/c-enums.h"
 #include <belle-sip/object++.hh>
 
 using namespace std;
diff --git a/src/utils/payload-type-handler.h b/src/utils/payload-type-handler.h
index 9ae211c1f6..c52f8a3812 100644
--- a/src/utils/payload-type-handler.h
+++ b/src/utils/payload-type-handler.h
@@ -32,6 +32,7 @@
 #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0
 #define PAYLOAD_TYPE_BITRATE_OVERRIDE PAYLOAD_TYPE_USER_FLAG_3
 #define PAYLOAD_TYPE_FROZEN_NUMBER PAYLOAD_TYPE_USER_FLAG_4
+#define PAYLOAD_TYPE_PRIORITY_BONUS PAYLOAD_TYPE_USER_FLAG_5 // Used for codec sorting and offer-answer.
 
 // =============================================================================
 
diff --git a/tester/audio_bypass_tester.c b/tester/audio_bypass_tester.c
index a46c72fe74..0e32ddf932 100644
--- a/tester/audio_bypass_tester.c
+++ b/tester/audio_bypass_tester.c
@@ -487,9 +487,8 @@ static void audio_bypass(void) {
 	BC_ASSERT_TRUE(call_ok);
 	if (!call_ok) goto end;
 
-	BC_ASSERT_STRING_EQUAL(linphone_call_params_get_used_audio_codec(
-	                           linphone_call_get_current_params(linphone_core_get_current_call(marie_lc)))
-	                           ->mime_type,
+	BC_ASSERT_STRING_EQUAL(linphone_payload_type_get_mime_type(linphone_call_params_get_used_audio_payload_type(
+	                           linphone_call_get_current_params(linphone_core_get_current_call(marie_lc)))),
 	                       "L16");
 
 	wait_for_until(pauline_lc, marie_lc, NULL, 0, 5000); // hello44100.wav is 4 seconds long
diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c
index 1012ec72de..a906047c70 100644
--- a/tester/call_single_tester.c
+++ b/tester/call_single_tester.c
@@ -5077,9 +5077,9 @@ static void call_with_in_dialog_codec_change_base(bool_t no_sdp) {
 	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
 	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1));
 	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
-	BC_ASSERT_STRING_EQUAL("PCMA", payload_type_get_mime(linphone_call_params_get_used_audio_codec(
+	BC_ASSERT_STRING_EQUAL("PCMA", linphone_payload_type_get_mime_type(linphone_call_params_get_used_audio_payload_type(
 	                                   linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))));
-	BC_ASSERT_STRING_EQUAL("PCMA", payload_type_get_mime(linphone_call_params_get_used_audio_codec(
+	BC_ASSERT_STRING_EQUAL("PCMA", linphone_payload_type_get_mime_type(linphone_call_params_get_used_audio_payload_type(
 	                                   linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))));
 	wait_for_until(marie->lc, pauline->lc, &dummy, 1, 5000);
 	BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(marie), 70, int, "%i");
diff --git a/tester/local_conference_tester_functions.cpp b/tester/local_conference_tester_functions.cpp
index c5e9726efc..52358d26b1 100644
--- a/tester/local_conference_tester_functions.cpp
+++ b/tester/local_conference_tester_functions.cpp
@@ -1746,18 +1746,20 @@ void update_sequence_number(bctbx_list_t **participants_info,
 
 static bool have_common_audio_payload(LinphoneCoreManager *mgr1, LinphoneCoreManager *mgr2) {
 	bool found = false;
-	const bctbx_list_t *elem = linphone_core_get_audio_codecs(mgr1->lc);
-	for (; elem != NULL; elem = elem->next) {
-		PayloadType *pt1 = (PayloadType *)elem->data;
-		if (linphone_core_payload_type_enabled(mgr1->lc, pt1) == TRUE) {
-			LinphonePayloadType *pt2 =
-			    linphone_core_get_payload_type(mgr2->lc, pt1->mime_type, pt1->clock_rate, pt1->channels);
+	bctbx_list_t *codecs = linphone_core_get_audio_payload_types(mgr1->lc);
+	for (bctbx_list_t *elem = codecs; elem != NULL; elem = elem->next) {
+		LinphonePayloadType *pt1 = (LinphonePayloadType *)elem->data;
+		if (linphone_payload_type_enabled(pt1) == TRUE) {
+			LinphonePayloadType *pt2 = linphone_core_get_payload_type(
+			    mgr2->lc, linphone_payload_type_get_mime_type(pt1), linphone_payload_type_get_clock_rate(pt1),
+			    linphone_payload_type_get_channels(pt1));
 			if (pt2 && linphone_payload_type_enabled(pt2)) {
 				found = true;
 			}
 			linphone_payload_type_unref(pt2);
 		}
 	}
+	bctbx_list_free_with_data(codecs, (bctbx_list_free_func)linphone_payload_type_unref);
 	return found;
 }
 
diff --git a/tester/offeranswer_tester.cpp b/tester/offeranswer_tester.cpp
index 346eb13e7f..d9ce61982c 100644
--- a/tester/offeranswer_tester.cpp
+++ b/tester/offeranswer_tester.cpp
@@ -65,16 +65,16 @@ static void start_with_no_config(void) {
 static void check_payload_type_numbers(LinphoneCall *call1, LinphoneCall *call2, int expected_number) {
 	const LinphoneCallParams *params = linphone_call_get_current_params(call1);
 	if (!BC_ASSERT_PTR_NOT_NULL(params)) return;
-	const PayloadType *pt = linphone_call_params_get_used_audio_codec(params);
+	const LinphonePayloadType *pt = linphone_call_params_get_used_audio_payload_type(params);
 	BC_ASSERT_PTR_NOT_NULL(pt);
 	if (pt) {
-		BC_ASSERT_EQUAL(payload_type_get_number(pt), expected_number, int, "%d");
+		BC_ASSERT_EQUAL(linphone_payload_type_get_number(pt), expected_number, int, "%d");
 	}
 	params = linphone_call_get_current_params(call2);
-	pt = linphone_call_params_get_used_audio_codec(params);
+	pt = linphone_call_params_get_used_audio_payload_type(params);
 	BC_ASSERT_PTR_NOT_NULL(pt);
 	if (pt) {
-		BC_ASSERT_EQUAL(payload_type_get_number(pt), expected_number, int, "%d");
+		BC_ASSERT_EQUAL(linphone_payload_type_get_number(pt), expected_number, int, "%d");
 	}
 }
 
@@ -144,13 +144,13 @@ static void simple_call_with_fmtps(void) {
 	pauline_call = linphone_core_get_current_call(pauline->lc);
 	BC_ASSERT_PTR_NOT_NULL(pauline_call);
 	if (pauline_call) {
-		LinphonePayloadType *pt =
+		const LinphonePayloadType *pt =
 		    linphone_call_params_get_used_audio_payload_type(linphone_call_get_current_params(pauline_call));
 		BC_ASSERT_PTR_NOT_NULL(pt);
 		if (pt) {
 			BC_ASSERT_STRING_EQUAL(linphone_payload_type_get_send_fmtp(pt), "parles-plus-fort=1");
 		}
-		linphone_payload_type_unref(pt);
+
 		pt = linphone_call_params_get_used_audio_payload_type(
 		    linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)));
 		BC_ASSERT_PTR_NOT_NULL(pt);
@@ -159,7 +159,6 @@ static void simple_call_with_fmtps(void) {
 			           linphone_payload_type_get_recv_fmtp(pt));
 			BC_ASSERT_STRING_EQUAL(linphone_payload_type_get_recv_fmtp(pt), "parles-plus-fort=1");
 		}
-		linphone_payload_type_unref(pt);
 	}
 
 	end_call(marie, pauline);
@@ -228,13 +227,12 @@ static void h264_call_with_fmtps(void) {
 	pauline_call = linphone_core_get_current_call(pauline->lc);
 	BC_ASSERT_PTR_NOT_NULL(pauline_call);
 	if (pauline_call) {
-		LinphonePayloadType *pt =
+		const LinphonePayloadType *pt =
 		    linphone_call_params_get_used_video_payload_type(linphone_call_get_current_params(pauline_call));
 		BC_ASSERT_PTR_NOT_NULL(pt);
 		if (pt) {
 			BC_ASSERT_PTR_NOT_NULL(strstr(linphone_payload_type_get_recv_fmtp(pt), "packetization-mode=1"));
 		}
-		linphone_payload_type_unref(pt);
 		pt = linphone_call_params_get_used_video_payload_type(
 		    linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)));
 		BC_ASSERT_PTR_NOT_NULL(pt);
@@ -244,7 +242,6 @@ static void h264_call_with_fmtps(void) {
 			BC_ASSERT_PTR_NOT_NULL(strstr(linphone_payload_type_get_recv_fmtp(pt), "packetization-mode=1"));
 			BC_ASSERT_PTR_NOT_NULL(strstr(linphone_payload_type_get_recv_fmtp(pt), "packetization-mode=1"));
 		}
-		linphone_payload_type_unref(pt);
 	}
 
 	end_call(marie, pauline);
@@ -377,7 +374,7 @@ static void h264_call_receiver_with_no_h264_support(void) {
 	pauline_call = linphone_core_get_current_call(pauline->lc);
 	BC_ASSERT_PTR_NOT_NULL(pauline_call);
 	if (pauline_call) {
-		LinphonePayloadType *pt =
+		const LinphonePayloadType *pt =
 		    linphone_call_params_get_used_video_payload_type(linphone_call_get_current_params(pauline_call));
 		BC_ASSERT_PTR_NULL(pt);
 		pt = linphone_call_params_get_used_video_payload_type(
@@ -427,13 +424,12 @@ static void h264_call_without_packetization_mode(void) {
 	pauline_call = linphone_core_get_current_call(pauline->lc);
 	BC_ASSERT_PTR_NOT_NULL(pauline_call);
 	if (pauline_call) {
-		LinphonePayloadType *pt =
+		const LinphonePayloadType *pt =
 		    linphone_call_params_get_used_video_payload_type(linphone_call_get_current_params(pauline_call));
 		BC_ASSERT_PTR_NOT_NULL(pt);
 		if (pt) {
 			BC_ASSERT_PTR_NULL(strstr(linphone_payload_type_get_recv_fmtp(pt), "packetization-mode"));
 		}
-		linphone_payload_type_unref(pt);
 		pt = linphone_call_params_get_used_video_payload_type(
 		    linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)));
 		BC_ASSERT_PTR_NOT_NULL(pt);
@@ -443,7 +439,6 @@ static void h264_call_without_packetization_mode(void) {
 			BC_ASSERT_PTR_NULL(strstr(linphone_payload_type_get_recv_fmtp(pt), "packetization-mode"));
 			BC_ASSERT_PTR_NULL(strstr(linphone_payload_type_get_recv_fmtp(pt), "packetization-mode"));
 		}
-		linphone_payload_type_unref(pt);
 	}
 
 	end_call(marie, pauline);
@@ -1090,6 +1085,134 @@ static void call_with_unknown_stream_accepted_2(void) {
 	_call_with_unknown_stream(TRUE, TRUE);
 }
 
+static void activate_video_and_ice(LinphoneCoreManager *m) {
+	LinphoneVideoActivationPolicy *pol = linphone_factory_create_video_activation_policy(linphone_factory_get());
+	LinphoneNatPolicy *nat_policy;
+	LinphoneAccountParams *account_params;
+	LinphoneAccount *account;
+	linphone_video_activation_policy_set_automatically_initiate(pol, TRUE);
+	linphone_video_activation_policy_set_automatically_accept(pol, TRUE);
+	linphone_core_set_video_activation_policy(m->lc, pol);
+	linphone_video_activation_policy_unref(pol);
+
+	linphone_core_enable_video_capture(m->lc, TRUE);
+	linphone_core_enable_video_display(m->lc, TRUE);
+
+	nat_policy = linphone_core_create_nat_policy(m->lc);
+	linphone_nat_policy_enable_ice(nat_policy, TRUE);
+
+	account = linphone_core_get_default_account(m->lc);
+	account_params = linphone_account_params_clone(linphone_account_get_params(account));
+	linphone_account_params_set_nat_policy(account_params, nat_policy);
+	linphone_account_set_params(account, account_params);
+	linphone_account_params_unref(account_params);
+	linphone_nat_policy_unref(nat_policy);
+
+	linphone_core_set_video_device(m->lc, liblinphone_tester_static_image_id);
+}
+
+static bool_t codec_appears_first(LinphoneCore *lc, const char *codec) {
+	bctbx_list_t *codec_list = linphone_core_get_video_payload_types(lc);
+	LinphonePayloadType *pt = (LinphonePayloadType *)codec_list->data;
+	bool_t ret = strcasecmp(codec, linphone_payload_type_get_mime_type(pt)) == 0;
+	bctbx_list_free_with_data(codec_list, (bctbx_list_free_func)linphone_payload_type_unref);
+	return ret;
+}
+
+static const char *call_selected_codec(LinphoneCall *call) {
+	const LinphoneCallParams *current_params = linphone_call_get_current_params(call);
+	const LinphonePayloadType *pt = linphone_call_params_get_used_video_payload_type(current_params);
+	if (BC_ASSERT_PTR_NOT_NULL(pt)) {
+		return linphone_payload_type_get_mime_type(pt);
+	}
+	return "";
+}
+
+static void check_linphonerc_config(const char *rcfile) {
+	char *path = bc_tester_res(rcfile);
+	if (BC_ASSERT_PTR_NOT_NULL(path)) {
+		LinphoneConfig *config = linphone_factory_create_config(linphone_factory_get(), path);
+		if (BC_ASSERT_PTR_NOT_NULL(config)) {
+			BC_ASSERT_STRING_EQUAL(linphone_config_get_string(config, "video", "codec_priority_policy", "unset"),
+			                       "unset");
+			linphone_config_unref(config);
+		}
+		bc_free(path);
+	}
+}
+
+static void call_with_video_codec_priority_policy(void) {
+	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
+	LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc");
+	LinphonePayloadType *vp8, *av1;
+	LinphoneCall *marie_call, *pauline_call;
+
+	vp8 = linphone_core_get_payload_type(pauline->lc, "VP8", 90000, -1);
+	av1 = linphone_core_get_payload_type(pauline->lc, "AV1", 90000, -1);
+
+	if (!vp8 || !av1) {
+		ms_warning("This test requires both VP8 and AV1 video codecs, skipped.");
+		goto end;
+	}
+	activate_video_and_ice(marie);
+	activate_video_and_ice(pauline);
+
+	/* Make sure that configuration files do not mention codec_priority_policy.*/
+	check_linphonerc_config("rcfiles/marie_rc");
+	check_linphonerc_config("rcfiles/pauline_tcp_rc");
+
+	/* PolicyAuto is the default one. However Marie has a video codec list defined, so in absence of
+	 [video]video_priority_policy item written in its configuration file, we must assume it is using the basic policy.
+   */
+	BC_ASSERT_TRUE(linphone_core_get_video_codec_priority_policy(marie->lc) == LinphoneCodecPriorityPolicyBasic);
+	BC_ASSERT_TRUE(linphone_core_get_video_codec_priority_policy(pauline->lc) == LinphoneCodecPriorityPolicyAuto);
+
+	BC_ASSERT_TRUE(codec_appears_first(marie->lc, "AV1"));
+	BC_ASSERT_TRUE(codec_appears_first(pauline->lc, "AV1"));
+
+	/* this is to force to re-compute the codec list order: */
+	linphone_core_set_video_codec_priority_policy(pauline->lc, LinphoneCodecPriorityPolicyBasic);
+	/* AV1 is before VP8 by default. Give an artificial bonus to VP8. Normally this is done at startup*/
+	linphone_payload_type_set_priority_bonus(vp8, TRUE); // this function is not public, apps should not do this.
+
+	linphone_core_set_video_codec_priority_policy(pauline->lc, LinphoneCodecPriorityPolicyAuto);
+	/* now vp8 shall appear first */
+	BC_ASSERT_TRUE(codec_appears_first(pauline->lc, "VP8"));
+
+	marie_call = linphone_core_invite_address(marie->lc, pauline->identity);
+	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1));
+	pauline_call = linphone_core_get_current_call(pauline->lc);
+	if (!BC_ASSERT_PTR_NOT_NULL(pauline_call)) goto end;
+	linphone_call_accept(pauline_call);
+	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
+	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
+	BC_ASSERT_STRING_EQUAL(call_selected_codec(marie_call), "VP8");
+	BC_ASSERT_STRING_EQUAL(call_selected_codec(pauline_call), "VP8");
+	/* Now comes the ICE re-INVITE */
+	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
+	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
+	/* Assert that the ICE re-invite did not change the selected codec */
+	BC_ASSERT_STRING_EQUAL(call_selected_codec(marie_call), "VP8");
+	BC_ASSERT_STRING_EQUAL(call_selected_codec(pauline_call), "VP8");
+	wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000);
+
+	linphone_call_terminate(pauline_call);
+	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
+	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1));
+	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
+	BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
+	/* Assert the priority policy for pauline is now set */
+	BC_ASSERT_STRING_EQUAL(
+	    linphone_config_get_string(linphone_core_get_config(pauline->lc), "video", "codec_priority_policy", "unset"),
+	    "1");
+
+end:
+	if (av1) linphone_payload_type_unref(av1);
+	if (vp8) linphone_payload_type_unref(vp8);
+	linphone_core_manager_destroy(marie);
+	linphone_core_manager_destroy(pauline);
+}
+
 #endif
 
 static test_t offeranswer_tests[] = {
@@ -1163,7 +1286,8 @@ static test_t offeranswer_tests[] = {
     TEST_NO_TAG("Call with unknown stream", call_with_unknown_stream),
     TEST_NO_TAG("Call with unknown stream, accepted", call_with_unknown_stream_accepted),
     TEST_NO_TAG("Call with unknown stream, accepted 2", call_with_unknown_stream_accepted_2),
-    TEST_NO_TAG("Call with 2 audio streams", call_with_two_audio_streams)
+    TEST_NO_TAG("Call with 2 audio streams", call_with_two_audio_streams),
+    TEST_NO_TAG("Call with video codec priority policy auto", call_with_video_codec_priority_policy)
 #endif
 };
 
diff --git a/tester/session_timers_tester.c b/tester/session_timers_tester.c
index 5566730986..b54434b5db 100644
--- a/tester/session_timers_tester.c
+++ b/tester/session_timers_tester.c
@@ -616,10 +616,10 @@ static void session_timer_interval_smaller(void) {
 	BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 3));
 	BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallUpdatedByRemote, 1));
 	BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
-	BC_ASSERT_STRING_EQUAL(payload_type_get_mime(linphone_call_params_get_used_audio_codec(
+	BC_ASSERT_STRING_EQUAL(linphone_payload_type_get_mime_type(linphone_call_params_get_used_audio_payload_type(
 	                           linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))),
 	                       "PCMA");
-	BC_ASSERT_STRING_EQUAL(payload_type_get_mime(linphone_call_params_get_used_audio_codec(
+	BC_ASSERT_STRING_EQUAL(linphone_payload_type_get_mime_type(linphone_call_params_get_used_audio_payload_type(
 	                           linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))),
 	                       "PCMA");
 	wait_for_until(pauline->lc, marie->lc, &dummy, 1, 5000);
-- 
GitLab