Merge remote-tracking branch 'origin/master' into dev_dtls

This commit is contained in:
Johan Pascal 2015-01-27 10:42:06 +01:00
commit 219451388d
41 changed files with 1025 additions and 517 deletions

View file

@ -7,6 +7,8 @@ SUBDIRS = build m4 pixmaps po @ORTP_DIR@ @MS2_DIR@ \
coreapi console gtk share scripts tools tester include
GITVERSION=`cd $(top_srcdir) && git describe --always || echo $(VERSION)`
ACLOCAL_FLAGS=-I$(top_srcdir)/m4
@ -20,11 +22,11 @@ OPTIONAL_SOUNDS=\
INSTALLDIR=$(abs_top_builddir)/linphone-install
INSTALLDIR_WITH_PREFIX=$(INSTALLDIR)/$(prefix)
ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(VERSION).zip
ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(GITVERSION).zip
ZIP_EXCLUDED=include lib \
$(OPTIONAL_SOUNDS)
SDK_ZIPFILE=$(abs_top_builddir)/lib$(PACKAGE)-win32-$(VERSION).zip
SDK_ZIPFILE=$(abs_top_builddir)/lib$(PACKAGE)-win32-sdk-$(GITVERSION).zip
SDK_EXCLUDED= \
bin/linphone.exe \
lib/*.la \
@ -173,7 +175,7 @@ setup.exe: filelist
cp $(ISS_SCRIPT) $(INSTALLDIR_WITH_PREFIX)/.
cd $(INSTALLDIR_WITH_PREFIX) && \
$(ISCC) $(ISS_SCRIPT)
mv $(INSTALLDIR_WITH_PREFIX)/Output/setup.exe $(PACKAGE)-$(VERSION)-setup.exe
mv $(INSTALLDIR_WITH_PREFIX)/Output/setup.exe $(PACKAGE)-setup-$(GITVERSION).exe
rm -rf $(INSTALLDIR_WITH_PREFIX)/Output
rm -f $(INSTALLDIR_WITH_PREFIX)/$(PACKAGE_WIN32_FILELIST)
rm -f $(INSTALLDIR_WITH_PREFIX)/$(ISS_SCRIPT)
@ -201,8 +203,8 @@ Portfile-devel: $(top_srcdir)/scripts/Portfile-devel.tmpl dist
### MAC
MACAPPNAME=Linphone.app
MACAPPZIP=$(PACKAGE)-$(VERSION).app.zip
MACAPPDMG=$(PACKAGE)-$(VERSION).dmg
MACAPPZIP=$(PACKAGE)-$(GITVERSION).app.zip
MACAPPDMG=$(PACKAGE)-$(GITVERSION).dmg
BUNDLEPREFIX=./
BUNDLEDIR=$(BUNDLEPREFIX)$(MACAPPNAME)
#a path prefix where additional libs can be cherry-picked by the bundler.

View file

@ -53,7 +53,7 @@ Install `GTK`. It is recommended to use the `quartz` backend for better integrat
brew install cairo --without-x11
brew install gtk+ --without-x11
brew install gettext gtk-mac-integration libsoup
brew install gettext gtk-mac-integration libsoup hicolor-icon-theme
#readline is required from linphonec.c otherwise compilation will fail
brew link readline --force
@ -148,6 +148,15 @@ If you don't need plugins, remove or comment out this line from the bundler file
${prefix:ms2plugins}/lib/mediastreamer/plugins/*.*.so
</binary>
If using HomeBrew, this is not working yet. However you will at least need to:
brew install shared-mime-info glib-networking hicolor-icon-theme
update-mime-database /usr/local/share/mime
And modify also:
<prefix name="default">/usr/local</prefix>
Then run, inside Linphone source tree configure as told before but with `--enable-relativeprefix` appended.
make && make bundle

View file

@ -33,6 +33,11 @@ fi
INTLTOOLIZE=$(which intltoolize)
#workaround for mingw bug in intltoolize script.
if test "$INTLTOOLIZE" = "/bin/intltoolize" ; then
INTLTOOLIZE=/usr/bin/intltoolize
fi
echo "Generating build scripts in linphone..."
set -x
$LIBTOOLIZE --copy --force

View file

@ -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) \

View file

@ -26,6 +26,8 @@
<string>Copyright 2011 Belledonne Communications</string>
<key>LSMinimumSystemVersion</key>
<string>10.4</string>
<key>NSAppSleepDisabled</key>
<string>YES</string>
</dict>
</plist>

View file

@ -62,7 +62,10 @@ case $target in
*mingw*)
CFLAGS="$CFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501 "
CXXFLAGS="$CXXFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501"
LIBS="$LIBS -L/lib -lws2_32"
dnl Workaround for mingw, whose compiler does not check in /usr/include ...
CPPFLAGS="$CPPFLAGS -I/usr/include"
LDFLAGS="$LDFLAGS -L/usr/lib"
LIBS="$LIBS -lws2_32"
GUI_FLAGS="-mwindows"
CONSOLE_FLAGS="-mconsole"
mingw_found=yes
@ -298,7 +301,7 @@ if test "$build_zlib" != "false" ; then
AC_MSG_NOTICE([zlib library and headers not found])
else
AC_DEFINE( HAVE_ZLIB, 1, [ZLIB support] )
ZLIBS_LIBS='-z'
ZLIB_LIBS='-lz'
AC_SUBST(ZLIB_LIBS)
fi
else

View file

@ -159,6 +159,13 @@ bool_t linphone_address_is_secure(const LinphoneAddress *uri){
return sal_address_is_secure(uri);
}
/**
* returns true if address is a routable sip address
*/
bool_t linphone_address_is_sip(const LinphoneAddress *uri){
return sal_address_is_sip(uri);
}
static bool_t strings_equals(const char *s1, const char *s2){
if (s1==NULL && s2==NULL) return TRUE;
if (s1!=NULL && s2!=NULL && strcmp(s1,s2)==0) return TRUE;

View file

@ -151,6 +151,11 @@ char *sal_address_as_string(const SalAddress *addr){
return ms_strdup(tmp);
}
bool_t sal_address_is_sip(const SalAddress *addr){
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
return belle_sip_header_address_get_uri(header_addr) != NULL;
}
char *sal_address_as_string_uri_only(const SalAddress *addr){
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
belle_sip_uri_t* sip_uri = belle_sip_header_address_get_uri(header_addr);
@ -210,7 +215,7 @@ void sal_address_unref(SalAddress *addr){
belle_sip_object_unref(BELLE_SIP_HEADER_ADDRESS(addr));
}
bool_t sal_address_is_ipv6(SalAddress *addr){
bool_t sal_address_is_ipv6(const SalAddress *addr){
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);
if (uri){

View file

@ -97,6 +97,7 @@ static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* ses
error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,bufLen,&length);
if( error != BELLE_SIP_OK ){
bufLen *= 2;
length = 0;
buff = belle_sip_realloc(buff,bufLen);
}
}
@ -687,6 +688,11 @@ int sal_call(SalOp *op, const char *from, const char *to){
ms_message("[%s] calling [%s] on op [%p]", from, to, op);
invite=sal_op_build_request(op,"INVITE");
if( invite == NULL ){
/* can happen if the op has an invalid address */
return -1;
}
sal_op_fill_invite(op,invite);
sal_op_call_fill_cbs(op);

View file

@ -198,6 +198,9 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event
sal_op_subscribe_fill_cbs(op);
/*???sal_exosip_fix_route(op); make sure to ha ;lr*/
req=sal_op_build_request(op,"SUBSCRIBE");
if( req == NULL ) {
return -1;
}
if (eventname){
if (op->event) belle_sip_object_unref(op->event);
op->event=belle_sip_header_create("Event",eventname);

View file

@ -150,20 +150,37 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) {
belle_sip_provider_t* prov=op->base.root->prov;
belle_sip_request_t *req;
belle_sip_uri_t* req_uri;
belle_sip_uri_t* to_uri;
const SalAddress* to_address;
const MSList *elem=sal_op_get_route_addresses(op);
char token[10];
/* check that the op has a correct to address */
to_address = sal_op_get_to_address(op);
if( to_address == NULL ){
ms_error("No To: address, cannot build request");
return NULL;
}
to_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_address));
if( to_uri == NULL ){
ms_error("To: address is invalid, cannot build request");
return NULL;
}
if (strcmp("REGISTER",method)==0 || op->privacy==SalPrivacyNone) {
from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op))
,belle_sip_random_token(token,sizeof(token)));
,belle_sip_random_token(token,sizeof(token)));
} else {
from_header=belle_sip_header_from_create2("Anonymous <sip:anonymous@anonymous.invalid>",belle_sip_random_token(token,sizeof(token)));
}
/*make sure to preserve components like headers or port*/
req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op))));
req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)to_uri);
belle_sip_uri_set_secure(req_uri,sal_op_is_secure(op));
to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL);
to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(to_address),NULL);
req=belle_sip_request_create(
req_uri,
@ -218,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);
}
}

