From 16180e24301bad46d60570689b8d11e3a07561de Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 21 Jan 2015 22:36:23 +0100 Subject: [PATCH] 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. --- build/android/liblinphone_tester.mk | 3 +- coreapi/bellesip_sal/sal_op_impl.c | 5 +- coreapi/callbacks.c | 17 ++ coreapi/linphonecall.c | 192 ++++++++++++-- coreapi/linphonecore.c | 394 ++++++++++++---------------- coreapi/linphonecore.h | 11 + coreapi/misc.c | 13 +- coreapi/offeranswer.c | 5 +- coreapi/private.h | 22 +- coreapi/quality_reporting.c | 1 + coreapi/sal.c | 5 +- include/sal/sal.h | 3 +- mediastreamer2 | 2 +- oRTP | 2 +- tester/Makefile.am | 3 +- tester/accountmanager.c | 7 +- tester/call_tester.c | 163 +----------- tester/liblinphone_tester.h | 2 + tester/offeranswer_tester.c | 297 +++++++++++++++++++++ tester/tester.c | 1 + 20 files changed, 704 insertions(+), 444 deletions(-) create mode 100644 tester/offeranswer_tester.c diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index ee2018621..d92bb60b5 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -18,7 +18,8 @@ common_SRC_FILES := \ transport_tester.c \ player_tester.c \ dtmf_tester.c \ - accountmanager.c + accountmanager.c \ + offeranswer_tester.c common_C_INCLUDES += \ $(LOCAL_PATH) \ diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index f9647f7ad..5c953ffc5 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -235,7 +235,10 @@ int sal_ping(SalOp *op, const char *from, const char *to){ void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) { belle_sip_header_user_agent_t* user_agent=belle_sip_message_get_header_by_type(message,belle_sip_header_user_agent_t); char user_agent_string[256]; - if(user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) { + if (user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) { + if (op->base.remote_ua!=NULL){ + ms_free(op->base.remote_ua); + } op->base.remote_ua=ms_strdup(user_agent_string); } } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index c43c84479..2d9ff58ae 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -96,7 +96,23 @@ static void prepare_early_media_forking(LinphoneCall *call){ if (call->videostream){ rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,FALSE); } +} +void linphone_call_update_frozen_payloads(LinphoneCall *call, SalMediaDescription *result_desc){ + SalMediaDescription *local=call->localdesc; + int i; + for(i=0;inb_streams;++i){ + MSList *elem; + for (elem=result_desc->streams[i].payloads;elem!=NULL;elem=elem->next){ + PayloadType *pt=(PayloadType*)elem->data; + if (is_payload_type_number_available(local->streams[i].already_assigned_payloads, payload_type_get_number(pt), NULL)){ + /*new codec, needs to be added to the list*/ + local->streams[i].already_assigned_payloads=ms_list_append(local->streams[i].already_assigned_payloads, payload_type_clone(pt)); + ms_message("LinphoneCall[%p] : payload type %i %s/%i fmtp=%s added to frozen list.", + call, payload_type_get_number(pt), pt->mime_type, pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : NULL); + } + } + } } void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ @@ -181,6 +197,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){ linphone_core_play_named_tone(lc,LinphoneToneCallOnHold); } + linphone_call_update_frozen_payloads(call, new_md); end: if (oldmd) sal_media_description_unref(oldmd); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 498c0accf..3c9dfaf90 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -228,35 +228,154 @@ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t propagate_encryption_changed(call); } -static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){ - MSList *l=NULL; +static int get_max_codec_sample_rate(const MSList *codecs){ + int max_sample_rate=0; const MSList *it; - int nb = 0; - if (max_sample_rate) *max_sample_rate=0; for(it=codecs;it!=NULL;it=it->next){ PayloadType *pt=(PayloadType*)it->data; - if (pt->flags & PAYLOAD_TYPE_ENABLED){ - int sample_rate = payload_type_get_rate(pt); + int sample_rate; + + if( strcasecmp("G722",pt->mime_type) == 0 ){ + /* G722 spec says 8000 but the codec actually requires 16000 */ + sample_rate = 16000; + }else sample_rate=pt->clock_rate; + if (sample_rate>max_sample_rate) max_sample_rate=sample_rate; + } + return max_sample_rate; +} - if( strcasecmp("G722",pt->mime_type) == 0 ){ - /* G722 spec says 8000 but the codec actually requires 16000 */ - ms_debug("Correcting sample rate for G722"); - sample_rate = 16000; - } - - if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){ - ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s", - pt->mime_type,pt->clock_rate,bandwidth_limit); - continue; - } - if (linphone_core_check_payload_type_usability(lc,pt)){ - l=ms_list_append(l,payload_type_clone(pt)); - nb++; - if (max_sample_rate && sample_rate>*max_sample_rate) *max_sample_rate=sample_rate; +static int find_payload_type_number(const MSList *assigned, const PayloadType *pt){ + const MSList *elem; + const PayloadType *candidate=NULL; + for(elem=assigned;elem!=NULL;elem=elem->next){ + const PayloadType *it=(const PayloadType*)elem->data; + if ((strcasecmp(pt->mime_type, payload_type_get_mime(it)) == 0) + && (it->clock_rate==pt->clock_rate) + && (it->channels==pt->channels || pt->channels<=0)) { + candidate=it; + if ((it->recv_fmtp!=NULL && pt->recv_fmtp!=NULL && strcasecmp(it->recv_fmtp, pt->recv_fmtp)==0) + || (it->recv_fmtp==NULL && pt->recv_fmtp==NULL)){ + break;/*exact match*/ } } - if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break; } + return candidate ? payload_type_get_number(candidate) : -1; +} + +bool_t is_payload_type_number_available(const MSList *l, int number, const PayloadType *ignore){ + const MSList *elem; + for (elem=l; elem!=NULL; elem=elem->next){ + const PayloadType *pt=(PayloadType*)elem->data; + if (pt!=ignore && payload_type_get_number(pt)==number) return FALSE; + } + return TRUE; +} + +static void linphone_core_assign_payload_type_numbers(LinphoneCore *lc, MSList *codecs){ + MSList *elem; + int dyn_number=lc->codecs_conf.dyn_pt; + for (elem=codecs; elem!=NULL; elem=elem->next){ + PayloadType *pt=(PayloadType*)elem->data; + int number=payload_type_get_number(pt); + + /*check if number is duplicated: it could be the case if the remote forced us to use a mapping with a previous offer*/ + if (number!=-1 && !(pt->flags & PAYLOAD_TYPE_FROZEN_NUMBER)){ + if (!is_payload_type_number_available(codecs, number, pt)){ + ms_message("Reassigning payload type %i %s/%i because already offered.", number, pt->mime_type, pt->clock_rate); + number=-1; /*need to be re-assigned*/ + } + } + + if (number==-1){ + while(dyn_number<127){ + if (is_payload_type_number_available(codecs, dyn_number, NULL)){ + payload_type_set_number(pt, dyn_number); + dyn_number++; + break; + } + dyn_number++; + } + if (dyn_number==127){ + ms_error("Too many payload types configured ! codec %s/%i is disabled.", pt->mime_type, pt->clock_rate); + payload_type_set_enable(pt, FALSE); + } + } + } +} + +static bool_t has_telephone_event_at_rate(const MSList *tev, int rate){ + const MSList *it; + for(it=tev;it!=NULL;it=it->next){ + const PayloadType *pt=(PayloadType*)it->data; + if (pt->clock_rate==rate) return TRUE; + } + return FALSE; +} + +static MSList * create_telephone_events(LinphoneCore *lc, const MSList *codecs){ + const MSList *it; + MSList *ret=NULL; + for(it=codecs;it!=NULL;it=it->next){ + const PayloadType *pt=(PayloadType*)it->data; + if (!has_telephone_event_at_rate(ret,pt->clock_rate)){ + PayloadType *tev=payload_type_clone(&payload_type_telephone_event); + tev->clock_rate=pt->clock_rate; + /*let it choose the number dynamically as for normal codecs*/ + payload_type_set_number(tev, -1); + if (ret==NULL){ + /*But for first telephone-event, prefer the number that was configured in the core*/ + if (is_payload_type_number_available(codecs, lc->codecs_conf.telephone_event_pt, NULL)){ + payload_type_set_number(tev, lc->codecs_conf.telephone_event_pt); + } + } + ret=ms_list_append(ret,tev); + } + } + return ret; +} + +typedef struct _CodecConstraints{ + int bandwidth_limit; + int max_codecs; + MSList *previously_used; +}CodecConstraints; + +static MSList *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, const MSList *codecs){ + MSList *l=NULL; + MSList *tevs=NULL; + const MSList *it; + int nb = 0; + + for(it=codecs;it!=NULL;it=it->next){ + PayloadType *pt=(PayloadType*)it->data; + int num; + + if (!(pt->flags & PAYLOAD_TYPE_ENABLED)) + continue; + if (hints->bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,hints->bandwidth_limit)){ + ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s", + pt->mime_type,pt->clock_rate,hints->bandwidth_limit); + continue; + } + if (!linphone_core_check_payload_type_usability(lc,pt)){ + continue; + } + pt=payload_type_clone(pt); + + /*look for a previously assigned number for this codec*/ + num=find_payload_type_number(hints->previously_used, pt); + if (num!=-1){ + payload_type_set_number(pt,num); + payload_type_set_flag(pt, PAYLOAD_TYPE_FROZEN_NUMBER); + } + + l=ms_list_append(l, pt); + nb++; + if ((hints->max_codecs > 0) && (nb >= hints->max_codecs)) break; + } + tevs=create_telephone_events(lc,l); + l=ms_list_concat(l,tevs); + linphone_core_assign_payload_type_numbers(lc, l); return l; } @@ -395,9 +514,16 @@ void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall #endif //BUILD_UPNP } +static void transfer_already_assigned_payload_types(SalMediaDescription *old, SalMediaDescription *md){ + int i; + for(i=0;inb_streams;++i){ + md->streams[i].already_assigned_payloads=old->streams[i].already_assigned_payloads; + old->streams[i].already_assigned_payloads=NULL; + } +} + void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){ MSList *l; - PayloadType *pt; SalMediaDescription *old_md=call->localdesc; int i; int nb_active_streams = 0; @@ -406,6 +532,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * LinphoneAddress *addr; char* local_ip=call->localip; const char *subject=linphone_call_params_get_session_name(call->params); + CodecConstraints codec_hints={0}; linphone_core_adapt_to_network(lc,call->ping_time,call->params); @@ -439,9 +566,11 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->streams[0].ptime=call->params->down_ptime; else md->streams[0].ptime=linphone_core_get_download_ptime(lc); - l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params->audio_bw,&md->streams[0].max_rate,-1); - pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event")); - l=ms_list_append(l,pt); + codec_hints.bandwidth_limit=call->params->audio_bw; + codec_hints.max_codecs=-1; + codec_hints.previously_used=old_md ? old_md->streams[0].already_assigned_payloads : NULL; + l=make_codec_list(lc, &codec_hints, lc->codecs_conf.audio_codecs); + md->streams[0].max_rate=get_max_codec_sample_rate(l); md->streams[0].payloads=l; nb_active_streams++; @@ -453,7 +582,10 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->streams[1].rtcp_port=call->media_ports[1].rtcp_port; md->streams[1].proto=md->streams[0].proto; md->streams[1].type=SalVideo; - l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); + codec_hints.bandwidth_limit=0; + codec_hints.max_codecs=-1; + codec_hints.previously_used=old_md ? old_md->streams[1].already_assigned_payloads : NULL; + l=make_codec_list(lc, &codec_hints, lc->codecs_conf.video_codecs); md->streams[1].payloads=l; nb_active_streams++; } @@ -468,7 +600,10 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->streams[i].proto = call->biggestdesc->streams[i].proto; md->streams[i].type = call->biggestdesc->streams[i].type; md->streams[i].dir = SalStreamInactive; - l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1); + codec_hints.bandwidth_limit=0; + codec_hints.max_codecs=1; + codec_hints.previously_used=NULL; + l = make_codec_list(lc, &codec_hints, lc->codecs_conf.video_codecs); md->streams[i].payloads = l; } @@ -481,6 +616,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * linphone_call_update_local_media_description_from_ice_or_upnp(call); linphone_address_destroy(addr); if (old_md){ + transfer_already_assigned_payload_types(old_md,md); call->localdesc_changed=sal_media_description_equals(md,old_md); sal_media_description_unref(old_md); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ef4133d87..2543cb007 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -982,12 +982,13 @@ static void rtp_config_read(LinphoneCore *lc) linphone_core_set_avpf_mode(lc,lp_config_get_int(lc->config,"rtp","avpf",0)); } -static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){ +static PayloadType * find_payload(const MSList *default_list, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){ PayloadType *candidate=NULL; - int i; PayloadType *it; - for(i=0;inext){ + it=(PayloadType*)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) ){ @@ -1009,7 +1010,20 @@ static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int c return candidate; } -static bool_t get_codec(LinphoneCore *lc, const char* type, int index, PayloadType **ret){ +static PayloadType* find_payload_type_from_list(const char* type, int rate, int channels, const MSList* from) { + const MSList *elem; + for(elem=from;elem!=NULL;elem=elem->next){ + PayloadType *pt=(PayloadType*)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)) { + return pt; + } + } + return NULL; +} + +static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, PayloadType **ret){ char codeckey[50]; const char *mime,*fmtp; int rate,channels,enabled; @@ -1017,7 +1031,7 @@ static bool_t get_codec(LinphoneCore *lc, const char* type, int index, PayloadTy LpConfig *config=lc->config; *ret=NULL; - snprintf(codeckey,50,"%s_%i",type,index); + snprintf(codeckey,50,"%s_codec_%i",type==SalAudio ? "audio" : "video", index); mime=lp_config_get_string(config,codeckey,"mime",NULL); if (mime==NULL || strlen(mime)==0 ) return FALSE; @@ -1025,85 +1039,52 @@ static bool_t get_codec(LinphoneCore *lc, const char* type, int index, PayloadTy fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL); channels=lp_config_get_int(config,codeckey,"channels",0); enabled=lp_config_get_int(config,codeckey,"enabled",1); - pt=find_payload(lc->default_profile,mime,rate,channels,fmtp); - if (pt && enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED; - //ms_message("Found codec %s/%i",pt->mime_type,pt->clock_rate); - if (pt==NULL) ms_warning("Ignoring codec config %s/%i with fmtp=%s because unsupported", - mime,rate,fmtp ? fmtp : ""); + if (!ms_filter_codec_supported(mime)){ + ms_warning("Codec %s/%i read from conf is not supported by mediastreamer2, ignored.",mime,rate); + return TRUE; + } + pt=find_payload(type==SalAudio ? lc->default_audio_codecs : lc->default_video_codecs,mime,rate,channels,fmtp); + if (!pt){ + MSList **default_list=(type==SalAudio) ? &lc->default_audio_codecs : &lc->default_video_codecs; + ms_warning("Codec %s/%i read from conf is not in the default list.",mime,rate); + pt=payload_type_new(); + pt->type=(type==SalAudio) ? PAYLOAD_AUDIO_PACKETIZED : PAYLOAD_VIDEO; + pt->mime_type=ortp_strdup(mime); + pt->clock_rate=rate; + pt->channels=channels; + payload_type_set_recv_fmtp(pt,fmtp); + *default_list=ms_list_append(*default_list, pt); + } + if (enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED; *ret=pt; return TRUE; } -#define RANK_END 10000 - -typedef struct codec_desc{ - const char *name; - int rate; -}codec_desc_t; - -static codec_desc_t codec_pref_order[]={ - {"opus", 48000}, - {"SILK", 16000}, - {"speex", 16000}, - {"speex", 8000}, - {"pcmu",8000}, - {"pcma",8000}, - {"VP8",90000}, - {"H264",90000}, - {"MP4V-ES",90000}, - {NULL,0} -}; - -static int find_codec_rank(const char *mime, int clock_rate){ - int i; - -#ifdef __arm__ - /*hack for opus, that needs to be disabed by default on ARM single processor, otherwise there is no cpu left for video processing*/ - if (strcasecmp(mime,"opus")==0){ - if (ms_get_cpu_count()==1) return RANK_END; - } -#endif - for(i=0;codec_pref_order[i].name!=NULL;++i){ - if (strcasecmp(codec_pref_order[i].name,mime)==0 && clock_rate==codec_pref_order[i].rate) - return i; - } - return RANK_END; -} - -static int codec_compare(const PayloadType *a, const PayloadType *b){ - int ra,rb; - ra=find_codec_rank(a->mime_type,a->clock_rate); - rb=find_codec_rank(b->mime_type,b->clock_rate); - if (ra>rb) return 1; - if (radefault_profile,i); - if (pt){ - if (mtype==SalVideo && pt->type!=PAYLOAD_VIDEO) - pt=NULL; - else if (mtype==SalAudio && (pt->type!=PAYLOAD_AUDIO_PACKETIZED - && pt->type!=PAYLOAD_AUDIO_CONTINUOUS)){ - pt=NULL; - } - if (pt && ms_filter_codec_supported(pt->mime_type)){ - if (ms_list_find(l,pt)==NULL){ - /*unranked codecs are disabled by default*/ - if (find_codec_rank(pt->mime_type, pt->clock_rate)!=RANK_END){ - payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); - } - ms_message("Adding new codec %s/%i with fmtp %s", - pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : ""); - l=ms_list_insert_sorted(l,pt,(int (*)(const void *, const void *))codec_compare); - } +/*this function merges the payload types from the codec default list with the list read from configuration file. + * If a new codec becomes supported in Liblinphone or if the list from configuration file is empty or incomplete, all the supported codecs are added + * automatically. This 'l' list is entirely destroyed and rewritten.*/ +static MSList *add_missing_codecs(const MSList *default_list, MSList *l){ + const MSList *elem; + MSList *newlist; + + for(elem=default_list; elem!=NULL; elem=elem->next){ + MSList *elem2=ms_list_find(l,elem->data); + if (!elem2){ + PayloadType *pt=(PayloadType*)elem->data; + /*this codec from default list should be inserted in the list*/ + if (!elem->prev){ + l=ms_list_prepend(l,pt); + }else{ + const MSList *after=ms_list_find(l,elem->prev->data); + l=ms_list_insert(l, after->next, pt); } + 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 : ""); } } - return l; + newlist=ms_list_copy_with_data(l,(void *(*)(void*))payload_type_clone); + ms_list_free(l); + return newlist; } static MSList *codec_append_if_new(MSList *l, PayloadType *pt){ @@ -1123,23 +1104,23 @@ static void codecs_config_read(LinphoneCore *lc) PayloadType *pt; MSList *audio_codecs=NULL; MSList *video_codecs=NULL; - for (i=0;get_codec(lc,"audio_codec",i,&pt);i++){ + + lc->codecs_conf.dyn_pt=96; + lc->codecs_conf.telephone_event_pt=lp_config_get_int(lc->config,"misc","telephone_event_pt",101); + + for (i=0;get_codec(lc,SalAudio,i,&pt);i++){ if (pt){ - if (!ms_filter_codec_supported(pt->mime_type)){ - ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); - }else audio_codecs=codec_append_if_new(audio_codecs,pt); + audio_codecs=codec_append_if_new(audio_codecs, pt); } } - audio_codecs=add_missing_codecs(lc,SalAudio,audio_codecs); + audio_codecs=add_missing_codecs(lc->default_audio_codecs,audio_codecs); - for (i=0;get_codec(lc,"video_codec",i,&pt);i++){ + for (i=0;get_codec(lc,SalVideo,i,&pt);i++){ if (pt){ - if (!ms_filter_codec_supported(pt->mime_type)){ - ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); - }else video_codecs=codec_append_if_new(video_codecs,(void *)pt); + video_codecs=codec_append_if_new(video_codecs, pt); } } - video_codecs=add_missing_codecs(lc,SalVideo,video_codecs); + video_codecs=add_missing_codecs(lc->default_video_codecs,video_codecs); linphone_core_set_audio_codecs(lc,audio_codecs); linphone_core_set_video_codecs(lc,video_codecs); linphone_core_update_allocated_audio_bandwidth(lc); @@ -1412,60 +1393,45 @@ const char * linphone_core_get_version(void){ return liblinphone_version; } -static void linphone_core_assign_payload_type(LinphoneCore *lc, PayloadType *const_pt, int number, const char *recv_fmtp){ - PayloadType *pt; - - pt=payload_type_clone(const_pt); - if (number==-1){ - /*look for a free number */ - MSList *elem; - int i; - for(i=lc->dyn_pt;ipayload_types;elem!=NULL;elem=elem->next){ - PayloadType *it=(PayloadType*)elem->data; - if (payload_type_get_number(it)==i){ - already_assigned=TRUE; - break; - } - } - if (!already_assigned){ - number=i; - lc->dyn_pt=i+1; - break; - } - } - if (number==-1){ - ms_fatal("FIXME: too many codecs, no more free numbers."); - } +static void linphone_core_register_payload_type(LinphoneCore *lc, const PayloadType *const_pt, const char *recv_fmtp, bool_t enabled){ + MSList **codec_list=const_pt->type==PAYLOAD_VIDEO ? &lc->default_video_codecs : &lc->default_audio_codecs; + if (ms_filter_codec_supported(const_pt->mime_type)){ + PayloadType *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); + /*Set a number to the payload type from the statically defined (RFC3551) profile, if not static, -1 is returned + and the payload type number will be determined dynamically later, at call time.*/ + payload_type_set_number(pt, + (number=rtp_profile_find_payload_number(&av_profile, pt->mime_type, pt->clock_rate, pt->channels)) + ); + ms_message("Codec %s/%i fmtp=[%s] number=%i, enabled=%i) added to default capabilities.", pt->mime_type, pt->clock_rate, + pt->recv_fmtp ? pt->recv_fmtp : "", number, (int)payload_type_enabled(pt)); + *codec_list=ms_list_append(*codec_list,pt); } - ms_message("assigning %s/%i payload type number %i",pt->mime_type,pt->clock_rate,number); - payload_type_set_number(pt,number); - if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp); - rtp_profile_set_payload(lc->default_profile,number,pt); - lc->payload_types=ms_list_append(lc->payload_types,pt); } -static void linphone_core_handle_static_payloads(LinphoneCore *lc){ +static void linphone_core_register_static_payloads(LinphoneCore *lc){ RtpProfile *prof=&av_profile; int i; for(i=0;idefault_profile,i) == NULL){ - linphone_core_assign_payload_type(lc,pt,i,NULL); +#ifndef VIDEO_ENABLED + if (pt->type==PAYLOAD_VIDEO) continue; +#endif + if (find_payload_type_from_list( + pt->mime_type, pt->clock_rate, pt->type!=PAYLOAD_VIDEO ? pt->channels : LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS, + pt->type==PAYLOAD_VIDEO ? lc->default_video_codecs : lc->default_audio_codecs)==NULL){ + linphone_core_register_payload_type(lc,pt,NULL,FALSE); } } } } static void linphone_core_free_payload_types(LinphoneCore *lc){ - rtp_profile_clear_all(lc->default_profile); - rtp_profile_destroy(lc->default_profile); - ms_list_for_each(lc->payload_types,(void (*)(void*))payload_type_destroy); - ms_list_free(lc->payload_types); - lc->payload_types=NULL; + ms_list_free_with_data(lc->default_audio_codecs, (void (*)(void*))payload_type_destroy); + ms_list_free_with_data(lc->default_video_codecs, (void (*)(void*))payload_type_destroy); } void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message){ @@ -1541,10 +1507,73 @@ static void linphone_core_deactivate_log_serialization_if_needed(void) { } } -static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, void * userdata) -{ - const char *remote_provisioning_uri = NULL; +static void linphone_core_register_default_codecs(LinphoneCore *lc){ const char *aac_fmtp162248, *aac_fmtp3244; + bool_t opus_enabled=TRUE; + /*default enabled audio codecs, in order of preference*/ +#ifdef __arm__ + /*hack for opus, that needs to be disabed by default on ARM single processor, otherwise there is no cpu left for video processing*/ + if (ms_get_cpu_count()==1) opus_enabled=FALSE; +#endif + linphone_core_register_payload_type(lc,&payload_type_opus,"useinbandfec=1; stereo=0; sprop-stereo=0",opus_enabled); + linphone_core_register_payload_type(lc,&payload_type_silk_wb,NULL,TRUE); + linphone_core_register_payload_type(lc,&payload_type_speex_wb,"vbr=on",TRUE); + linphone_core_register_payload_type(lc,&payload_type_speex_nb,"vbr=on",TRUE); + linphone_core_register_payload_type(lc,&payload_type_pcmu8000,NULL,TRUE); + linphone_core_register_payload_type(lc,&payload_type_pcma8000,NULL,TRUE); + + /*other audio codecs, not enabled by default, in order of preference*/ + linphone_core_register_payload_type(lc,&payload_type_gsm,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g722,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_ilbc,"mode=30",FALSE); + linphone_core_register_payload_type(lc,&payload_type_amr,"octet-align=1",FALSE); + linphone_core_register_payload_type(lc,&payload_type_amrwb,"octet-align=1",FALSE); + linphone_core_register_payload_type(lc,&payload_type_g729,"annexb=no",FALSE); + /* For AAC, we use a config value to determine if we ought to support SBR. Since it is not offically supported + * for the mpeg4-generic mime type, setting this flag to 1 will break compatibility with other clients. */ + if( lp_config_get_int(lc->config, "misc", "aac_use_sbr", FALSE) ) { + ms_message("Using SBR for AAC"); + aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1"; + aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1"; + } else { + aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"; + aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"; + } + linphone_core_register_payload_type(lc,&payload_type_aaceld_16k,aac_fmtp162248,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aaceld_22k,aac_fmtp162248,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aaceld_32k,aac_fmtp3244,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aaceld_44k,aac_fmtp3244,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aaceld_48k,aac_fmtp162248,FALSE); + linphone_core_register_payload_type(lc,&payload_type_isac,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_speex_uwb,"vbr=on",FALSE); + linphone_core_register_payload_type(lc,&payload_type_silk_nb,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_silk_mb,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_silk_swb,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g726_16,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g726_24,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g726_32,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g726_40,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aal2_g726_16,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aal2_g726_24,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aal2_g726_32,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aal2_g726_40,NULL,FALSE); + + + +#ifdef VIDEO_ENABLED + /*default enabled video codecs, in order of preference*/ + linphone_core_register_payload_type(lc,&payload_type_vp8,NULL,TRUE); + linphone_core_register_payload_type(lc,&payload_type_h264,"profile-level-id=42801F",TRUE); + linphone_core_register_payload_type(lc,&payload_type_mp4v,"profile-level-id=3",TRUE); + linphone_core_register_payload_type(lc,&payload_type_h263_1998,"CIF=1;QCIF=1",FALSE); + linphone_core_register_payload_type(lc,&payload_type_h263,NULL,FALSE); +#endif + /*register all static payload types declared in av_profile of oRTP, if not already declared above*/ + linphone_core_register_static_payloads(lc); +} + +static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, void * userdata){ + const char *remote_provisioning_uri = NULL; LinphoneCoreVTable* local_vtable= linphone_core_v_table_new(); ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); @@ -1558,83 +1587,10 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up"); ortp_init(); linphone_core_activate_log_serialization_if_needed(); - lc->dyn_pt=96; - lc->default_profile=rtp_profile_new("default profile"); - linphone_core_assign_payload_type(lc,&payload_type_pcmu8000,0,NULL); - linphone_core_assign_payload_type(lc,&payload_type_gsm,3,NULL); - linphone_core_assign_payload_type(lc,&payload_type_pcma8000,8,NULL); - linphone_core_assign_payload_type(lc,&payload_type_speex_nb,110,"vbr=on"); - linphone_core_assign_payload_type(lc,&payload_type_speex_wb,111,"vbr=on"); - linphone_core_assign_payload_type(lc,&payload_type_speex_uwb,112,"vbr=on"); - linphone_core_assign_payload_type(lc,&payload_type_telephone_event,101,"0-15"); - linphone_core_assign_payload_type(lc,&payload_type_g722,9,NULL); - -#ifdef ENABLE_NONSTANDARD_GSM - { - PayloadType *pt; - pt=payload_type_clone(&payload_type_gsm); - pt->clock_rate=11025; - linphone_core_assign_payload_type(lc,pt,-1,NULL); - pt->clock_rate=22050; - linphone_core_assign_payload_type(lc,pt,-1,NULL); - payload_type_destroy(pt); - } -#endif - -#ifdef VIDEO_ENABLED - - linphone_core_assign_payload_type(lc,&payload_type_h263,34,NULL); - linphone_core_assign_payload_type(lc,&payload_type_h263_1998,98,"CIF=1;QCIF=1"); - linphone_core_assign_payload_type(lc,&payload_type_mp4v,99,"profile-level-id=3"); - linphone_core_assign_payload_type(lc,&payload_type_h264,102,"profile-level-id=42801F"); - linphone_core_assign_payload_type(lc,&payload_type_vp8,103,NULL); - - /* linphone_core_assign_payload_type(lc,&payload_type_theora,97,NULL); commented out to free 1 slot */ - /* linphone_core_assign_payload_type(lc,&payload_type_x_snow,-1,NULL); commented out to free 1 slot */ - /* due to limited space in SDP, we have to disable this h264 line which is normally no more necessary */ - /* linphone_core_assign_payload_type(&payload_type_h264,-1,"packetization-mode=1;profile-level-id=428014");*/ -#endif - - /* For AAC, we use a config value to determine if we ought to support SBR. Since it is not offically supported - * for the mpeg4-generic mime type, setting this flag to 1 will break compatibility with other clients. */ - if( lp_config_get_int(lc->config, "misc", "aac_use_sbr", FALSE) ) { - ms_message("Using SBR for AAC"); - aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1"; - aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1"; - } else { - aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"; - aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"; - } - - - /*add all payload type for which we don't care about the number */ - linphone_core_assign_payload_type(lc,&payload_type_ilbc,-1,"mode=30"); - linphone_core_assign_payload_type(lc,&payload_type_amr,-1,"octet-align=1"); - linphone_core_assign_payload_type(lc,&payload_type_amrwb,-1,"octet-align=1"); - /* linphone_core_assign_payload_type(lc,&payload_type_lpc1015,-1,NULL); commented out to free 1 slot */ - linphone_core_assign_payload_type(lc,&payload_type_g726_16,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_g726_24,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_g726_32,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_g726_40,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_16,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_24,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_32,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_40,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_silk_nb,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_silk_mb,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_silk_wb,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_silk_swb,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_g729,18,"annexb=no"); - linphone_core_assign_payload_type(lc,&payload_type_aaceld_16k,-1,aac_fmtp162248); - linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,aac_fmtp162248); - linphone_core_assign_payload_type(lc,&payload_type_aaceld_32k,-1,aac_fmtp3244); - linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,aac_fmtp3244); - linphone_core_assign_payload_type(lc,&payload_type_aaceld_48k,-1,aac_fmtp162248); - linphone_core_assign_payload_type(lc,&payload_type_opus,-1,"useinbandfec=1; stereo=0; sprop-stereo=0"); - linphone_core_assign_payload_type(lc,&payload_type_isac,-1,NULL); - linphone_core_handle_static_payloads(lc); - + ms_init(); + + linphone_core_register_default_codecs(lc); /* create a mediastreamer2 event queue and set it as global */ /* This allows to run event's callback in linphone_core_iterate() */ lc->msevq=ms_event_queue_new(); @@ -1841,8 +1797,7 @@ LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc){ * The list is taken by the LinphoneCore thus the application should not free it. * This list is made of struct PayloadType describing the codec parameters. **/ -int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs) -{ +int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs){ if (lc->codecs_conf.audio_codecs!=NULL) ms_list_free(lc->codecs_conf.audio_codecs); lc->codecs_conf.audio_codecs=codecs; _linphone_core_codec_config_write(lc); @@ -1860,8 +1815,7 @@ int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs) * The list is taken by the LinphoneCore thus the application should not free it. * This list is made of struct PayloadType describing the codec parameters. **/ -int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs) -{ +int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs){ if (lc->codecs_conf.video_codecs!=NULL) ms_list_free(lc->codecs_conf.video_codecs); lc->codecs_conf.video_codecs=codecs; _linphone_core_codec_config_write(lc); @@ -6212,8 +6166,8 @@ void _linphone_core_codec_config_write(LinphoneCore *lc){ static void codecs_config_uninit(LinphoneCore *lc) { _linphone_core_codec_config_write(lc); - ms_list_free(lc->codecs_conf.audio_codecs); - ms_list_free(lc->codecs_conf.video_codecs); + ms_list_free_with_data(lc->codecs_conf.audio_codecs, (void (*)(void*))payload_type_destroy); + ms_list_free_with_data(lc->codecs_conf.video_codecs, (void (*)(void*))payload_type_destroy); } void ui_config_uninit(LinphoneCore* lc) @@ -6519,20 +6473,6 @@ const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc){ return lc->sound_conf.ringback_tone; } -static PayloadType* find_payload_type_from_list(const char* type, int rate, int channels, const MSList* from) { - const MSList *elem; - for(elem=from;elem!=NULL;elem=elem->next){ - PayloadType *pt=(PayloadType*)elem->data; - if ((strcasecmp((char*)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)) { - return pt; - } - } - return NULL; -} - - LinphonePayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) { LinphonePayloadType* result = find_payload_type_from_list(type, rate, channels, linphone_core_get_audio_codecs(lc)); if (result) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c8a259f25..1e72fcd0a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2345,8 +2345,19 @@ LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, Linphone */ LINPHONE_PUBLIC LinphonePayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ; +/** + * @ingroup media_parameters + * Returns the payload type number assigned for this codec. +**/ LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt); +/** + * @ingroup media_parameters + * Force a number for a payload type. The LinphoneCore does payload type number assignment automatically. THis function is to be used mainly for tests, in order + * to override the automatic assignment mechanism. +**/ +LINPHONE_PUBLIC void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, int number); + LINPHONE_PUBLIC const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt); LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const PayloadType *pt); diff --git a/coreapi/misc.c b/coreapi/misc.c index 59244d3de..d88c80cd5 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -59,15 +59,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define RTP_HDR_SZ 12 #define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/ -static void payload_type_set_enable(PayloadType *pt,int value) -{ - if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \ - else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED); -} - -static bool_t payload_type_enabled(const PayloadType *pt) { - return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0); -} bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const LinphonePayloadType *pt){ if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){ @@ -97,6 +88,10 @@ int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *p return payload_type_get_number(pt); } +void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, int number){ + payload_type_set_number(pt,number); +} + const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){ if (ms_filter_codec_supported(pt->mime_type)){ MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type); diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index d7d2e6e84..b9ece30d8 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -110,6 +110,7 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t res=ms_list_append(res,newp); /* we should use the remote numbering even when parsing a response */ payload_type_set_number(newp,remote_number); + payload_type_set_flag(newp, PAYLOAD_TYPE_FROZEN_NUMBER); if (reading_response && remote_number!=local_number){ ms_warning("For payload type %s, proposed number was %i but the remote phone answered %i", newp->mime_type, local_number, remote_number); @@ -120,6 +121,7 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t */ newp=payload_type_clone(newp); payload_type_set_number(newp,local_number); + payload_type_set_flag(newp, PAYLOAD_TYPE_FROZEN_NUMBER); res=ms_list_append(res,newp); } }else{ @@ -143,7 +145,8 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t if (!found){ ms_message("Adding %s/%i for compatibility, just in case.",p1->mime_type,p1->clock_rate); p1=payload_type_clone(p1); - p1->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV; + payload_type_set_flag(p1, PAYLOAD_TYPE_FLAG_CAN_RECV); + payload_type_set_flag(p1, PAYLOAD_TYPE_FROZEN_NUMBER); res=ms_list_append(res,p1); } } diff --git a/coreapi/private.h b/coreapi/private.h index 55f1f1034..68a0e6354 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -365,6 +365,7 @@ static MS2_INLINE void set_string(char **dest, const char *src){ #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 void linphone_process_authentication(LinphoneCore* lc, SalOp *op); void linphone_authentication_ok(LinphoneCore *lc, SalOp *op); @@ -643,7 +644,9 @@ typedef struct sound_config typedef struct codecs_config { MSList *audio_codecs; /* list of audio codecs in order of preference*/ - MSList *video_codecs; /* for later use*/ + MSList *video_codecs; + int dyn_pt; + int telephone_event_pt; }codecs_config_t; typedef struct video_config{ @@ -710,7 +713,8 @@ struct _LinphoneCore Sal *sal; LinphoneGlobalState state; struct _LpConfig *config; - RtpProfile *default_profile; + MSList *default_audio_codecs; + MSList *default_video_codecs; net_config_t net_conf; sip_config_t sip_conf; rtp_config_t rtp_conf; @@ -719,8 +723,6 @@ struct _LinphoneCore codecs_config_t codecs_conf; ui_config_t ui_conf; autoreplier_config_t autoreplier_conf; - MSList *payload_types; - int dyn_pt; LinphoneProxyConfig *default_proxy; MSList *friends; MSList *auth_info; @@ -1014,6 +1016,18 @@ static MS2_INLINE const LinphoneErrorInfo *linphone_error_info_from_sal_op(const return (const LinphoneErrorInfo*)sal_op_get_error_info(op); } +static MS2_INLINE void payload_type_set_enable(PayloadType *pt,int value) +{ + if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \ + else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED); +} + +static MS2_INLINE bool_t payload_type_enabled(const PayloadType *pt) { + return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0); +} + +bool_t is_payload_type_number_available(const MSList *l, int number, const PayloadType *ignore); + const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc); /** Belle Sip-based objects need unique ids diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index bb1d443bf..e22f7229c 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -332,6 +332,7 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, } linphone_content_set_buffer(content, buffer, strlen(buffer)); + ms_free(buffer); if (call->log->reporting.on_report_sent != NULL){ call->log->reporting.on_report_sent( diff --git a/coreapi/sal.c b/coreapi/sal.c index b8395c897..1577f95f6 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -62,9 +62,10 @@ SalMediaDescription *sal_media_description_new(){ static void sal_media_description_destroy(SalMediaDescription *md){ int i; for(i=0;istreams[i].payloads,(void (*)(void *))payload_type_destroy); - ms_list_free(md->streams[i].payloads); + ms_list_free_with_data(md->streams[i].payloads,(void (*)(void *))payload_type_destroy); + ms_list_free_with_data(md->streams[i].already_assigned_payloads,(void (*)(void *))payload_type_destroy); md->streams[i].payloads=NULL; + md->streams[i].already_assigned_payloads=NULL; } ms_free(md); } diff --git a/include/sal/sal.h b/include/sal/sal.h index c44317c88..42f2d6da8 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -196,7 +196,8 @@ typedef struct SalStreamDescription{ char rtcp_addr[64]; int rtp_port; int rtcp_port; - MSList *payloads; //lc);it!=NULL;it=it->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)it->data; - LinphoneAddress *modified_identity=account_manager_check_account(am,cfg); - if (m->identity){ - linphone_address_unref(m->identity); - } - m->identity=linphone_address_ref(modified_identity); + account_manager_check_account(am,cfg); } } diff --git a/tester/call_tester.c b/tester/call_tester.c index d608e9723..51cd2d550 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -34,7 +34,6 @@ static void srtp_call(void); static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy); -static void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate); static char *create_filepath(const char *dir, const char *filename, const char *ext); // prototype definition for call_recording() @@ -727,7 +726,7 @@ static void cancelled_call(void) { linphone_core_manager_destroy(pauline); } -static void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate){ +void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate){ const MSList *elem=linphone_core_get_audio_codecs(lc); PayloadType *pt; @@ -754,40 +753,6 @@ static void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mi } #endif -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 call_with_dns_time_out(void) { LinphoneCoreManager* marie = linphone_core_manager_new2( "empty_rc", FALSE); LCSipTransports transport = {9773,0,0,0}; @@ -3036,115 +3001,6 @@ static void multiple_early_media(void) { } #endif -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 char *create_filepath(const char *dir, const char *filename, const char *ext) { return ms_strdup_printf("%s/%s.%s",dir,filename,ext); } @@ -3530,7 +3386,6 @@ test_t call_tests[] = { { "Early cancelled call", early_cancelled_call}, { "Call with DNS timeout", call_with_dns_time_out }, { "Cancelled ringing call", cancelled_ringing_call }, - { "Call failed because of codecs", call_failed_because_of_codecs }, { "Simple call", simple_call }, { "Call with timeouted bye", call_with_timeouted_bye }, { "Direct call over IPv6", direct_call_over_ipv6}, @@ -3607,22 +3462,6 @@ test_t call_tests[] = { { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, { "Call redirected by callee", call_redirect}, { "Call with specified codec bitrate", call_with_specified_codec_bitrate}, - { "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 }, { "Call with in-dialog UPDATE request", call_with_in_dialog_update }, { "Call with in-dialog codec change", call_with_in_dialog_codec_change }, { "Call with in-dialog codec change no sdp", call_with_in_dialog_codec_change_no_sdp }, diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 0ae708b70..5f257bb08 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -62,6 +62,7 @@ extern test_suite_t log_collection_test_suite; extern test_suite_t transport_test_suite; extern test_suite_t player_test_suite; extern test_suite_t dtmf_test_suite; +extern test_suite_t offeranswer_test_suite; extern int liblinphone_tester_nb_test_suites(void); @@ -293,6 +294,7 @@ bool_t call_with_test_params(LinphoneCoreManager* caller_mgr bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr); void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2); +void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate); stats * get_stats(LinphoneCore *lc); LinphoneCoreManager *get_manager(LinphoneCore *lc); const char *liblinphone_tester_get_subscribe_content(void); diff --git a/tester/offeranswer_tester.c b/tester/offeranswer_tester.c new file mode 100644 index 000000000..b9de6a879 --- /dev/null +++ b/tester/offeranswer_tester.c @@ -0,0 +1,297 @@ +/* + 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 +}; diff --git a/tester/tester.c b/tester/tester.c index 8c09b90f1..d3a34a375 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -420,6 +420,7 @@ void liblinphone_tester_set_writable_dir_prefix(const char* writable_dir_prefix) void liblinphone_tester_init(void) { add_test_suite(&setup_test_suite); add_test_suite(®ister_test_suite); + add_test_suite(&offeranswer_test_suite); add_test_suite(&call_test_suite); add_test_suite(&message_test_suite); add_test_suite(&presence_test_suite);