linphone-ios/tester/offeranswer_tester.c
Simon Morlat 16180e2430 change the way payload type numbers are assigned, so that an application can support more payload type than the RTP profile table allows to contain.
Compliance with RFC3264 (offer answer model) is improved, by reusing numbers in case of reINVITEs.
Fix memory leaks
Move offer/answer related tests into a new test suite.
2015-01-21 22:38:46 +01:00

297 lines
10 KiB
C

/*
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#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_pos<speex_codec_pos);
pt=linphone_core_find_payload_type(lc, "speex", 16000, 1);
CU_ASSERT_PTR_NOT_NULL(pt);
if (pt) {
CU_ASSERT_TRUE(linphone_core_payload_type_enabled(lc, pt)==TRUE);
}
linphone_core_destroy(lc);
}
static void check_payload_type_numbers(LinphoneCall *call1, LinphoneCall *call2, int expected_number){
const LinphoneCallParams *params=linphone_call_get_current_params(call1);
const PayloadType *pt=linphone_call_params_get_used_audio_codec(params);
CU_ASSERT_PTR_NOT_NULL(pt);
if (pt){
CU_ASSERT_TRUE(linphone_core_get_payload_type_number(linphone_call_get_core(call1),pt)==expected_number);
}
params=linphone_call_get_current_params(call2);
pt=linphone_call_params_get_used_audio_codec(params);
CU_ASSERT_PTR_NOT_NULL(pt);
if (pt){
CU_ASSERT_TRUE(linphone_core_get_payload_type_number(linphone_call_get_core(call1),pt)==expected_number);
}
}
static void simple_call_with_different_codec_mappings(void) {
int begin;
int leaked_objects;
LinphoneCoreManager* marie;
LinphoneCoreManager* pauline;
LinphoneCall *pauline_call;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_rc");
disable_all_audio_codecs_except_one(marie->lc,"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
};