View file

@ -172,6 +172,9 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
op->dir=SalOpDirOutgoing;
req=sal_op_build_request(op,"MESSAGE");
if (req == NULL ){
return -1;
}
if (sal_op_get_contact_address(op)){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
}

View file

@ -306,8 +306,10 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expi
belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.from_address),"tag");
belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.to_address),"tag");
req=sal_op_build_request(op,"SUBSCRIBE");
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
if( req ){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
}
return sal_op_send_request(op,req);
}

View file

@ -76,6 +76,11 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expire
op->type=SalOpPublish;
req=sal_op_build_request(op,"PUBLISH");
if( req == NULL ){
return -1;
}
if (sal_op_get_contact_address(op)){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
}
@ -101,6 +106,10 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna
sal_op_publish_fill_cbs(op);
req=sal_op_build_request(op,"PUBLISH");
if( req == NULL ){
return -1;
}
if (sal_op_get_contact_address(op)){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
}

View file

@ -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;i<result_desc->nb_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);
@ -597,7 +614,7 @@ static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call, bool_t
}
}
if (call->state==LinphoneCallStreamsRunning) {
if ( call->state == LinphoneCallStreamsRunning) {
/*reINVITE and in-dialogs UPDATE go here*/
linphone_core_notify_display_status(lc,_("Call is updated by remote."));
call->defer_update=FALSE;
@ -605,8 +622,21 @@ static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call, bool_t
if (call->defer_update==FALSE){
linphone_core_accept_call_update(lc,call,NULL);
}
if (rmd==NULL)
if (rmd==NULL){
call->expect_media_in_ack=TRUE;
}
} else if( call->state == LinphoneCallPausedByRemote ){
/* Case where no SDP is present and we were paused by remote.
* We send back an ACK with our SDP and expect the remote to send its own.
* No state change here until an answer is received. */
call->defer_update=FALSE;
if (call->defer_update==FALSE){
_linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state));
}
if (rmd==NULL){
call->expect_media_in_ack=TRUE;
}
} else if (is_update){ /*SIP UPDATE case, can occur in early states*/
linphone_call_set_state(call, LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote");
_linphone_core_accept_call_update(lc,call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate));

View file

@ -234,35 +234,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;
}
@ -401,9 +520,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;i<old->nb_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;
@ -412,6 +538,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);
@ -445,9 +572,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;
if (call->audiostream && call->audiostream->ms.sessions.rtp_session) {
char* me = linphone_address_as_string_uri_only(call->me);
@ -467,7 +596,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;
if (call->videostream && call->videostream->ms.sessions.rtp_session) {
char* me = linphone_address_as_string_uri_only(call->me);
@ -490,7 +622,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;
}
@ -511,6 +646,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);
}

