/* liblinphone_tester - liblinphone test suite Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "CUnit/Basic.h" #include "linphonecore.h" #include "lpconfig.h" #include "private.h" #include "liblinphone_tester.h" static int get_codec_position(const MSList *l, const char *mime_type, int rate){ const MSList *elem; int i; for (elem=l, i=0; elem!=NULL; elem=elem->next,i++){ PayloadType *pt=(PayloadType*)elem->data; if (strcasecmp(pt->mime_type, mime_type)==0 && pt->clock_rate==rate) return i; } return -1; } /*check basic things about codecs at startup: order and enablement*/ static void start_with_no_config(void){ LinphoneCoreVTable vtable={0}; LinphoneCore *lc=linphone_core_new(&vtable, NULL, NULL, NULL); const MSList *codecs=linphone_core_get_audio_codecs(lc); int opus_codec_pos; int speex_codec_pos=get_codec_position(codecs, "speex", 8000); int speex16_codec_pos=get_codec_position(codecs, "speex", 16000); PayloadType *pt; opus_codec_pos=get_codec_position(codecs, "opus", 48000); if (opus_codec_pos!=-1) CU_ASSERT_TRUE(opus_codec_pos==0); CU_ASSERT_TRUE(speex16_codec_poslc,"pcmu",-1); disable_all_audio_codecs_except_one(pauline->lc,"pcmu",-1); /*marie set a fantasy number to PCMU*/ linphone_core_set_payload_type_number(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMU", 8000, -1), 104); CU_ASSERT_TRUE(call(marie,pauline)); pauline_call=linphone_core_get_current_call(pauline->lc); CU_ASSERT_PTR_NOT_NULL(pauline_call); if (pauline_call){ LinphoneCallParams *params; check_payload_type_numbers(linphone_core_get_current_call(marie->lc), pauline_call, 104); /*make a reinvite in the other direction*/ linphone_core_update_call(pauline->lc, pauline_call, params=linphone_core_create_call_params(pauline->lc, pauline_call)); linphone_call_params_unref(params); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdating,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdatedByRemote,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); /*payload type numbers shall remain the same*/ check_payload_type_numbers(linphone_core_get_current_call(marie->lc), pauline_call, 104); } end_call(marie,pauline); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); leaked_objects=belle_sip_object_get_object_count()-begin; CU_ASSERT_TRUE(leaked_objects==0); if (leaked_objects>0){ belle_sip_object_dump_active_objects(); } } static void call_failed_because_of_codecs(void) { int begin,leaked_objects; belle_sip_object_enable_leak_detector(TRUE); begin=belle_sip_object_get_object_count(); { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* out_call; disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1); disable_all_audio_codecs_except_one(pauline->lc,"pcma",-1); out_call = linphone_core_invite_address(pauline->lc,marie->identity); linphone_call_ref(out_call); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); /*flexisip will retain the 488 until the "urgent reply" timeout (I.E 5s) arrives.*/ CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,7000)); CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonNotAcceptable); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallReleased,0); linphone_call_unref(out_call); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } leaked_objects=belle_sip_object_get_object_count()-begin; CU_ASSERT_TRUE(leaked_objects==0); if (leaked_objects>0){ belle_sip_object_dump_active_objects(); } } static void profile_call(bool_t avpf1, bool_t srtp1, bool_t avpf2, bool_t srtp2, const char *expected_profile) { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); LinphoneProxyConfig *lpc; const LinphoneCallParams *params; if (avpf1) { linphone_core_get_default_proxy(marie->lc, &lpc); linphone_proxy_config_enable_avpf(lpc, TRUE); linphone_proxy_config_set_avpf_rr_interval(lpc, 3); } if (avpf2) { linphone_core_get_default_proxy(pauline->lc, &lpc); linphone_proxy_config_enable_avpf(lpc, TRUE); linphone_proxy_config_set_avpf_rr_interval(lpc, 3); } if (srtp1) { if (linphone_core_media_encryption_supported(marie->lc, LinphoneMediaEncryptionSRTP)) { linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionSRTP); } } if (srtp2) { if (linphone_core_media_encryption_supported(pauline->lc, LinphoneMediaEncryptionSRTP)) { linphone_core_set_media_encryption(pauline->lc, LinphoneMediaEncryptionSRTP); } } CU_ASSERT_TRUE(call(marie, pauline)); CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); params = linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)); CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); params = linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)); CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); linphone_core_terminate_all_calls(marie->lc); CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected, 1); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallConnected, 1); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(marie); } static void avp_to_avp_call(void) { profile_call(FALSE, FALSE, FALSE, FALSE, "RTP/AVP"); } static void avp_to_avpf_call(void) { profile_call(FALSE, FALSE, TRUE, FALSE, "RTP/AVP"); } static void avp_to_savp_call(void) { profile_call(FALSE, FALSE, FALSE, TRUE, "RTP/AVP"); } static void avp_to_savpf_call(void) { profile_call(FALSE, FALSE, TRUE, TRUE, "RTP/AVP"); } static void avpf_to_avp_call(void) { profile_call(TRUE, FALSE, FALSE, FALSE, "RTP/AVPF"); } static void avpf_to_avpf_call(void) { profile_call(TRUE, FALSE, TRUE, FALSE, "RTP/AVPF"); } static void avpf_to_savp_call(void) { profile_call(TRUE, FALSE, FALSE, TRUE, "RTP/AVPF"); } static void avpf_to_savpf_call(void) { profile_call(TRUE, FALSE, TRUE, TRUE, "RTP/AVPF"); } static void savp_to_avp_call(void) { profile_call(FALSE, TRUE, FALSE, FALSE, "RTP/SAVP"); } static void savp_to_avpf_call(void) { profile_call(FALSE, TRUE, TRUE, FALSE, "RTP/SAVP"); } static void savp_to_savp_call(void) { profile_call(FALSE, TRUE, FALSE, TRUE, "RTP/SAVP"); } static void savp_to_savpf_call(void) { profile_call(FALSE, TRUE, TRUE, TRUE, "RTP/SAVP"); } static void savpf_to_avp_call(void) { profile_call(TRUE, TRUE, FALSE, FALSE, "RTP/SAVPF"); } static void savpf_to_avpf_call(void) { profile_call(TRUE, TRUE, TRUE, FALSE, "RTP/SAVPF"); } static void savpf_to_savp_call(void) { profile_call(TRUE, TRUE, FALSE, TRUE, "RTP/SAVPF"); } static void savpf_to_savpf_call(void) { profile_call(TRUE, TRUE, TRUE, TRUE, "RTP/SAVPF"); } static test_t offeranswer_tests[] = { { "Start with no config", start_with_no_config }, { "Call failed because of codecs", call_failed_because_of_codecs }, { "Simple call with different codec mappings", simple_call_with_different_codec_mappings}, { "AVP to AVP call", avp_to_avp_call }, { "AVP to AVPF call", avp_to_avpf_call }, { "AVP to SAVP call", avp_to_savp_call }, { "AVP to SAVPF call", avp_to_savpf_call }, { "AVPF to AVP call", avpf_to_avp_call }, { "AVPF to AVPF call", avpf_to_avpf_call }, { "AVPF to SAVP call", avpf_to_savp_call }, { "AVPF to SAVPF call", avpf_to_savpf_call }, { "SAVP to AVP call", savp_to_avp_call }, { "SAVP to AVPF call", savp_to_avpf_call }, { "SAVP to SAVP call", savp_to_savp_call }, { "SAVP to SAVPF call", savp_to_savpf_call }, { "SAVPF to AVP call", savpf_to_avp_call }, { "SAVPF to AVPF call", savpf_to_avpf_call }, { "SAVPF to SAVP call", savpf_to_savp_call }, { "SAVPF to SAVPF call", savpf_to_savpf_call }, }; test_suite_t offeranswer_test_suite = { "Offer-answer", NULL, NULL, sizeof(offeranswer_tests) / sizeof(offeranswer_tests[0]), offeranswer_tests };