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);