View file

@ -983,12 +983,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;i<RTP_PROFILE_MAX_PAYLOADS;++i){
it=rtp_profile_get_payload(prof,i);
const MSList *elem;
for(elem=default_list;elem!=NULL;elem=elem->next){
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) ){
@ -1010,7 +1011,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;
@ -1018,7 +1032,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;
@ -1026,85 +1040,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 (ra<rb) return -1;
return 1;
}
static MSList *add_missing_codecs(LinphoneCore *lc, SalStreamType mtype, MSList *l){
int i;
for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
PayloadType *pt=rtp_profile_get_payload(lc->default_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){
@ -1124,23 +1105,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);
@ -1413,60 +1394,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;i<RTP_PROFILE_MAX_PAYLOADS;++i){
bool_t already_assigned=FALSE;
for(elem=lc->payload_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;i<RTP_PROFILE_MAX_PAYLOADS;++i){
PayloadType *pt=rtp_profile_get_payload(prof,i);
if (pt){
// insert static payload only if no profile exists
if (rtp_profile_get_payload(lc->default_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){
@ -1548,10 +1514,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());
@ -1565,83 +1594,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();
@ -1848,8 +1804,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);
@ -1867,8 +1822,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);
@ -2632,6 +2586,15 @@ void linphone_core_iterate(LinphoneCore *lc){
}
}
static LinphoneAddress* _linphone_core_destroy_addr_if_not_sip( LinphoneAddress* addr ){
if( linphone_address_is_sip(addr) ) {
return addr;
} else {
linphone_address_destroy(addr);
return NULL;
}
}
/**
* Interpret a call destination as supplied by the user, and returns a fully qualified
* LinphoneAddress.
@ -2668,7 +2631,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url)
tmpurl=enumres->sip_address[0];
uri=linphone_address_new(tmpurl);
enum_lookup_res_free(enumres);
return uri;
return _linphone_core_destroy_addr_if_not_sip(uri);
}
/* check if we have a "sip:" or a "sips:" */
if ( (strstr(url,"sip:")==NULL) && (strstr(url,"sips:")==NULL) ){
@ -2679,7 +2642,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url)
uri=linphone_address_new(tmpurl);
ms_free(tmpurl);
if (uri){
return uri;
return _linphone_core_destroy_addr_if_not_sip(uri);
}
}
@ -2695,12 +2658,12 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url)
linphone_proxy_config_normalize_number(proxy,url,normalized_username,
sizeof(normalized_username));
linphone_address_set_username(uri,normalized_username);
return uri;
return _linphone_core_destroy_addr_if_not_sip(uri);
}else return NULL;
}
uri=linphone_address_new(url);
if (uri!=NULL){
return uri;
return _linphone_core_destroy_addr_if_not_sip(uri);
}
return NULL;
@ -4021,7 +3984,11 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
}
#endif //BUILD_UPNP
sal_call_set_local_media_description(call->op,call->localdesc);
if (!lc->sip_conf.sdp_200_ack){
sal_call_set_local_media_description(call->op,call->localdesc);
} else {
sal_call_set_local_media_description(call->op,NULL);
}
sal_media_description_set_dir(call->localdesc,SalStreamSendRecv);
if (call->params->in_conference && !call->current_params->in_conference) subject="Conference";
if ( sal_call_update(call->op,subject,FALSE) != 0){
@ -4032,6 +3999,12 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){
lc->current_call=call;
snprintf(temp,sizeof(temp)-1,"Resuming the call with %s",linphone_call_get_remote_address_as_string(call));
linphone_core_notify_display_status(lc,temp);
if (lc->sip_conf.sdp_200_ack){
/*we are NOT offering, set local media description after sending the call so that we are ready to
process the remote offer when it will arrive*/
sal_call_set_local_media_description(call->op,call->localdesc);
}
return 0;
}
@ -6195,8 +6168,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)
@ -6505,20 +6478,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) {

View file

@ -398,6 +398,7 @@ LINPHONE_PUBLIC void linphone_address_set_port(LinphoneAddress *uri, int port);
/*remove tags, params etc... so that it is displayable to the user*/
LINPHONE_PUBLIC void linphone_address_clean(LinphoneAddress *uri);
LINPHONE_PUBLIC bool_t linphone_address_is_secure(const LinphoneAddress *uri);
LINPHONE_PUBLIC bool_t linphone_address_is_sip(const LinphoneAddress *uri);
LINPHONE_PUBLIC LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri);
LINPHONE_PUBLIC void linphone_address_set_transport(LinphoneAddress *uri,LinphoneTransportType type);
LINPHONE_PUBLIC char *linphone_address_as_string(const LinphoneAddress *u);
@ -2345,8 +2346,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);

