diff --git a/CHANGELOG.md b/CHANGELOG.md
index b157d8f689f7885c2166e09235fa2acd7de1e657..aae4dc2a03018f77d9865051aa4bd9f778e74e32 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -30,6 +30,7 @@ This changelog file was started on October 2019. Previous changes were more or l
 - linphone_core_interpret_url() will unescape characters first if possible if only a username is given as input parameter.
 - linphone_chat_message_cancel_file_transfer() no longer deletes the file for outgoing messages.
 - magic search result created from filter now applies the international prefix of the default proxy config if possible.
+- file transfer progress callback will be at most notified 100 times.
 
 ### Fixed
 - Internal refactoring of management of locally played tones, in order to fix race conditions.
diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp
index a40173831db13200bb83094d29a3c38ca191f2e3..4e97ce70bc9c5843e1348958eefe24e8bd46102d 100644
--- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp
+++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp
@@ -109,6 +109,11 @@ void FileTransferChatMessageModifier::fileTransferOnProgress (
 	if (!message)
 		return;
 
+	size_t percentage = offset * 100 / total;
+	if (percentage <= lastNotifiedPercentage) {
+		return;
+	}
+
 	LinphoneChatMessage *msg = L_GET_C_BACK_PTR(message);
 	LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg);
 	LinphoneContent *content = L_GET_C_BACK_PTR((Content *)currentFileContentToTransfer);
@@ -120,6 +125,7 @@ void FileTransferChatMessageModifier::fileTransferOnProgress (
 		linphone_core_notify_file_transfer_progress_indication(message->getCore()->getCCore(), msg, content, offset, total);
 	}
 	_linphone_chat_message_notify_file_transfer_progress_indication(msg, content, offset, total);
+	lastNotifiedPercentage = percentage;
 }
 
 static int _chat_message_on_send_body (
@@ -520,6 +526,8 @@ int FileTransferChatMessageModifier::uploadFile (belle_sip_body_handler_t *bh) {
 		currentFileContentToTransfer->setFilePath(message->getPrivate()->getFileTransferFilepath());
 	}
 
+	lastNotifiedPercentage = 0;
+
 	belle_http_request_listener_callbacks_t cbs = { 0 };
 	cbs.process_response = _chat_message_process_response_from_post_file;
 	cbs.process_io_error = _chat_message_process_io_error_upload;
@@ -1092,6 +1100,7 @@ bool FileTransferChatMessageModifier::downloadFile (
 		currentFileContentToTransfer->setFilePath(message->getPrivate()->getFileTransferFilepath());
 	}
 
+	lastNotifiedPercentage = 0;
 	lInfo() << "Downloading file transfer content [" << fileTransferContent << "], removing it to keep only the file content [" << fileContent << "]";
 
 	belle_http_request_listener_callbacks_t cbs = { 0 };
diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.h b/src/chat/modifier/file-transfer-chat-message-modifier.h
index 1e32a520034e996e0ea8bd3a4ce6948f401c9dd4..2725c900f4d006903643933e813c5132b216a5a2 100644
--- a/src/chat/modifier/file-transfer-chat-message-modifier.h
+++ b/src/chat/modifier/file-transfer-chat-message-modifier.h
@@ -85,6 +85,8 @@ private:
 	belle_http_request_listener_t *httpListener = nullptr;
 	belle_http_provider_t *provider  = nullptr;
 
+	size_t lastNotifiedPercentage = 0;
+
 	BackgroundTask bgTask;
 };
 
diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp
index 73a1dadd97a5d393a711ed5421df87030ce28d07..39bd59d8b1cbdf026179f4880b28f9ac37a3bc25 100644
--- a/src/conference/session/media-session.cpp
+++ b/src/conference/session/media-session.cpp
@@ -243,33 +243,40 @@ bool MediaSessionPrivate::failure () {
 			break;
 		case SalReasonUnsupportedContent: /* This is for compatibility: linphone sent 415 because of SDP offer answer failure */
 		case SalReasonNotAcceptable:
-			lInfo() << "Outgoing CallSession [" << q << "] failed with SRTP and/or AVPF enabled";
-			if ((state == CallSession::State::OutgoingInit) || (state == CallSession::State::OutgoingProgress)
-				|| (state == CallSession::State::OutgoingRinging) /* Push notification case */ || (state == CallSession::State::OutgoingEarlyMedia)) {
-				for (int i = 0; i < localDesc->nb_streams; i++) {
-					if (!sal_stream_description_enabled(&localDesc->streams[i]))
-						continue;
-					if (getParams()->getMediaEncryption() == LinphoneMediaEncryptionSRTP) {
-						if (getParams()->avpfEnabled()) {
-							if (i == 0)
-								lInfo() << "Retrying CallSession [" << q << "] with SAVP";
-							getParams()->enableAvpf(false);
-							restartInvite();
-							return true;
-						} else if (!linphone_core_is_media_encryption_mandatory(q->getCore()->getCCore())) {
+			if ((state == CallSession::State::OutgoingInit) 
+				|| (state == CallSession::State::OutgoingProgress)
+				|| (state == CallSession::State::OutgoingRinging) /* Push notification case */ 
+				|| (state == CallSession::State::OutgoingEarlyMedia)) {
+				bool mediaEncrptionSrtp = getParams()->getMediaEncryption() == LinphoneMediaEncryptionSRTP;
+				bool avpfEnabled = getParams()->avpfEnabled();
+				if (mediaEncrptionSrtp || avpfEnabled) {
+					lInfo() << "Outgoing CallSession [" << q << "] failed with SRTP and/or AVPF enabled";
+
+					for (int i = 0; i < localDesc->nb_streams; i++) {
+						if (!sal_stream_description_enabled(&localDesc->streams[i]))
+							continue;
+						if (mediaEncrptionSrtp) {
+							if (avpfEnabled) {
+								if (i == 0)
+									lInfo() << "Retrying CallSession [" << q << "] with SAVP";
+								getParams()->enableAvpf(false);
+								restartInvite();
+								return true;
+							} else if (!linphone_core_is_media_encryption_mandatory(q->getCore()->getCCore())) {
+								if (i == 0)
+									lInfo() << "Retrying CallSession [" << q << "] with AVP";
+								getParams()->setMediaEncryption(LinphoneMediaEncryptionNone);
+								memset(localDesc->streams[i].crypto, 0, sizeof(localDesc->streams[i].crypto));
+								restartInvite();
+								return true;
+							}
+						} else if (avpfEnabled) {
 							if (i == 0)
 								lInfo() << "Retrying CallSession [" << q << "] with AVP";
-							getParams()->setMediaEncryption(LinphoneMediaEncryptionNone);
-							memset(localDesc->streams[i].crypto, 0, sizeof(localDesc->streams[i].crypto));
+							getParams()->enableAvpf(false);
 							restartInvite();
 							return true;
 						}
-					} else if (getParams()->avpfEnabled()) {
-						if (i == 0)
-							lInfo() << "Retrying CallSession [" << q << "] with AVP";
-						getParams()->enableAvpf(false);
-						restartInvite();
-						return true;
 					}
 				}
 			}
diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h
index 56cb659585c590f8a6fb446d7547741a9f95fc80..cf6b7207202475e1e92e01becc33d0dea6ff5094 100644
--- a/tester/liblinphone_tester.h
+++ b/tester/liblinphone_tester.h
@@ -245,6 +245,7 @@ typedef struct _stats {
 	int number_of_LinphoneIsComposingActiveReceived;
 	int number_of_LinphoneIsComposingIdleReceived;
 	int progress_of_LinphoneFileTransfer;
+	int number_of_LinphoneFileTransfer;
 
 	int number_of_LinphoneChatRoomConferenceJoined;
 	int number_of_LinphoneChatRoomEphemeralTimerStarted;
@@ -466,6 +467,7 @@ void _receive_file_plus_text(bctbx_list_t *coresList, LinphoneCoreManager *lcm,
 
 LinphoneBuffer * tester_memory_file_transfer_send(LinphoneChatMessage *message, LinphoneContent* content, size_t offset, size_t size);
 void file_transfer_progress_indication(LinphoneChatMessage *message, LinphoneContent* content, size_t offset, size_t total);
+void file_transfer_progress_indication_2(LinphoneChatMessage *message, LinphoneContent* content, size_t offset, size_t total);
 void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room);
 void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg);
 void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
diff --git a/tester/message_tester.c b/tester/message_tester.c
index 09dbde00a1b523c8a0058c78047349b1c749624a..5fdaa6e32f4c4a29835ffb260f7b38330ef00cba 100644
--- a/tester/message_tester.c
+++ b/tester/message_tester.c
@@ -79,7 +79,7 @@ LinphoneChatMessage* create_message_from_sintel_trailer_legacy(LinphoneChatRoom
 	return msg;
 }
 
-LinphoneChatMessage* create_message_from_sintel_trailer(LinphoneChatRoom *chat_room) {
+LinphoneChatMessage* _create_message_from_sintel_trailer(LinphoneChatRoom *chat_room, bool_t use_alt_file_transfer_progress_indication_cb) {
 	FILE *file_to_send = NULL;
 	LinphoneChatMessageCbs *cbs;
 	LinphoneContent* content;
@@ -103,7 +103,11 @@ LinphoneChatMessage* create_message_from_sintel_trailer(LinphoneChatRoom *chat_r
 	cbs = linphone_factory_create_chat_message_cbs(linphone_factory_get());
 	linphone_chat_message_cbs_set_file_transfer_send_chunk(cbs, tester_file_transfer_send_2);
 	linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed);
-	linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
+	if (use_alt_file_transfer_progress_indication_cb) {
+		linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication_2);
+	} else {
+		linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
+	}
 	BC_ASSERT_PTR_NOT_NULL(linphone_content_get_user_data(content));
 	linphone_chat_message_add_callbacks(msg, cbs);
 	linphone_chat_message_cbs_unref(cbs);
@@ -113,6 +117,10 @@ LinphoneChatMessage* create_message_from_sintel_trailer(LinphoneChatRoom *chat_r
 	return msg;
 }
 
+LinphoneChatMessage* create_message_from_sintel_trailer(LinphoneChatRoom *chat_room) {
+	return _create_message_from_sintel_trailer(chat_room, FALSE);
+}
+
 LinphoneChatMessage* create_file_transfer_message_from_sintel_trailer(LinphoneChatRoom *chat_room) {
 	FILE *file_to_send = NULL;
 	LinphoneChatMessageCbs *cbs;
@@ -1345,8 +1353,8 @@ static void file_transfer_2_messages_simultaneously(void) {
 
 		/* create a chatroom on pauline's side */
 		pauline_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
-		msg = create_message_from_sintel_trailer(pauline_room);
-		msg2 = create_message_from_sintel_trailer(pauline_room);
+		msg = _create_message_from_sintel_trailer(pauline_room, FALSE);
+		msg2 = _create_message_from_sintel_trailer(pauline_room, TRUE);
 
 		BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_core_get_chat_rooms(marie->lc)), 0, unsigned int, "%u");
 		if (bctbx_list_size(linphone_core_get_chat_rooms(marie->lc)) == 0) {
@@ -1390,7 +1398,7 @@ static void file_transfer_2_messages_simultaneously(void) {
 					cbs = linphone_factory_create_chat_message_cbs(linphone_factory_get());
 					linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
 					linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received);
-					linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
+					linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication_2);
 					linphone_chat_message_add_callbacks(recvMsg2, cbs);
 					linphone_chat_message_cbs_unref(cbs);
 					linphone_chat_message_download_file(recvMsg2);
diff --git a/tester/tester.c b/tester/tester.c
index d06407364133ec6bbc773cc7f5090a5efb8cb47f..83739fc7dfa7cbc0de57399b07ca8e2128530eb2 100644
--- a/tester/tester.c
+++ b/tester/tester.c
@@ -2636,6 +2636,36 @@ void file_transfer_progress_indication(LinphoneChatMessage *msg, LinphoneContent
 	stats *counters = get_stats(lc);
 	char *address = linphone_address_as_string(linphone_chat_message_is_outgoing(msg) ? to_address : from_address);
 
+	if (progress == 0) {
+		counters->number_of_LinphoneFileTransfer = 0;
+	}
+	counters->number_of_LinphoneFileTransfer++;
+
+	BC_ASSERT_EQUAL(linphone_chat_message_get_state(msg), LinphoneChatMessageStateFileTransferInProgress, int, "%d");
+	bctbx_message(
+		"File transfer  [%d%%] %s of type [%s/%s] %s [%s] \n",
+		progress,
+		linphone_chat_message_is_outgoing(msg) ? "sent" : "received",
+		linphone_content_get_type(content),
+		linphone_content_get_subtype(content),
+		linphone_chat_message_is_outgoing(msg) ? "to" : "from",
+		address
+	);
+	counters->progress_of_LinphoneFileTransfer = progress;
+	if (progress == 100) {
+		counters->number_of_LinphoneFileTransferDownloadSuccessful++;
+		BC_ASSERT_LOWER(counters->number_of_LinphoneFileTransfer, 100, int, "%d");
+	}
+	free(address);
+}
+void file_transfer_progress_indication_2(LinphoneChatMessage *msg, LinphoneContent* content, size_t offset, size_t total) {
+	const LinphoneAddress *from_address = linphone_chat_message_get_from_address(msg);
+	const LinphoneAddress *to_address = linphone_chat_message_get_to_address(msg);
+	int progress = (int)((offset * 100)/total);
+	LinphoneCore *lc = linphone_chat_message_get_core(msg);
+	stats *counters = get_stats(lc);
+	char *address = linphone_address_as_string(linphone_chat_message_is_outgoing(msg) ? to_address : from_address);
+
 	BC_ASSERT_EQUAL(linphone_chat_message_get_state(msg), LinphoneChatMessageStateFileTransferInProgress, int, "%d");
 	bctbx_message(
 		"File transfer  [%d%%] %s of type [%s/%s] %s [%s] \n",