From 46ed0550a23e82e6a71bb052fc64399db6ad261d Mon Sep 17 00:00:00 2001
From: johan pascal <johan.pascal@belledonne-communications.com>
Date: Mon, 21 Aug 2023 11:29:45 +0200
Subject: [PATCH] Add setting for videostream to fallback to dummy codec when
 the requested one is not found

---
 src/conference/session/video-mixer.cpp  |  3 +
 src/conference/session/video-stream.cpp |  5 ++
 tester/call_video_tester.cpp            | 89 +++++++++++++++++++++++++
 3 files changed, 97 insertions(+)

diff --git a/src/conference/session/video-mixer.cpp b/src/conference/session/video-mixer.cpp
index 62f0673432..bce09ad094 100644
--- a/src/conference/session/video-mixer.cpp
+++ b/src/conference/session/video-mixer.cpp
@@ -116,6 +116,9 @@ void MS2VideoMixer::addLocalParticipant() {
 void MS2VideoMixer::createLocalMember(bool isThumbnail) {
 	LinphoneCore *core = getSession().getCCore();
 	VideoStream *vs = video_stream_new(core->factory, isThumbnail ? 65000 : 65002, isThumbnail ? 65001 : 65003, FALSE);
+	video_stream_set_fallback_to_dummy_codec(
+	    vs, linphone_config_get_bool(linphone_core_get_config(core), "video", "fallback_to_dummy_codec", TRUE));
+
 	if (!mLocalDummyProfile) mLocalDummyProfile = sMakeDummyProfile();
 	MSMediaStreamIO io;
 	int outputBandwidth = getOutputBandwidth() * 1000;
diff --git a/src/conference/session/video-stream.cpp b/src/conference/session/video-stream.cpp
index 6203ef69cd..1804788d8c 100644
--- a/src/conference/session/video-stream.cpp
+++ b/src/conference/session/video-stream.cpp
@@ -287,6 +287,10 @@ void MS2VideoStream::render(const OfferAnswerContext &ctx, CallSession::State ta
 	const MSWebCam *currentCam = video_stream_get_camera(mStream);
 	bool cameraChanged = currentCam && cam && (currentCam != cam);
 
+	video_stream_set_fallback_to_dummy_codec(
+	    mStream,
+	    linphone_config_get_bool(linphone_core_get_config(getCCore()), "video", "fallback_to_dummy_codec", TRUE));
+
 	/* Shutdown preview */
 	if (getCCore()->previewstream) {
 		if (getCCore()->video_conf.reuse_preview_source)
@@ -605,6 +609,7 @@ void MS2VideoStream::stop() {
 	/* In mediastreamer2, stop actually stops and destroys. We immediately need to recreate the stream object for later
 	 * use, keeping the sessions (for RTP, SRTP, ZRTP etc) that were setup at the beginning. */
 	mStream = video_stream_new_with_sessions(getCCore()->factory, &mSessions);
+
 	getMediaSessionPrivate().getCurrentParams()->getPrivate()->setUsedVideoCodec(nullptr);
 }
 
diff --git a/tester/call_video_tester.cpp b/tester/call_video_tester.cpp
index 69272c690a..83b963f98d 100644
--- a/tester/call_video_tester.cpp
+++ b/tester/call_video_tester.cpp
@@ -880,6 +880,94 @@ static void video_call(void) {
 	linphone_core_manager_destroy(pauline);
 }
 
+static void video_call_dummy_codec(void) {
+	LpConfig *lp;
+	LinphoneCoreManager *pauline =
+	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
+	if (linphone_core_get_payload_type(pauline->lc, "h264", -1, -1) != NULL) {
+		bctbx_warning("Test skipped: this test is enabled only when h264 is not available");
+		linphone_core_manager_destroy(pauline);
+		return;
+	}
+	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
+	lp = linphone_core_get_config(marie->lc);
+	linphone_config_set_bool(lp, "video", "fallback_to_dummy_codec", FALSE);
+	linphone_config_set_bool(lp, "video", "dont_check_codecs", TRUE);
+	linphone_core_reload_ms_plugins(marie->lc, NULL); // force codec config reload
+	lp = linphone_core_get_config(pauline->lc);
+	linphone_config_set_bool(lp, "video", "fallback_to_dummy_codec", FALSE);
+	linphone_config_set_bool(lp, "video", "dont_check_codecs", TRUE);
+	linphone_core_reload_ms_plugins(pauline->lc, NULL); // force codec config reload
+	disable_all_video_codecs_except_one(marie->lc, "h264");
+	disable_all_video_codecs_except_one(pauline->lc, "h264");
+	LinphoneCallTestParams marie_test_params = {0}, pauline_test_params = {0};
+
+	linphone_core_set_video_device(marie->lc, "Mire: Mire (synthetic moving picture)");
+	linphone_core_set_video_device(pauline->lc, "Mire: Mire (synthetic moving picture)");
+	linphone_core_enable_video_display(pauline->lc, TRUE);
+	linphone_core_enable_video_capture(pauline->lc, TRUE);
+	linphone_core_enable_video_display(marie->lc, TRUE);
+	linphone_core_enable_video_capture(marie->lc, TRUE);
+
+	/* Perform a call, with fallback to dummy deactivated
+	 * Call is established but the video stream is not uploading data */
+	marie_test_params.base = linphone_core_create_call_params(marie->lc, NULL);
+	linphone_call_params_enable_video(marie_test_params.base, TRUE);
+	pauline_test_params.base = linphone_core_create_call_params(pauline->lc, NULL);
+	linphone_call_params_enable_video(pauline_test_params.base, TRUE);
+
+	BC_ASSERT_TRUE(call_with_params2(marie, pauline, &marie_test_params, &pauline_test_params, FALSE));
+	linphone_call_params_unref(marie_test_params.base);
+	linphone_call_params_unref(pauline_test_params.base);
+	LinphoneCall *pauline_call = linphone_core_get_current_call(pauline->lc);
+	LinphoneCall *marie_call = linphone_core_get_current_call(marie->lc);
+	/* 2 seconds wait and check the videostream is only initialized (and not started) */
+	int dummy = 0;
+	wait_for_until(marie->lc, pauline->lc, &dummy, 1, 2000);
+
+	if (pauline_call && marie_call) {
+		BC_ASSERT_TRUE(media_stream_get_state(linphone_call_get_stream(pauline_call, LinphoneStreamTypeVideo)) ==
+		               MSStreamInitialized);
+		BC_ASSERT_TRUE(media_stream_get_state(linphone_call_get_stream(marie_call, LinphoneStreamTypeVideo)) ==
+		               MSStreamInitialized);
+	} else {
+		BC_FAIL("Fail to get current calls");
+	}
+	end_call(pauline, marie);
+
+	/* Perform a call, with fallback to dummy activated
+	 * Call is established and the video stream is uploading(meaningless) data */
+	lp = linphone_core_get_config(marie->lc);
+	linphone_config_set_bool(lp, "video", "fallback_to_dummy_codec", TRUE);
+	lp = linphone_core_get_config(pauline->lc);
+	linphone_config_set_bool(lp, "video", "fallback_to_dummy_codec", TRUE);
+	marie_test_params.base = linphone_core_create_call_params(marie->lc, NULL);
+	linphone_call_params_enable_video(marie_test_params.base, TRUE);
+	pauline_test_params.base = linphone_core_create_call_params(pauline->lc, NULL);
+	linphone_call_params_enable_video(pauline_test_params.base, TRUE);
+
+	BC_ASSERT_TRUE(call_with_params2(marie, pauline, &marie_test_params, &pauline_test_params, FALSE));
+	linphone_call_params_unref(marie_test_params.base);
+	linphone_call_params_unref(pauline_test_params.base);
+	pauline_call = linphone_core_get_current_call(pauline->lc);
+	marie_call = linphone_core_get_current_call(marie->lc);
+
+	/* 2 seconds wait and check the videostream is started */
+	wait_for_until(marie->lc, pauline->lc, &dummy, 1, 2000);
+	if (pauline_call && marie_call) {
+		BC_ASSERT_TRUE(media_stream_get_state(linphone_call_get_stream(pauline_call, LinphoneStreamTypeVideo)) ==
+		               MSStreamStarted);
+		BC_ASSERT_TRUE(media_stream_get_state(linphone_call_get_stream(marie_call, LinphoneStreamTypeVideo)) ==
+		               MSStreamStarted);
+	} else {
+		BC_FAIL("Fail to get current calls");
+	}
+	end_call(pauline, marie);
+
+	linphone_core_manager_destroy(marie);
+	linphone_core_manager_destroy(pauline);
+}
+
 static void video_call_without_rtcp(void) {
 	LpConfig *lp;
 	LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
@@ -3068,6 +3156,7 @@ static test_t call_video_tests[] = {
     TEST_NO_TAG("Simple video call implicit AVPF to AVPF", video_call_implicit_AVPF_to_AVPF),
     TEST_NO_TAG("Video added by reINVITE, with implicit AVPF", video_call_established_by_reinvite_with_implicit_avpf),
     TEST_NO_TAG("Simple video call", video_call),
+    TEST_NO_TAG("Simple video call fallback to dummy codec", video_call_dummy_codec),
     TEST_NO_TAG("Simple video call without rtcp", video_call_without_rtcp),
     TEST_NO_TAG("Simple ZRTP video call", video_call_zrtp),
     TEST_ONE_TAG("Simple DTLS video call", video_call_dtls, "DTLS"),
-- 
GitLab