View file

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

View file

@ -31,7 +31,49 @@ static bool_t only_telephone_event(const MSList *l){
return TRUE;
}
static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){
typedef struct _PayloadTypeMatcher{
const char *mime_type;
PayloadType *(*match_func)(const MSList *l, const PayloadType *refpt);
}PayloadTypeMatcher;
static PayloadType * opus_match(const MSList *l, const PayloadType *refpt){
PayloadType *pt;
const MSList *elem;
PayloadType *candidate=NULL;
for (elem=l;elem!=NULL;elem=elem->next){
pt=(PayloadType*)elem->data;
/*workaround a bug in earlier versions of linphone where opus/48000/1 is offered, which is uncompliant with opus rtp draft*/
if (strcasecmp(pt->mime_type,"opus")==0 ){
if (refpt->channels==1){
pt->channels=1; /*so that we respond with same number of channels */
candidate=pt;
}else if (refpt->channels==2){
return pt;
}
}
}
return candidate;
}
/* the reason for this matcher is for some stupid uncompliant phone that offer G729a mime type !*/
static PayloadType * g729A_match(const MSList *l, const PayloadType *refpt){
PayloadType *pt;
const MSList *elem;
PayloadType *candidate=NULL;
for (elem=l;elem!=NULL;elem=elem->next){
pt=(PayloadType*)elem->data;
if (strcasecmp(pt->mime_type,"G729")==0 && refpt->channels==pt->channels){
candidate=pt;
}
}
return candidate;
}
static PayloadType * amr_match(const MSList *l, const PayloadType *refpt){
PayloadType *pt;
char value[10];
const MSList *elem;
@ -40,39 +82,63 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload
for (elem=l;elem!=NULL;elem=elem->next){
pt=(PayloadType*)elem->data;
/*workaround a bug in earlier versions of linphone where opus/48000/1 is offered, which is uncompliant with opus rtp draft*/
if (refpt->mime_type && strcasecmp(refpt->mime_type,"opus")==0 && refpt->channels==1
&& strcasecmp(pt->mime_type,refpt->mime_type)==0){
pt->channels=1; /*so that we respond with same number of channels */
candidate=pt;
break;
}
/* the compare between G729 and G729A is for some stupid uncompliant phone*/
if ( pt->mime_type && refpt->mime_type &&
(strcasecmp(pt->mime_type,refpt->mime_type)==0 ||
(strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 ))
&& pt->clock_rate==refpt->clock_rate && pt->channels==refpt->channels){
candidate=pt;
/*good candidate, check fmtp for H264 */
if (strcasecmp(pt->mime_type,"H264")==0){
if (pt->recv_fmtp!=NULL && refpt->recv_fmtp!=NULL){
int mode1=0,mode2=0;
if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))){
mode1=atoi(value);
}
if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))){
mode2=atoi(value);
}
if (mode1==mode2)
break; /*exact match */
}
}else break;
if ( pt->mime_type && refpt->mime_type
&& strcasecmp(pt->mime_type, refpt->mime_type)==0
&& pt->clock_rate==refpt->clock_rate
&& pt->channels==refpt->channels) {
int octedalign1=0,octedalign2=0;
if (pt->recv_fmtp!=NULL && fmtp_get_value(pt->recv_fmtp,"octet-align",value,sizeof(value))){
octedalign1=atoi(value);
}
if (refpt->send_fmtp!=NULL && fmtp_get_value(refpt->send_fmtp,"octet-align",value,sizeof(value))){
octedalign2=atoi(value);
}
if (octedalign1==octedalign2) {
candidate=pt;
break; /*exact match */
}
}
}
return candidate;
}
static PayloadType * generic_match(const MSList *l, const PayloadType *refpt){
PayloadType *pt;
const MSList *elem;
for (elem=l;elem!=NULL;elem=elem->next){
pt=(PayloadType*)elem->data;
if ( pt->mime_type && refpt->mime_type
&& strcasecmp(pt->mime_type, refpt->mime_type)==0
&& pt->clock_rate==refpt->clock_rate
&& pt->channels==refpt->channels)
return pt;
}
return NULL;
}
static PayloadTypeMatcher matchers[]={
{"opus", opus_match},
{"G729A", g729A_match},
{"AMR", amr_match},
{"AMR-WB", amr_match},
{NULL, NULL}
};
static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){
PayloadTypeMatcher *m;
for(m=matchers;m->mime_type!=NULL;++m){
if (refpt->mime_type && strcasecmp(m->mime_type,refpt->mime_type)==0){
return m->match_func(l,refpt);
}
}
return generic_match(l,refpt);
}
static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){
const MSList *e2,*e1;
MSList *res=NULL;
@ -110,6 +176,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 +187,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 +211,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);
}
}

View file

