diff --git a/Makefile.am b/Makefile.am
index 2fd425a0d..4f3f46860 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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.
diff --git a/README.macos.md b/README.macos.md
index 381efcf2f..4028bb40a 100644
--- a/README.macos.md
+++ b/README.macos.md
@@ -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
+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:
+
+ /usr/local
+
Then run, inside Linphone source tree configure as told before but with `--enable-relativeprefix` appended.
make && make bundle
diff --git a/autogen.sh b/autogen.sh
index 9cedbf164..d5ec9ea80 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -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
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/build/macos/Info-linphone.plist.in b/build/macos/Info-linphone.plist.in
index b9cde78a9..7d20d4ac6 100644
--- a/build/macos/Info-linphone.plist.in
+++ b/build/macos/Info-linphone.plist.in
@@ -26,6 +26,8 @@
Copyright 2011 Belledonne Communications
LSMinimumSystemVersion
10.4
+ NSAppSleepDisabled
+ YES
diff --git a/configure.ac b/configure.ac
index 40d93a208..6edb22499 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
diff --git a/coreapi/address.c b/coreapi/address.c
index 764a8fb24..d9d772337 100644
--- a/coreapi/address.c
+++ b/coreapi/address.c
@@ -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;
diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c
index c4ff234d7..034135f72 100644
--- a/coreapi/bellesip_sal/sal_address_impl.c
+++ b/coreapi/bellesip_sal/sal_address_impl.c
@@ -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){
diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c
index 921184cf6..4aca82a81 100644
--- a/coreapi/bellesip_sal/sal_op_call.c
+++ b/coreapi/bellesip_sal/sal_op_call.c
@@ -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);
diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c
index 4409c73a3..d4a24bd9b 100644
--- a/coreapi/bellesip_sal/sal_op_events.c
+++ b/coreapi/bellesip_sal/sal_op_events.c
@@ -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);
diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c
index 2e68146a0..5c953ffc5 100644
--- a/coreapi/bellesip_sal/sal_op_impl.c
+++ b/coreapi/bellesip_sal/sal_op_impl.c
@@ -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 ",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);
}
}
diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c
index 3324cefb7..017845833 100644
--- a/coreapi/bellesip_sal/sal_op_message.c
+++ b/coreapi/bellesip_sal/sal_op_message.c
@@ -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)));
}
diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c
index 23db49e6f..6de0a0fbf 100644
--- a/coreapi/bellesip_sal/sal_op_presence.c
+++ b/coreapi/bellesip_sal/sal_op_presence.c
@@ -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);
}
diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c
index 2655c58d2..17ef8e8db 100644
--- a/coreapi/bellesip_sal/sal_op_publish.c
+++ b/coreapi/bellesip_sal/sal_op_publish.c
@@ -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)));
}
diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c
index fe65a4282..ad425b21c 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);
@@ -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));
diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c
index 8923b804a..d3766c174 100644
--- a/coreapi/linphonecall.c
+++ b/coreapi/linphonecall.c
@@ -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;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;
@@ -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);
}
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index 678d0ca53..393f405ea 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -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;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) ){
@@ -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 (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){
@@ -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;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){
@@ -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) {
diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h
index 3ec93dc5d..f7d8af700 100644
--- a/coreapi/linphonecore.h
+++ b/coreapi/linphonecore.h
@@ -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);
diff --git a/coreapi/misc.c b/coreapi/misc.c
index 99ea9182d..5912acc8f 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 755c6bcd7..ef14fad81 100644
--- a/coreapi/offeranswer.c
+++ b/coreapi/offeranswer.c
@@ -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);
}
}
diff --git a/coreapi/private.h b/coreapi/private.h
index 9978252fa..8778f1020 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -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
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 6aa444947..ea26b25d8 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 e2ce603cc..f765bf349 100644
--- a/include/sal/sal.h
+++ b/include/sal/sal.h
@@ -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; //\n"
"Language-Team: Arabic (http://www.transifex.com/projects/p/linphone-gtk/"
"language/ar/)\n"
diff --git a/po/de.po b/po/de.po
index 2446bd02c..229f60c71 100644
--- a/po/de.po
+++ b/po/de.po
@@ -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 \n"
"Language-Team: German (http://www.transifex.com/projects/p/linphone-gtk/"
"language/de/)\n"
diff --git a/po/fr.po b/po/fr.po
index 23a2060fa..aff7882d6 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -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 \n"
"Language-Team: French (http://www.transifex.com/projects/p/linphone-gtk/"
"language/fr/)\n"
diff --git a/po/ja.po b/po/ja.po
index 0ebeaa016..e998ee25c 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -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"
diff --git a/po/ru.po b/po/ru.po
index fd7b8f5b9..b3e312070 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -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 \n"
"Language-Team: Russian (http://www.transifex.com/projects/p/linphone-gtk/"
"language/ru/)\n"
diff --git a/po/sr.po b/po/sr.po
index ae6f5da59..56f9e5f19 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -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: Мирослав Николић \n"
"Language-Team: Serbian (http://www.transifex.com/projects/p/linphone-gtk/"
"language/sr/)\n"
diff --git a/tester/Makefile.am b/tester/Makefile.am
index d296841ad..6c5ba79bc 100644
--- a/tester/Makefile.am
+++ b/tester/Makefile.am
@@ -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)
diff --git a/tester/accountmanager.c b/tester/accountmanager.c
index 97cf8803b..2236b2039 100644
--- a/tester/accountmanager.c
+++ b/tester/accountmanager.c
@@ -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);
}
}
diff --git a/tester/call_tester.c b/tester/call_tester.c
index ca02f9ef3..5103ea15e 100644
--- a/tester/call_tester.c
+++ b/tester/call_tester.c
@@ -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},
diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c
index aa4f78f29..27b9672b0 100644
--- a/tester/liblinphone_tester.c
+++ b/tester/liblinphone_tester.c
@@ -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__
diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h
index dded33942..b6aca2626 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/log_collection_tester.c b/tester/log_collection_tester.c
index 35cf8d1f2..3260e3078 100644
--- a/tester/log_collection_tester.c
+++ b/tester/log_collection_tester.c
@@ -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);
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);
diff --git a/tools/python/unittests/test_register.py b/tools/python/unittests/test_register.py
index f62da77e0..abfa6fa17 100644
--- a/tools/python/unittests/test_register.py
+++ b/tools/python/unittests/test_register.py
@@ -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)