@ -353,6 +353,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);
@ -631,7 +632,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{
@ -698,7 +701,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;
@ -707,8 +711,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;
@ -1003,6 +1005,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

View file

@ -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(

View file

@ -62,9 +62,10 @@ SalMediaDescription *sal_media_description_new(){
static void sal_media_description_destroy(SalMediaDescription *md){
int i;
for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;i++){
ms_list_for_each(md->streams[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);
}

View file

@ -109,7 +109,8 @@ void sal_address_set_transport(SalAddress* addr,SalTransport transport);
void sal_address_set_transport_name(SalAddress* addr,const char* transport);
void sal_address_set_params(SalAddress *addr, const char *params);
void sal_address_set_uri_params(SalAddress *addr, const char *params);
bool_t sal_address_is_ipv6(SalAddress *addr);
bool_t sal_address_is_ipv6(const SalAddress *addr);
bool_t sal_address_is_sip(const SalAddress *addr);
void sal_address_set_password(SalAddress *addr, const char *passwd);
const char *sal_address_get_password(const SalAddress *addr);
void sal_address_set_header(SalAddress *addr, const char *header_name, const char *header_value);
@ -206,7 +207,8 @@ typedef struct SalStreamDescription{
char rtcp_cname[255];
int rtp_port;
int rtcp_port;
MSList *payloads; //<list of PayloadType
MSList *payloads; /*<list of PayloadType */
MSList *already_assigned_payloads; /*<list of PayloadType offered in the past, used for correct allocation of payload type numbers*/
int bandwidth;
int ptime;
SalStreamDir dir;

@ -1 +1 @@
Subproject commit d5389594e93c3499d70d9ddd556f9aac62aabc0a
Subproject commit 30e90d0f8a1a17fcd5b718a3eb8758f005f2052b

2
oRTP

@ -1 +1 @@
Subproject commit 723deb7e9e016f5134a6f708f28ee95694e97068
Subproject commit 4ef1702f7f8f21d65e6e9da68d4f8f2c2376f614

View file

@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: linphone-gtk\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-13 16:18+0100\n"
"PO-Revision-Date: 2015-01-06 14:11+0000\n"
"PO-Revision-Date: 2015-01-13 16:34+0000\n"
"Last-Translator: محيي الدين <tx99h4@hotmail.com>\n"
"Language-Team: Arabic (http://www.transifex.com/projects/p/linphone-gtk/"
"language/ar/)\n"

View file

@ -12,7 +12,7 @@ msgstr ""
"Project-Id-Version: linphone-gtk\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-13 16:18+0100\n"
"PO-Revision-Date: 2015-01-06 11:29+0000\n"
"PO-Revision-Date: 2015-01-13 16:34+0000\n"
"Last-Translator: Gautier Pelloux-Prayer <gautier.pelloux@gmail.com>\n"
"Language-Team: German (http://www.transifex.com/projects/p/linphone-gtk/"
"language/de/)\n"

View file

@ -12,7 +12,7 @@ msgstr ""
"Project-Id-Version: linphone-gtk\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-13 16:18+0100\n"
"PO-Revision-Date: 2015-01-06 11:41+0000\n"
"PO-Revision-Date: 2015-01-13 16:34+0000\n"
"Last-Translator: Gautier Pelloux-Prayer <gautier.pelloux@gmail.com>\n"
"Language-Team: French (http://www.transifex.com/projects/p/linphone-gtk/"
"language/fr/)\n"

View file

@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: linphone-gtk\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-13 16:18+0100\n"
"PO-Revision-Date: 2015-01-09 16:31+0000\n"
"PO-Revision-Date: 2015-01-13 16:34+0000\n"
"Last-Translator: Alexander\n"
"Language-Team: Japanese (http://www.transifex.com/projects/p/linphone-gtk/"
"language/ja/)\n"

View file

@ -13,7 +13,7 @@ msgstr ""
"Project-Id-Version: linphone-gtk\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-13 16:18+0100\n"
"PO-Revision-Date: 2015-01-07 08:31+0000\n"
"PO-Revision-Date: 2015-01-14 09:11+0000\n"
"Last-Translator: AlexL <loginov.alex.valer@gmail.com>\n"
"Language-Team: Russian (http://www.transifex.com/projects/p/linphone-gtk/"
"language/ru/)\n"

View file

@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: linphone-gtk\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-13 16:18+0100\n"
"PO-Revision-Date: 2015-01-07 17:21+0000\n"
"PO-Revision-Date: 2015-01-13 16:34+0000\n"
"Last-Translator: Мирослав Николић <miroslavnikolic@rocketmail.com>\n"
"Language-Team: Serbian (http://www.transifex.com/projects/p/linphone-gtk/"
"language/sr/)\n"

View file

@ -26,7 +26,8 @@ liblinphonetester_la_SOURCES = tester.c \
transport_tester.c \
player_tester.c \
dtmf_tester.c \
accountmanager.c
accountmanager.c \
offeranswer_tester.c
liblinphonetester_la_LDFLAGS= -no-undefined
liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS)

View file

@ -77,6 +77,7 @@ void account_manager_destroy(void){
ms_free(the_am);
}
the_am=NULL;
ms_message("Test account manager destroyed.");
}
Account *account_manager_get_account(AccountManager *m, const LinphoneAddress *identity){
@ -211,10 +212,6 @@ void linphone_core_manager_check_accounts(LinphoneCoreManager *m){
for(it=linphone_core_get_proxy_config_list(m->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);
}
}

View file

@ -33,8 +33,6 @@
#endif
static void srtp_call(void);
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()
@ -728,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;
@ -755,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};
@ -2017,15 +1981,13 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag
CU_ASSERT_PTR_NOT_NULL_FATAL(marie_call_laure);
linphone_core_add_to_conference(marie->lc,marie_call_laure);
CU_ASSERT_TRUE(wait_for(marie->lc,laure->lc,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1,5000));
linphone_core_add_to_conference(marie->lc,marie_call_pauline);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,5000));
CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,3000));
@ -2160,12 +2122,16 @@ static void call_with_file_player(void) {
linphone_core_terminate_all_calls(marie->lc);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1));
#ifndef __arm__
CU_ASSERT_TRUE(ms_audio_diff(hellopath,recordpath,&similar,NULL,NULL)==0);
CU_ASSERT_TRUE(similar>threshold);
CU_ASSERT_TRUE(similar<=1.0);
if(similar > threshold && similar <=1.0) {
remove(recordpath);
}
#else
remove(recordpath);
#endif
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
ms_free(recordpath);
@ -2228,16 +2194,16 @@ static void call_with_mkv_file_player(void) {
linphone_core_terminate_all_calls(marie->lc);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1));
#ifdef ANDROID
/*inter-correlation process is too much CPU consuming ending in a 20 minutes test on Android...*/
remove(recordpath);
#else
#ifndef __arm__
CU_ASSERT_TRUE(ms_audio_diff(hellowav,recordpath,&similar,NULL,NULL)==0);
CU_ASSERT_TRUE(similar>threshold);
CU_ASSERT_TRUE(similar<=1.0);
if(similar>threshold && similar<=1.0) {
remove(recordpath);
}
#else
/*inter-correlation process is too much CPU consuming ending in a 20 minutes test on arm...*/
remove(recordpath);
#endif
ms_free(recordpath);
@ -3061,115 +3027,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);
}
@ -3548,6 +3405,65 @@ static void outgoing_reinvite_without_ack_sdp() {
#endif
}
static void call_with_paused_no_sdp_on_resume() {
int begin;
int leaked_objects;
int dummy=0;
LinphoneCoreManager* marie;
LinphoneCoreManager* pauline;
LinphoneCall* call_marie = NULL;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_rc");
CU_ASSERT_TRUE(call(pauline,marie));
liblinphone_tester_check_rtcp(marie,pauline);
call_marie = linphone_core_get_current_call(marie->lc);
CU_ASSERT_PTR_NOT_NULL(call_marie);
ms_message("== Call is OK ==");
/* the called party pause the call */
wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000);
linphone_core_pause_call(marie->lc,call_marie);
ms_message("== Call pausing ==");
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1));
/*stay in pause a little while in order to generate traffic*/
wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000);
ms_message("== Call paused, marie call: %p ==", call_marie);
linphone_core_enable_sdp_200_ack(marie->lc,TRUE);
linphone_core_resume_call(marie->lc,call_marie);
CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2));
CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2));
wait_for_until(marie->lc, pauline->lc, &dummy, 1, 3000);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(call_marie)->download_bandwidth>70);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth>70);
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();
}
}
test_t call_tests[] = {
{ "Early declined call", early_declined_call },
{ "Call declined", call_declined },
@ -3555,7 +3471,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},
@ -3633,25 +3548,10 @@ 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 },
{ "Call with pause no SDP on resume", call_with_paused_no_sdp_on_resume },
{ "Call with custom supported tags", call_with_custom_supported_tags },
{ "Call log from taken from asserted id",call_log_from_taken_from_p_asserted_id},
{ "Incoming INVITE without SDP",incoming_invite_without_sdp},

View file

@ -109,6 +109,14 @@ JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject
return ret;
}
JNIEXPORT void JNICALL Java_org_linphone_tester_Tester_keepAccounts(JNIEnv *env, jclass c, jboolean keep) {
liblinphone_tester_keep_accounts((int)keep);
}
JNIEXPORT void JNICALL Java_org_linphone_tester_Tester_clearAccounts(JNIEnv *env, jclass c) {
liblinphone_tester_clear_accounts();
}
#endif /* ANDROID */
#ifdef __QNX__

View file

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

View file

@ -32,8 +32,8 @@
#endif
/*getline is not available on android...*/
#ifdef ANDROID
/*getline is POSIX 2008, not available on many systems.*/
#if defined(ANDROID) || defined(WIN32)
/* This code is public domain -- Will Hartung 4/9/09 */
size_t getline(char **lineptr, size_t *n, FILE *stream) {
char *bufptr = NULL;
@ -153,8 +153,10 @@ time_t check_file(LinphoneCoreManager* mgr) {
int line_count = 0;
char *line = NULL;
size_t line_size = 256;
#ifndef WIN32
struct tm tm_curr;
time_t time_prev = -1;
#endif
#if HAVE_ZLIB
// 0) if zlib is enabled, we must decompress the file first
@ -170,6 +172,7 @@ time_t check_file(LinphoneCoreManager* mgr) {
while (getline(&line, &line_size, file) != -1) {
// a) there should be at least 25 lines
++line_count;
#ifndef WIN32
// b) logs should be ordered by date (format: 2014-11-04 15:22:12:606)
if (strlen(line) > 24) {
char date[24] = {'\0'};
@ -180,6 +183,9 @@ time_t check_file(LinphoneCoreManager* mgr) {
time_prev = time_curr;
}
}
#else
ms_warning("strptime() not available for this platform, test is incomplete.");
#endif
}
CU_ASSERT_TRUE(line_count > 25);
free(line);

297
tester/offeranswer_tester.c Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "CUnit/Basic.h"
#include "linphonecore.h"
#include "lpconfig.h"
#include "private.h"
#include "liblinphone_tester.h"
static int get_codec_position(const MSList *l, const char *mime_type, int rate){
const MSList *elem;
int i;
for (elem=l, i=0; elem!=NULL; elem=elem->next,i++){
PayloadType *pt=(PayloadType*)elem->data;
if (strcasecmp(pt->mime_type, mime_type)==0 && pt->clock_rate==rate) return i;
}
return -1;
}
/*check basic things about codecs at startup: order and enablement*/
static void start_with_no_config(void){
LinphoneCoreVTable vtable={0};
LinphoneCore *lc=linphone_core_new(&vtable, NULL, NULL, NULL);
const MSList *codecs=linphone_core_get_audio_codecs(lc);
int opus_codec_pos;
int speex_codec_pos=get_codec_position(codecs, "speex", 8000);
int speex16_codec_pos=get_codec_position(codecs, "speex", 16000);
PayloadType *pt;
opus_codec_pos=get_codec_position(codecs, "opus", 48000);
if (opus_codec_pos!=-1) CU_ASSERT_TRUE(opus_codec_pos==0);
CU_ASSERT_TRUE(speex16_codec_pos<speex_codec_pos);
pt=linphone_core_find_payload_type(lc, "speex", 16000, 1);
CU_ASSERT_PTR_NOT_NULL(pt);
if (pt) {
CU_ASSERT_TRUE(linphone_core_payload_type_enabled(lc, pt)==TRUE);
}
linphone_core_destroy(lc);
}
static void check_payload_type_numbers(LinphoneCall *call1, LinphoneCall *call2, int expected_number){
const LinphoneCallParams *params=linphone_call_get_current_params(call1);
const PayloadType *pt=linphone_call_params_get_used_audio_codec(params);
CU_ASSERT_PTR_NOT_NULL(pt);
if (pt){
CU_ASSERT_TRUE(linphone_core_get_payload_type_number(linphone_call_get_core(call1),pt)==expected_number);
}
params=linphone_call_get_current_params(call2);
pt=linphone_call_params_get_used_audio_codec(params);
CU_ASSERT_PTR_NOT_NULL(pt);
if (pt){
CU_ASSERT_TRUE(linphone_core_get_payload_type_number(linphone_call_get_core(call1),pt)==expected_number);
}
}
static void simple_call_with_different_codec_mappings(void) {
int begin;
int leaked_objects;
LinphoneCoreManager* marie;
LinphoneCoreManager* pauline;
LinphoneCall *pauline_call;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_rc");
disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1);
disable_all_audio_codecs_except_one(pauline->lc,"pcmu",-1);
/*marie set a fantasy number to PCMU*/
linphone_core_set_payload_type_number(marie->lc,
linphone_core_find_payload_type(marie->lc, "PCMU", 8000, -1),
104);
CU_ASSERT_TRUE(call(marie,pauline));
pauline_call=linphone_core_get_current_call(pauline->lc);
CU_ASSERT_PTR_NOT_NULL(pauline_call);
if (pauline_call){
LinphoneCallParams *params;
check_payload_type_numbers(linphone_core_get_current_call(marie->lc), pauline_call, 104);
/*make a reinvite in the other direction*/
linphone_core_update_call(pauline->lc, pauline_call,
params=linphone_core_create_call_params(pauline->lc, pauline_call));
linphone_call_params_unref(params);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdating,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdatedByRemote,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2));
/*payload type numbers shall remain the same*/
check_payload_type_numbers(linphone_core_get_current_call(marie->lc), pauline_call, 104);
}
end_call(marie,pauline);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_TRUE(leaked_objects==0);
if (leaked_objects>0){
belle_sip_object_dump_active_objects();
}
}
static void call_failed_because_of_codecs(void) {
int begin,leaked_objects;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
{
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall* out_call;
disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1);
disable_all_audio_codecs_except_one(pauline->lc,"pcma",-1);
out_call = linphone_core_invite_address(pauline->lc,marie->identity);
linphone_call_ref(out_call);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1));
/*flexisip will retain the 488 until the "urgent reply" timeout (I.E 5s) arrives.*/
CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,7000));
CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonNotAcceptable);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallReleased,0);
linphone_call_unref(out_call);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_TRUE(leaked_objects==0);
if (leaked_objects>0){
belle_sip_object_dump_active_objects();
}
}
static void profile_call(bool_t avpf1, bool_t srtp1, bool_t avpf2, bool_t srtp2, const char *expected_profile) {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc");
LinphoneProxyConfig *lpc;
const LinphoneCallParams *params;
if (avpf1) {
linphone_core_get_default_proxy(marie->lc, &lpc);
linphone_proxy_config_enable_avpf(lpc, TRUE);
linphone_proxy_config_set_avpf_rr_interval(lpc, 3);
}
if (avpf2) {
linphone_core_get_default_proxy(pauline->lc, &lpc);
linphone_proxy_config_enable_avpf(lpc, TRUE);
linphone_proxy_config_set_avpf_rr_interval(lpc, 3);
}
if (srtp1) {
if (linphone_core_media_encryption_supported(marie->lc, LinphoneMediaEncryptionSRTP)) {
linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionSRTP);
}
}
if (srtp2) {
if (linphone_core_media_encryption_supported(pauline->lc, LinphoneMediaEncryptionSRTP)) {
linphone_core_set_media_encryption(pauline->lc, LinphoneMediaEncryptionSRTP);
}
}
CU_ASSERT_TRUE(call(marie, pauline));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
params = linphone_call_get_current_params(linphone_core_get_current_call(marie->lc));
CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile);
params = linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc));
CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile);
linphone_core_terminate_all_calls(marie->lc);
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected, 1);
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallConnected, 1);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(marie);
}
static void avp_to_avp_call(void) {
profile_call(FALSE, FALSE, FALSE, FALSE, "RTP/AVP");
}
static void avp_to_avpf_call(void) {
profile_call(FALSE, FALSE, TRUE, FALSE, "RTP/AVP");
}
static void avp_to_savp_call(void) {
profile_call(FALSE, FALSE, FALSE, TRUE, "RTP/AVP");
}
static void avp_to_savpf_call(void) {
profile_call(FALSE, FALSE, TRUE, TRUE, "RTP/AVP");
}
static void avpf_to_avp_call(void) {
profile_call(TRUE, FALSE, FALSE, FALSE, "RTP/AVPF");
}
static void avpf_to_avpf_call(void) {
profile_call(TRUE, FALSE, TRUE, FALSE, "RTP/AVPF");
}
static void avpf_to_savp_call(void) {
profile_call(TRUE, FALSE, FALSE, TRUE, "RTP/AVPF");
}
static void avpf_to_savpf_call(void) {
profile_call(TRUE, FALSE, TRUE, TRUE, "RTP/AVPF");
}
static void savp_to_avp_call(void) {
profile_call(FALSE, TRUE, FALSE, FALSE, "RTP/SAVP");
}
static void savp_to_avpf_call(void) {
profile_call(FALSE, TRUE, TRUE, FALSE, "RTP/SAVP");
}
static void savp_to_savp_call(void) {
profile_call(FALSE, TRUE, FALSE, TRUE, "RTP/SAVP");
}
static void savp_to_savpf_call(void) {
profile_call(FALSE, TRUE, TRUE, TRUE, "RTP/SAVP");
}
static void savpf_to_avp_call(void) {
profile_call(TRUE, TRUE, FALSE, FALSE, "RTP/SAVPF");
}
static void savpf_to_avpf_call(void) {
profile_call(TRUE, TRUE, TRUE, FALSE, "RTP/SAVPF");
}
static void savpf_to_savp_call(void) {
profile_call(TRUE, TRUE, FALSE, TRUE, "RTP/SAVPF");
}
static void savpf_to_savpf_call(void) {
profile_call(TRUE, TRUE, TRUE, TRUE, "RTP/SAVPF");
}
static test_t offeranswer_tests[] = {
{ "Start with no config", start_with_no_config },
{ "Call failed because of codecs", call_failed_because_of_codecs },
{ "Simple call with different codec mappings", simple_call_with_different_codec_mappings},
{ "AVP to AVP call", avp_to_avp_call },
{ "AVP to AVPF call", avp_to_avpf_call },
{ "AVP to SAVP call", avp_to_savp_call },
{ "AVP to SAVPF call", avp_to_savpf_call },
{ "AVPF to AVP call", avpf_to_avp_call },
{ "AVPF to AVPF call", avpf_to_avpf_call },
{ "AVPF to SAVP call", avpf_to_savp_call },
{ "AVPF to SAVPF call", avpf_to_savpf_call },
{ "SAVP to AVP call", savp_to_avp_call },
{ "SAVP to AVPF call", savp_to_avpf_call },
{ "SAVP to SAVP call", savp_to_savp_call },
{ "SAVP to SAVPF call", savp_to_savpf_call },
{ "SAVPF to AVP call", savpf_to_avp_call },
{ "SAVPF to AVPF call", savpf_to_avpf_call },
{ "SAVPF to SAVP call", savpf_to_savp_call },
{ "SAVPF to SAVPF call", savpf_to_savpf_call },
};
test_suite_t offeranswer_test_suite = {
"Offer-answer",
NULL,
NULL,
sizeof(offeranswer_tests) / sizeof(offeranswer_tests[0]),
offeranswer_tests
};

View file

@ -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(&register_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);

View file

@ -181,11 +181,11 @@ class TestRegister:
cm = CoreManager('multi_account_rc', False)
number_of_udp_proxies = reduce(lambda x, y: x + int(y.transport == "udp"), cm.lc.proxy_config_list, 0)
total_number_of_proxies = len(cm.lc.proxy_config_list)
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationOk == total_number_of_proxies), True)
register_ok = cm.stats.number_of_LinphoneRegistrationOk
# Keep only UDP
tr = cm.lc.sip_transports
tr.tcp_port = 0
tr.tls_port = 0
tr.dtls_port = 0
tr = linphone.SipTransports(0, 0, 0, 0)
tr.udp_port = cm.lc.sip_transports.udp_port
cm.lc.sip_transports = tr
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationOk == number_of_udp_proxies), True)
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationOk == (register_ok + number_of_udp_proxies)), True)
assert_equals(CoreManager.wait_for(cm, cm, lambda cm1, cm2: cm1.stats.number_of_LinphoneRegistrationFailed == (total_number_of_proxies - number_of_udp_proxies)), True)