Merge remote-tracking branch 'origin' into dev_lime

Conflicts:
	build/android/Android.mk
	coreapi/Makefile.am
This commit is contained in:
Jehan Monnier 2014-05-14 15:15:50 +02:00
commit ed4d9c0d20
52 changed files with 2384 additions and 1009 deletions

View file

@ -118,8 +118,8 @@ linphone-deps packages.
List of software included in linphone-deps:
antlr3c (compiled)
bzrtp (compiled)
polarssl (compiled
belle-sip (compiled)
libsrtp (compiled)
libavcodec, libavutil, libavformat, libavdevice, libswscale (compiled, all these from ffmpeg)
libtheora (from the web)
@ -167,6 +167,14 @@ When running "make install DESTDIR=<somepath>", somepath must be absolute and sh
$ make install
$ make install DESTDIR=/home/<myuser>/libsrtp-install
- building bzrtp
* download the sources with msys-git shell using the following command:
$ git clone git://git.linphone.org/bzrtp.git
* compile and install
$ ./autogen.sh
$ ./configure --prefix=/usr --enable-shared --disable-static
$ make && make install
- building sqlite3
* download the sources on the following website:
http://www.sqlite.org/download.html (choose the sqlite-autoconf-3XXX.tar.gz)

View file

@ -65,7 +65,8 @@ LOCAL_SRC_FILES := \
xml2lpc.c \
lpc2xml.c \
remote_provisioning.c \
lime.c
lime.c \
quality_reporting.c
ifndef LINPHONE_VERSION
LINPHONE_VERSION = "Devel"

View file

@ -203,6 +203,7 @@
<ClCompile Include="..\..\..\coreapi\offeranswer.c" />
<ClCompile Include="..\..\..\coreapi\presence.c" />
<ClCompile Include="..\..\..\coreapi\proxy.c" />
<ClCompile Include="..\..\..\coreapi\quality_reporting.c" />
<ClCompile Include="..\..\..\coreapi\sal.c" />
<ClCompile Include="..\..\..\coreapi\siplogin.c" />
<ClCompile Include="..\..\..\coreapi\sipsetup.c" />
@ -275,4 +276,4 @@
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsPhone\v$(TargetPlatformVersion)\Microsoft.Cpp.WindowsPhone.$(TargetPlatformVersion).targets" Condition="'$(Platform)'=='ARM'" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -1,3 +1,7 @@
if(MSVC)
find_library(LIBGCC NAMES gcc)
find_library(LIBMINGWEX NAMES mingwex)
endif()
find_library(LIBORTP NAMES ortp)
find_library(LIBMEDIASTREAMER_BASE NAMES mediastreamer_base)
find_library(LIBMEDIASTREAMER_VOIP NAMES mediastreamer_voip)
@ -74,6 +78,7 @@ set(SOURCE_FILES
offeranswer.c
presence.c
proxy.c
quality_reporting.c
remote_provisioning.c
sal.c
siplogin.c
@ -118,7 +123,7 @@ add_definitions(
set(LIBS ws2_32)
endif(WIN32)
set(LIBS ${LIBS} ${LIBORTP} ${LIBMEDIASTREAMER_BASE} ${LIBMEDIASTREAMER_VOIP} ${LIBBELLESIP} ${LIBXML2})
set(LIBS ${LIBS} ${LIBGCC} ${LIBMINGWEX} ${LIBORTP} ${LIBMEDIASTREAMER_BASE} ${LIBMEDIASTREAMER_VOIP} ${LIBBELLESIP} ${LIBXML2})
add_library(linphone SHARED ${SOURCE_FILES})
set_target_properties(linphone PROPERTIES VERSION 3.7.0 SOVERSION 5)

View file

@ -18,11 +18,7 @@ CLEANFILES=$(GITVERSION_FILE)
## Process this file with automake to produce Makefile.in
linphone_includedir=$(includedir)/linphone
linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonepresence.h linphonecore_utils.h lpconfig.h sipsetup.h event.h xml2lpc.h lpc2xml.h
if BUILD_TUNNEL
linphone_include_HEADERS+=linphone_tunnel.h
endif
linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonepresence.h linphonecore_utils.h lpconfig.h sipsetup.h event.h xml2lpc.h lpc2xml.h linphone_tunnel.h
lib_LTLIBRARIES=liblinphone.la
@ -57,6 +53,7 @@ liblinphone_la_SOURCES=\
lpc2xml.c \
remote_provisioning.c \
lime.c \
quality_reporting.c quality_reporting.h\
$(GITVERSION_FILE)
if BUILD_UPNP
@ -82,9 +79,9 @@ endif
liblinphone_la_SOURCES+=linphone_tunnel_config.c
if BUILD_TUNNEL
liblinphone_la_SOURCES+=linphone_tunnel.cc TunnelManager.cc TunnelManager.hh
liblinphone_la_SOURCES+=linphone_tunnel.cc TunnelManager.cc TunnelManager.hh linphone_tunnel.h
else
liblinphone_la_SOURCES+=linphone_tunnel_stubs.c
liblinphone_la_SOURCES+=linphone_tunnel_stubs.c linphone_tunnel.h
endif

View file

@ -117,7 +117,7 @@ void sal_process_authentication(SalOp *op) {
belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction);
belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(initial_request,belle_sip_header_from_t);
belle_sip_uri_t *from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from);
if (strcasecmp(belle_sip_uri_get_host(from_uri),"anonymous.invalid")==0){
/*prefer using the from from the SalOp*/
from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)sal_op_get_from_address(op));
@ -137,7 +137,7 @@ void sal_process_authentication(SalOp *op) {
ms_error("sal_process_authentication() op=[%p] cannot obtain new request from dialog.",op);
return;
}
if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,from_uri,&auth_list)) {
if (is_within_dialog) {
sal_op_send_request(op,new_request);
@ -308,7 +308,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
belle_sip_response_t* response = belle_sip_response_event_get_response(event);
int response_code = belle_sip_response_get_status_code(response);
if (!client_transaction) {
ms_warning("Discarding stateless response [%i]",response_code);
return;
@ -334,11 +334,11 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
}
sal_op_assign_recv_headers(op,(belle_sip_message_t*)response);
if (op->callbacks && op->callbacks->process_response_event) {
/*handle authorization*/
switch (response_code) {
case 200:
case 200:
break;
case 401:
case 407:
@ -424,14 +424,18 @@ Sal * sal_init(){
belle_sip_listener_callbacks_t listener_callbacks;
Sal * sal=ms_new0(Sal,1);
sal->auto_contacts=TRUE;
/*first create the stack, which initializes the belle-sip object's pool for this thread*/
belle_sip_set_log_handler(_belle_sip_log);
sal->stack = belle_sip_stack_new(NULL);
sal->user_agent=belle_sip_header_user_agent_new();
#if defined(PACKAGE_NAME) && defined(LINPHONE_VERSION)
belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION);
#endif
sal_append_stack_string_to_user_agent(sal);
belle_sip_object_ref(sal->user_agent);
belle_sip_set_log_handler(_belle_sip_log);
sal->stack = belle_sip_stack_new(NULL);
sal->prov = belle_sip_stack_create_provider(sal->stack,NULL);
sal_nat_helper_enable(sal,TRUE);
memset(&listener_callbacks,0,sizeof(listener_callbacks));
@ -677,10 +681,10 @@ static void set_tls_properties(Sal *ctx){
if (lp){
belle_sip_tls_listening_point_t *tlp=BELLE_SIP_TLS_LISTENING_POINT(lp);
int verify_exceptions=0;
if (!ctx->tls_verify) verify_exceptions=BELLE_SIP_TLS_LISTENING_POINT_BADCERT_ANY_REASON;
else if (!ctx->tls_verify_cn) verify_exceptions=BELLE_SIP_TLS_LISTENING_POINT_BADCERT_CN_MISMATCH;
belle_sip_tls_listening_point_set_root_ca(tlp,ctx->root_ca); /*root_ca might be NULL */
belle_sip_tls_listening_point_set_verify_exceptions(tlp,verify_exceptions);
}
@ -802,7 +806,7 @@ void sal_auth_info_set_mode(SalAuthInfo* auth_info, SalAuthMode mode) { auth_inf
void sal_certificates_chain_delete(SalCertificatesChain *chain) {
belle_sip_object_unref((belle_sip_object_t *)chain);
}
void sal_signing_key_delete(SalSigningKey *key) {
void sal_signing_key_delete(SalSigningKey *key) {
belle_sip_object_unref((belle_sip_object_t *)key);
}
@ -829,7 +833,7 @@ int sal_auth_compute_ha1(const char* userid,const char* realm,const char* passwo
SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){
belle_sip_message_t *msg=(belle_sip_message_t*)ch;
belle_sip_header_t *h;
if (msg==NULL){
msg=(belle_sip_message_t*)belle_sip_request_new();
belle_sip_object_ref(msg);
@ -846,7 +850,7 @@ SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name,
const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){
if (ch){
belle_sip_header_t *h=belle_sip_message_get_header((belle_sip_message_t*)ch,name);
if (h){
return belle_sip_header_get_unparsed_value(h);
}
@ -879,12 +883,12 @@ void sal_set_uuid(Sal *sal, const char *uuid){
}
typedef struct {
unsigned int time_low;
unsigned short time_mid;
unsigned short time_hi_and_version;
unsigned char clock_seq_hi_and_reserved;
unsigned char clock_seq_low;
unsigned char node[6];
unsigned int time_low;
unsigned short time_mid;
unsigned short time_hi_and_version;
unsigned char clock_seq_hi_and_reserved;
unsigned char clock_seq_low;
unsigned char node[6];
} sal_uuid_t;
@ -892,7 +896,7 @@ int sal_create_uuid(Sal*ctx, char *uuid, size_t len){
sal_uuid_t uuid_struct;
int i;
int written;
if (len==0) return -1;
/*create an UUID as described in RFC4122, 4.4 */
belle_sip_random_bytes((unsigned char*)&uuid_struct, sizeof(sal_uuid_t));
@ -900,7 +904,7 @@ int sal_create_uuid(Sal*ctx, char *uuid, size_t len){
uuid_struct.clock_seq_hi_and_reserved|=1<<7;
uuid_struct.time_hi_and_version&=~(0xf<<12);
uuid_struct.time_hi_and_version|=4<<12;
written=snprintf(uuid,len,"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", uuid_struct.time_low, uuid_struct.time_mid,
uuid_struct.time_hi_and_version, uuid_struct.clock_seq_hi_and_reserved,
uuid_struct.clock_seq_low);
@ -938,6 +942,10 @@ void sal_enable_test_features(Sal*ctx, bool_t enabled){
ctx->enable_test_features=enabled;
}
void sal_use_no_initial_route(Sal *ctx, bool_t enabled){
ctx->no_initial_route=enabled;
}
SalResolverContext * sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data){
return (SalResolverContext*)belle_sip_stack_resolve_a(sal->stack,name,port,family,(belle_sip_resolver_callback_t)cb,data);
}

View file

@ -47,6 +47,7 @@ struct Sal{
bool_t use_dates;
bool_t auto_contacts;
bool_t enable_test_features;
bool_t no_initial_route;
};
typedef enum SalOpState {

View file

@ -111,9 +111,9 @@ static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription
}
static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
SalOp* op=(SalOp*)user_ctx;
if (op->state==SalOpStateTerminated) return;
if (!op->dialog) {
/*call terminated very early*/
sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO error",NULL);
@ -129,7 +129,7 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat
if (op->dialog && op->dialog==belle_sip_dialog_terminated_event_get_dialog(event)) {
/*belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog);*/
ms_message("Dialog [%p] terminated for op [%p]",belle_sip_dialog_terminated_event_get_dialog(event),op);
switch(belle_sip_dialog_get_previous_state(op->dialog)) {
case BELLE_SIP_DIALOG_CONFIRMED:
if (op->state!=SalOpStateTerminated && op->state!=SalOpStateTerminating) {
@ -192,7 +192,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
set_or_update_dialog(op,belle_sip_response_event_get_dialog(event));
dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,op->dialog,belle_sip_dialog_state_to_string(dialog_state));
switch(dialog_state) {
@ -290,9 +290,9 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
SalOp* op=(SalOp*)user_ctx;
if (op->state==SalOpStateTerminated) return;
if (!op->dialog) {
/*call terminated very early*/
sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL);
@ -342,7 +342,7 @@ static void unsupported_method(belle_sip_server_transaction_t* server_transactio
* Extract the sdp from a sip message.
* If there is no body in the message, the session_desc is set to null, 0 is returned.
* If body was present is not a SDP or parsing of SDP failed, -1 is returned and SalReason is set appropriately.
*
*
**/
static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) {
belle_sip_header_content_type_t* content_type=belle_sip_message_get_header_by_type(message,belle_sip_header_content_type_t);
@ -388,7 +388,7 @@ static int process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) {
belle_sip_object_unref(sdp);
}else op->sdp_offering=TRUE; /*INVITE without SDP*/
}else err=-1;
if (err==-1){
sal_call_decline(op,reason,NULL);
}
@ -560,6 +560,18 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
belle_sip_server_transaction_send_response(server_transaction,sal_op_create_response_from_request(op,req,481));
} else if (strcmp("MESSAGE",method)==0){
sal_process_incoming_message(op,event);
} else if (strcmp("UPDATE",method)==0) {
/*rfc 3311
* 5.2 Receiving an UPDATE
* ...
* If the UAS cannot change the session parameters without prompting the user, it SHOULD reject
* the request with a 504 response.
*/
resp=sal_op_create_response_from_request(op,req,504);
belle_sip_message_add_header( BELLE_SIP_MESSAGE(resp)
,belle_sip_header_create( "Warning", "Cannot change the session parameters without prompting the user"));
belle_sip_server_transaction_send_response(server_transaction,resp);
return;
}else{
ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog);
unsupported_method(server_transaction,req);
@ -582,7 +594,7 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){
if (op->base.local_media)
sal_media_description_unref(op->base.local_media);
op->base.local_media=desc;
if (op->base.remote_media){
/*case of an incoming call where we modify the local capabilities between the time
* the call is ringing and it is accepted (for example if you want to accept without video*/
@ -597,7 +609,7 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){
static belle_sip_header_allow_t *create_allow(){
belle_sip_header_allow_t* header_allow;
header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO, UPDATE");
header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO, UPDATE");
return header_allow;
}
@ -609,8 +621,8 @@ static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer"));
}
if (op->base.local_media){
op->sdp_offering=TRUE;
set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),op->base.local_media);
op->sdp_offering=TRUE;
set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),op->base.local_media);
}else op->sdp_offering=FALSE;
return;
}
@ -633,7 +645,7 @@ int sal_call(SalOp *op, const char *from, const char *to){
}
if (op->referred_by)
belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->referred_by));
return sal_op_send_request(op,invite);
}
@ -679,7 +691,7 @@ int sal_call_notify_ringing(SalOp *op, bool_t early_media){
belle_sip_response_t* ringing_response = sal_op_create_response_from_request(op,req,status_code);
belle_sip_header_t *require;
const char *tags=NULL;
if (early_media){
handle_offer_answer_response(op,ringing_response);
}
@ -692,7 +704,7 @@ int sal_call_notify_ringing(SalOp *op, bool_t early_media){
}
#ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING
if (tags && strstr(tags,"100rel")!=0)
if (tags && strstr(tags,"100rel")!=0)
#endif
{
belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op);
@ -740,7 +752,7 @@ int sal_call_accept(SalOp*h){
if ((contact_header=sal_op_create_contact(h))) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header));
}
_sal_op_add_custom_headers(h, BELLE_SIP_MESSAGE(response));
handle_offer_answer_response(h,response);
@ -757,7 +769,7 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti
belle_sip_response_t* response;
belle_sip_header_contact_t* contact=NULL;
int status=sal_reason_to_sip_code(reason);
if (reason==SalReasonRedirect){
if (redirection!=NULL) {
if (strstr(redirection,"sip:")!=0) status=302;
@ -812,7 +824,7 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){
if (req){
int bodylen;
char dtmf_body[128]={0};
snprintf(dtmf_body, sizeof(dtmf_body)-1, "Signal=%c\r\nDuration=250\r\n", dtmf);
bodylen=strlen(dtmf_body);
belle_sip_message_set_body((belle_sip_message_t*)req,dtmf_body,bodylen);

View file

@ -90,19 +90,19 @@ SalAuthInfo * sal_op_get_auth_requested(SalOp *op){
belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){
belle_sip_header_contact_t* contact_header;
belle_sip_uri_t* contact_uri;
if (sal_op_get_contact_address(op)) {
contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op)));
} else {
contact_header= belle_sip_header_contact_new();
}
if (!(contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header)))) {
/*no uri, just creating a new one*/
contact_uri=belle_sip_uri_new();
belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact_header),contact_uri);
}
belle_sip_uri_set_secure(contact_uri,sal_op_is_secure(op));
if (op->privacy!=SalPrivacyNone){
belle_sip_uri_set_user(contact_uri,NULL);
@ -122,15 +122,38 @@ belle_sip_header_t * sal_make_supported_header(Sal *sal){
return belle_sip_header_create("Supported","replaces, outbound");
}
static void add_initial_route_set(belle_sip_request_t *request, const MSList *list){
const MSList *elem;
for (elem=list;elem!=NULL;elem=elem->next){
SalAddress *addr=(SalAddress*)elem->data;
belle_sip_header_route_t *route;
belle_sip_uri_t *uri;
/*Optimization: if the initial route set only contains one URI which is the same as the request URI, ommit it*/
if (elem==list && list->next==NULL){
belle_sip_uri_t *requri=belle_sip_request_get_uri(request);
/*skip the first route it is the same as the request uri*/
if (strcmp(sal_address_get_domain(addr),belle_sip_uri_get_host(requri))==0 ){
ms_message("Skipping top route of initial route-set because same as request-uri.");
continue;
}
}
route=belle_sip_header_route_create((belle_sip_header_address_t*)addr);
uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)route);
belle_sip_uri_set_lr_param(uri,1);
belle_sip_message_add_header((belle_sip_message_t*)request,(belle_sip_header_t*)route);
}
}
belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) {
belle_sip_header_from_t* from_header;
belle_sip_header_to_t* to_header;
belle_sip_provider_t* prov=op->base.root->prov;
belle_sip_request_t *req;
belle_sip_uri_t* req_uri;
const MSList *elem=sal_op_get_route_addresses(op);
char token[10];
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)));
@ -157,6 +180,11 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) {
belle_sip_header_p_preferred_identity_t* p_preferred_identity=belle_sip_header_p_preferred_identity_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(p_preferred_identity));
}
if (elem && strcmp(method,"REGISTER")!=0 && !op->base.root->no_initial_route){
add_initial_route_set(req,elem);
}
if (strcmp("REGISTER",method)!=0 && op->privacy!=SalPrivacyNone ){
belle_sip_header_privacy_t* privacy_header=belle_sip_header_privacy_new();
if (op->privacy&SalPrivacyCritical)
@ -213,7 +241,7 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) {
}
static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *msg){
if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){
belle_sip_header_contact_t* newct;
/*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/
@ -224,7 +252,7 @@ static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *m
}
/*if a header already exists in the message, replace it*/
belle_sip_message_set_header(msg,h);
}
void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){
@ -246,20 +274,20 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req
belle_sip_header_contact_t* contact;
int result =-1;
belle_sip_uri_t *next_hop_uri=NULL;
if (add_contact) {
contact = sal_op_create_contact(op);
belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact));
}
_sal_op_add_custom_headers(op, (belle_sip_message_t*)request);
if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) {
/*don't put route header if dialog is in confirmed state*/
const MSList *elem=sal_op_get_route_addresses(op);
const char *transport;
const char *method=belle_sip_request_get_method(request);
if (elem) {
outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data);
next_hop_uri=outbound_proxy;
@ -284,7 +312,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req
}
}
}
if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport &&
if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport &&
(strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){
/*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/
belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t);
@ -307,12 +335,12 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req
belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL);
}
result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/);
/*update call id if not set yet for this OP*/
if (result == 0 && !op->base.call_id) {
op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_call_id_t))));
}
return result;
}
@ -323,9 +351,9 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) {
return -1; /*sanity check*/
}
/*
Header field where proxy ACK BYE CAN INV OPT REG
___________________________________________________________
Contact R o - - m o o
Header field where proxy ACK BYE CAN INV OPT REG
___________________________________________________________
Contact R o - - m o o
*/
if (strcmp(belle_sip_request_get_method(request),"INVITE")==0
||strcmp(belle_sip_request_get_method(request),"REGISTER")==0
@ -415,7 +443,7 @@ SalReason sal_reason_to_sip_code(SalReason r){
SalReason _sal_reason_from_sip_code(int code) {
if (code>=100 && code<300) return SalReasonNone;
switch(code) {
case 0:
return SalReasonIOError;
@ -490,7 +518,7 @@ void sal_error_info_reset(SalErrorInfo *ei){
if (ei->warnings){
ms_free(ei->warnings);
ei->warnings=NULL;
}
if (ei->full_string){
ms_free(ei->full_string);
@ -522,7 +550,7 @@ void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *respon
belle_sip_header_t *warning=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Warning");
SalErrorInfo *ei=&op->error_info;
const char *warnings;
warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL;
if (warnings==NULL) warnings=reason_header ? belle_sip_header_get_unparsed_value(reason_header) : NULL;
sal_error_info_set(ei,SalReasonUnknown,code,reason_phrase,warnings);
@ -618,7 +646,7 @@ void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){
}
const char *sal_op_get_remote_contact(const SalOp *op){
/*
/*
* remote contact is filled in process_response
* return sal_custom_header_find(op->base.recv_custom_headers,"Contact");
*/
@ -649,16 +677,16 @@ bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody){
belle_sip_header_content_type_t *content_type;
belle_sip_header_content_length_t *clen=NULL;
belle_sip_header_t *content_encoding;
content_type=belle_sip_message_get_header_by_type(msg,belle_sip_header_content_type_t);
if (content_type){
body=belle_sip_message_get_body(msg);
clen=belle_sip_message_get_header_by_type(msg,belle_sip_header_content_length_t);
}
content_encoding=belle_sip_message_get_header(msg,"Content-encoding");
memset(salbody,0,sizeof(SalBody));
if (content_type && body && clen) {
salbody->type=belle_sip_header_content_type_get_type(content_type);
salbody->subtype=belle_sip_header_content_type_get_subtype(content_type);
@ -693,7 +721,7 @@ bool_t sal_op_is_ipv6(SalOp *op){
belle_sip_transaction_t *tr=NULL;
belle_sip_header_address_t *contact;
belle_sip_request_t *req;
if (op->refresher)
tr=(belle_sip_transaction_t *)belle_sip_refresher_get_transaction(op->refresher);
@ -701,7 +729,7 @@ bool_t sal_op_is_ipv6(SalOp *op){
tr=(belle_sip_transaction_t *)op->pending_client_trans;
if (tr==NULL)
tr=(belle_sip_transaction_t *)op->pending_server_trans;
if (tr==NULL){
ms_error("Unable to determine IP version from signaling operation.");
return FALSE;

View file

@ -164,6 +164,8 @@ static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_req
return NULL;
if (belle_sip_header_content_length_get_content_length(content_length) == 0)
return NULL;
if (body==NULL) return NULL;
op->base.root->callbacks.parse_presence_requested(op,
belle_sip_header_content_type_get_type(content_type),
@ -175,7 +177,7 @@ static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_req
}
static void handle_notify(SalOp *op, belle_sip_request_t *req){
belle_sip_response_t* resp;
belle_sip_response_t* resp=NULL;
belle_sip_server_transaction_t* server_transaction=op->pending_server_trans;
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t);
SalSubscribeStatus sub_state;
@ -183,30 +185,24 @@ static void handle_notify(SalOp *op, belle_sip_request_t *req){
if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) {
SalPresenceModel *presence_model = NULL;
const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
if (body==NULL){
ms_error("No body in NOTIFY received from [%s]",sal_op_get_from(op));
resp = sal_op_create_response_from_request(op, req, 415);
belle_sip_server_transaction_send_response(server_transaction,resp);
return;
if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) {
sub_state=SalSubscribeTerminated;
ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op));
} else {
sub_state=SalSubscribeActive;
}
presence_model = process_presence_notification(op, req);
if (presence_model != NULL) {
if (presence_model != NULL || body==NULL) {
/* Presence notification body parsed successfully. */
if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) {
sub_state=SalSubscribeTerminated;
ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op));
} else {
sub_state=SalSubscribeActive;
}
resp = sal_op_create_response_from_request(op, req, 200); /*create first because the op may be destroyed by notify_presence */
op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL);
} else {
} else if (body){
/* Formatting error in presence notification body. */
ms_error("Wrongly formatted presence notification received");
resp = sal_op_create_response_from_request(op, req, 400);
ms_warning("Wrongly formatted presence document.");
resp = sal_op_create_response_from_request(op, req, 488);
}
belle_sip_server_transaction_send_response(server_transaction,resp);
if (resp) belle_sip_server_transaction_send_response(server_transaction,resp);
}
}

View file

@ -32,6 +32,7 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher
/*only take first one for now*/
op->auth_info=sal_auth_info_create((belle_sip_auth_event_t*)(belle_sip_refresher_get_auth_events(refresher)->data));
}
sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL);
if(status_code == 200) {
/*check service route rfc3608*/
belle_sip_header_service_route_t* service_route;
@ -41,7 +42,7 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher
}
sal_op_set_service_route(op,(const SalAddress*)service_route_address);
if (service_route_address) belle_sip_object_unref(service_route_address);
sal_remove_pending_auth(op->base.root,op); /*just in case*/
op->base.root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->refresher)>0);
} else if (status_code>=400) {
@ -55,7 +56,6 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher
chooses not to re-register, the UA SHOULD discard any stored service
route for that address-of-record. */
sal_op_set_service_route(op,NULL);
sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL);
op->base.root->callbacks.register_failure(op);
if (op->auth_info) {
/*add pending auth*/

View file

@ -117,7 +117,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
mime_param= belle_sdp_mime_parameter_create ( pt->mime_type
, payload_type_get_number ( pt )
, pt->clock_rate
,stream->type==SalAudio?1:-1 );
, pt->channels>0 ? pt->channels : -1 );
belle_sdp_mime_parameter_set_parameters ( mime_param,pt->recv_fmtp );
if ( stream->ptime>0 ) {
belle_sdp_mime_parameter_set_ptime ( mime_param,stream->ptime );
@ -149,22 +149,22 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
const char *enc_name=NULL;
switch ( stream->crypto[j].algo ) {
case AES_128_SHA1_80:
case MS_AES_128_SHA1_80:
enc_name="AES_CM_128_HMAC_SHA1_80";
break;
case AES_128_SHA1_32:
case MS_AES_128_SHA1_32:
enc_name="AES_CM_128_HMAC_SHA1_32";
break;
case AES_256_SHA1_32:
case MS_AES_256_SHA1_32:
enc_name="AES_CM_256_HMAC_SHA1_32";
break;
case AES_256_SHA1_80:
case MS_AES_256_SHA1_80:
enc_name="AES_CM_256_HMAC_SHA1_32";
break;
case AES_128_NO_AUTH:
case MS_AES_128_NO_AUTH:
ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" );
break;
case NO_CIPHER_SHA1_80:
case MS_NO_CIPHER_SHA1_80:
ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" );
break;
default:
@ -351,13 +351,13 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med
tmp2 );
if ( nb == 3 ) {
if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ){
stream->crypto[valid_count].algo = AES_128_SHA1_80;
stream->crypto[valid_count].algo = MS_AES_128_SHA1_80;
}else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 ){
stream->crypto[valid_count].algo = AES_128_SHA1_32;
stream->crypto[valid_count].algo = MS_AES_128_SHA1_32;
}else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_32",tmp ) == 0 ){
stream->crypto[valid_count].algo = AES_256_SHA1_32;
stream->crypto[valid_count].algo = MS_AES_256_SHA1_32;
}else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_80",tmp ) == 0 ){
stream->crypto[valid_count].algo = AES_256_SHA1_80;
stream->crypto[valid_count].algo = MS_AES_256_SHA1_80;
}else {
ms_warning ( "Failed to parse crypto-algo: '%s'", tmp );
stream->crypto[valid_count].algo = 0;

View file

@ -1075,7 +1075,7 @@ static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, cons
if (lev==NULL) {
/*out of subscribe notify */
lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionOutgoing,eventname);
lev=linphone_event_new_with_out_of_dialog_op(lc,op,LinphoneSubscriptionOutgoing,eventname);
}
if (lc->vtable.notify_received){
const LinphoneContent *ct=linphone_content_from_sal_body(&content,body);

View file

@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphonecore.h"
#include "private.h"
#include "lpconfig.h"
@ -114,7 +114,7 @@ bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *f
LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const char* to) {
LinphoneAddress *to_addr=linphone_core_interpret_url(lc,to);
LinphoneChatRoom *ret;
if (to_addr==NULL){
ms_error("linphone_core_get_or_create_chat_room(): Cannot make a valid address with %s",to);
return NULL;
@ -174,7 +174,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
char* content_type;
const char *identity=NULL;
time_t t=time(NULL);
if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){
if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
if (call->state==LinphoneCallConnected ||
@ -271,7 +271,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
char *cleanfrom;
LinphoneChatMessage* msg;
const SalCustomHeader *ch;
addr=linphone_address_new(sal_msg->from);
linphone_address_clean(addr);
cr=linphone_core_get_chat_room(lc,addr);
@ -284,20 +284,20 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
msg = linphone_chat_room_create_message(cr, sal_msg->text);
linphone_chat_message_set_from(msg, cr->peer_url);
{
LinphoneAddress *to;
to=sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) : linphone_address_new(linphone_core_get_identity(lc));
msg->to=to;
}
msg->time=sal_msg->time;
msg->state=LinphoneChatMessageStateDelivered;
msg->is_read=FALSE;
msg->dir=LinphoneChatMessageIncoming;
ch=sal_op_get_recv_custom_header(op);
if (ch) msg->custom_headers=sal_custom_header_clone(ch);
if (sal_msg->url) {
linphone_chat_message_set_external_body_url(msg, sal_msg->url);
}
@ -442,8 +442,8 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con
* @return a new #LinphoneChatMessage
*/
LinphoneChatMessage* linphone_chat_room_create_message_2(
LinphoneChatRoom *cr, const char* message, const char* external_body_url,
LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming) {
LinphoneChatRoom *cr, const char* message, const char* external_body_url,
LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming) {
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage);
@ -610,13 +610,13 @@ void linphone_chat_room_compose(LinphoneChatRoom *cr) {
*/
const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state) {
switch (state) {
case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle";
case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle";
case LinphoneChatMessageStateInProgress:return "LinphoneChatMessageStateInProgress";
case LinphoneChatMessageStateDelivered:return "LinphoneChatMessageStateDelivered";
case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered";
default: return "Unknown state";
}
}
/**
@ -658,8 +658,8 @@ const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessag
/**
* Linphone message can carry external body as defined by rfc2017
*
* @param message a LinphoneChatMessage
*
* @param message a LinphoneChatMessage
* @param url ex: access-type=URL; URL="http://www.foo.com/file"
*/
void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url) {
@ -680,7 +680,7 @@ void linphone_chat_message_set_from(LinphoneChatMessage* message, const Linphone
}
/**
* Get origin of the message
* Get origin of the message
*@param message #LinphoneChatMessage obj
*@return #LinphoneAddress
*/
@ -699,7 +699,7 @@ void linphone_chat_message_set_to(LinphoneChatMessage* message, const LinphoneAd
}
/**
* Get destination of the message
* Get destination of the message
*@param message #LinphoneChatMessage obj
*@return #LinphoneAddress
*/
@ -785,7 +785,7 @@ bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message) {
* @return the id
*/
unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message) {
return message->storage_id;
return message->storage_id;
}
/**

View file

@ -74,17 +74,17 @@ LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir,
return lev;
}
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name){
static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name, bool_t is_out_of_dialog){
LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, op);
if (dir==LinphoneSubscriptionIncoming){
lev->resource_addr=linphone_address_clone((LinphoneAddress*)sal_op_get_to_address(op));
lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op));
}else{
lev->resource_addr=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(op));
}
lev->is_out_of_dialog_op=is_out_of_dialog;
return lev;
}
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) {
return linphone_event_new_with_op_base(lc,op,dir,name,FALSE);
}
LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) {
return linphone_event_new_with_op_base(lc,op,dir,name,TRUE);
}
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){
LinphoneCore *lc=lev->lc;
if (lev->subscription_state!=state){
@ -129,8 +129,6 @@ LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAd
LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event, expires);
linphone_configure_op(lc,lev->op,resource,NULL,TRUE);
sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1));
lev->resource_addr=linphone_address_clone(resource);
lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op));
return lev;
}
@ -318,8 +316,6 @@ static void linphone_event_destroy(LinphoneEvent *lev){
if (lev->op)
sal_op_release(lev->op);
ms_free(lev->name);
if (lev->resource_addr) linphone_address_destroy(lev->resource_addr);
if (lev->from) linphone_address_destroy(lev->from);
ms_free(lev);
}
@ -341,11 +337,19 @@ const char *linphone_event_get_name(const LinphoneEvent *lev){
}
const LinphoneAddress *linphone_event_get_from(const LinphoneEvent *lev){
return lev->from;
if (lev->is_out_of_dialog_op){
return (LinphoneAddress*)sal_op_get_to_address(lev->op);
}else{
return (LinphoneAddress*)sal_op_get_from_address(lev->op);
}
}
const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){
return lev->resource_addr;
if (lev->is_out_of_dialog_op){
return (LinphoneAddress*)sal_op_get_from_address(lev->op);
}else{
return (LinphoneAddress*)sal_op_get_to_address(lev->op);
}
}
LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev){

View file

@ -62,8 +62,8 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
case LinphoneStatusPending:
str=_("Pending");
break;
case LinphoneStatusVacation:
str=_("Vacation");
case LinphoneStatusVacation:
str=_("Vacation");
default:
str=_("Unknown-bug");
}
@ -109,7 +109,7 @@ LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){
void __linphone_friend_do_subscribe(LinphoneFriend *fr){
LinphoneCore *lc=fr->lc;
if (fr->outsub==NULL){
/* people for which we don't have yet an answer should appear as offline */
fr->presence=NULL;
@ -132,7 +132,7 @@ LinphoneFriend * linphone_friend_new(){
obj->pol=LinphoneSPAccept;
obj->presence=NULL;
obj->subscribe=TRUE;
return obj;
return obj;
}
LinphoneFriend *linphone_friend_new_with_address(const char *addr){
@ -244,9 +244,17 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){
static void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
if (lf->outsub!=NULL) {
LinphoneCore *lc=lf->lc;
sal_op_release(lf->outsub);
lf->outsub=NULL;
lf->subscribe_active=FALSE;
/*notify application that we no longer know the presence activity */
if (lf->presence != NULL) {
linphone_presence_model_unref(lf->presence);
}
lf->presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,"unknown activity");
if (lc->vtable.notify_presence_received)
lc->vtable.notify_presence_received(lc,lf);
}
lf->initial_subscribes_sent=FALSE;
}
@ -255,7 +263,7 @@ void linphone_friend_close_subscriptions(LinphoneFriend *lf){
linphone_friend_unsubscribe(lf);
if (lf->insub){
sal_notify_presence_close(lf->insub);
}
}
@ -388,7 +396,7 @@ BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){
**/
void linphone_friend_update_subscribes(LinphoneFriend *fr, LinphoneProxyConfig *proxy, bool_t only_when_registered){
int can_subscribe=1;
if (only_when_registered && (fr->subscribe || fr->subscribe_active)){
LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(fr->lc,fr->uri);
if (proxy && proxy!=cfg) return;
@ -592,13 +600,13 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde
int a;
LinphoneFriend *lf;
LpConfig *config=lc->config;
sprintf(item,"friend_%i",index);
if (!lp_config_has_section(config,item)){
return NULL;
}
tmp=lp_config_get_string(config,item,"url",NULL);
if (tmp==NULL) {
return NULL;
@ -614,7 +622,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde
}
a=lp_config_get_int(config,item,"subscribe",0);
linphone_friend_send_subscribe(lf,a);
linphone_friend_set_ref_key(lf,lp_config_get_string(config,item,"refkey",NULL));
return lf;
}
@ -639,9 +647,9 @@ void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf,
char key[50];
char *tmp;
const char *refkey;
sprintf(key,"friend_%i",index);
if (lf==NULL){
lp_config_clean_section(config,key);
return;

View file

@ -46,7 +46,7 @@ void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig
}
const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){
return NULL;
return NULL;
}
void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){
@ -56,7 +56,7 @@ void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){
}
bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){
return FALSE;
return FALSE;
}
bool_t linphone_tunnel_connected(LinphoneTunnel *tunnel){

View file

@ -95,25 +95,24 @@ bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
}
static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
// Check ZRTP encryption in audiostream
if (!call->audiostream_encrypted) {
return FALSE;
}
#ifdef VIDEO_ENABLED
// If video enabled, check ZRTP encryption in videostream
{
const LinphoneCallParams *params=linphone_call_get_current_params(call);
if (params->has_video && !call->videostream_encrypted) {
return FALSE;
int number_of_encrypted_stream = 0;
int number_of_active_stream = 0;
if (call) {
if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
number_of_active_stream++;
if(media_stream_is_secured((MediaStream *)call->audiostream))
number_of_encrypted_stream++;
}
if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
number_of_active_stream++;
if (media_stream_is_secured((MediaStream *)call->videostream))
number_of_encrypted_stream++;
}
}
#endif
return TRUE;
return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream;
}
void propagate_encryption_changed(LinphoneCall *call){
static void propagate_encryption_changed(LinphoneCall *call){
LinphoneCore *lc=call->core;
if (!linphone_call_are_all_streams_encrypted(call)) {
ms_message("Some streams are not encrypted");
@ -128,23 +127,11 @@ void propagate_encryption_changed(LinphoneCall *call){
}
}
#ifdef VIDEO_ENABLED
static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){
LinphoneCall *call = (LinphoneCall *)data;
ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted");
call->videostream_encrypted=encrypted;
propagate_encryption_changed(call);
}
#endif
static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
char status[255]={0};
LinphoneCall *call;
ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted");
call = (LinphoneCall *)data;
call->audiostream_encrypted=encrypted;
if (encrypted && call->core->vtable.display_status != NULL) {
snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
@ -248,7 +235,7 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){
LinphoneCore *lc=call->core;
int i;
SalMediaDescription *old_md=call->localdesc;
bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1);
for(i=0; i<md->n_active_streams; i++) {
if (md->streams[i].proto == SalProtoRtpSavp) {
@ -260,11 +247,11 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){
}
}else{
md->streams[i].crypto[0].tag = 1;
md->streams[i].crypto[0].algo = AES_128_SHA1_80;
md->streams[i].crypto[0].algo = MS_AES_128_SHA1_80;
if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key, SAL_SRTP_KEY_SIZE))
md->streams[i].crypto[0].algo = 0;
md->streams[i].crypto[1].tag = 2;
md->streams[i].crypto[1].algo = AES_128_SHA1_32;
md->streams[i].crypto[1].algo = MS_AES_128_SHA1_32;
if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key, SAL_SRTP_KEY_SIZE))
md->streams[i].crypto[1].algo = 0;
md->streams[i].crypto[2].algo = 0;
@ -399,7 +386,7 @@ static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){
int tried_port;
int existing_port;
bool_t already_used=FALSE;
for(offset=0;offset<100;offset+=2){
tried_port=base_port+offset;
already_used=FALSE;
@ -482,13 +469,14 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
call->log=linphone_call_log_new(call, from, to);
call->owns_call_log=TRUE;
call->camera_enabled=TRUE;
call->current_params.media_encryption=LinphoneMediaEncryptionNone;
linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
port_config_set(call,0,min_port,max_port);
linphone_core_get_video_port_range(call->core, &min_port, &max_port);
port_config_set(call,1,min_port,max_port);
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
}
@ -648,14 +636,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
linphone_call_init_media_streams(call);
switch (linphone_core_get_firewall_policy(call->core)) {
case LinphonePolicyUseIce:
/*start ICE gathering*/
linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
linphone_call_start_media_streams_for_ice_gathering(call);
if (linphone_core_gather_ice_candidates(call->core,call)<0) {
/* Ice candidates gathering failed, proceed with the call anyway. */
linphone_call_delete_ice_session(call);
linphone_call_stop_media_streams_for_ice_gathering(call);
}
linphone_call_prepare_ice(call,TRUE);
break;
case LinphonePolicyUseStun:
call->ping_time=linphone_core_run_stun_tests(call->core,call);
@ -780,7 +761,6 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
return;
}
}
ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
linphone_call_state_to_string(cstate));
@ -789,6 +769,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
Indeed it does not change the state of the call (still paused or running)*/
call->state=cstate;
}
if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
switch(call->non_op_error.reason){
case SalReasonDeclined:
@ -807,8 +788,18 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
call->media_start_time=time(NULL);
}
if (cstate == LinphoneCallStreamsRunning) {
linphone_reporting_update_ip(call);
}
if (lc->vtable.call_state_changed)
lc->vtable.call_state_changed(lc,call,cstate,message);
if (cstate==LinphoneCallEnd){
if (call->log->status == LinphoneCallSuccess)
linphone_reporting_publish(call);
}
if (cstate==LinphoneCallReleased){
if (call->op!=NULL) {
/*transfer the last error so that it can be obtained even in Released state*/
@ -923,6 +914,16 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
}
#endif
if (linphone_call_are_all_streams_encrypted(call)) {
if (linphone_call_get_authentication_token(call)) {
call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
} else {
call->current_params.media_encryption=LinphoneMediaEncryptionSRTP;
}
} else {
call->current_params.media_encryption=LinphoneMediaEncryptionNone;
}
return &call->current_params;
}
@ -1303,7 +1304,7 @@ const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp){
/**
* Set the session name of the media session (ie in SDP). Subject from the SIP message (which is different) can be set using linphone_call_params_set_custom_header().
* @param cp the call parameters.
* @param name the session name
* @param name the session name
**/
void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *name){
if (cp->session_name){
@ -1403,7 +1404,10 @@ static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const u
switch (event_id) {
case MS_VIDEO_DECODER_DECODING_ERRORS:
ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
linphone_call_send_vfu_request(call);
if (call->videostream && (video_stream_is_decoding_error_to_be_reported(call->videostream, 5000) == TRUE)) {
video_stream_decoding_error_reported(call->videostream);
linphone_call_send_vfu_request(call);
}
break;
case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
ms_message("First video frame decoded successfully");
@ -1431,6 +1435,60 @@ static void port_config_set_random_choosed(LinphoneCall *call, int stream_index,
call->media_ports[stream_index].rtcp_port=rtp_session_get_local_rtcp_port(session);
}
static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream_index, bool_t create_checklist){
MediaStream *ms=stream_index == 0 ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream;
if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
IceCheckList *cl;
rtp_session_set_pktinfo(ms->sessions.rtp_session, TRUE);
rtp_session_set_symmetric_rtp(ms->sessions.rtp_session, FALSE);
cl=ice_session_check_list(call->ice_session, stream_index);
if (cl == NULL && create_checklist) {
cl=ice_check_list_new();
ice_session_add_check_list(call->ice_session, cl);
ms_message("Created new ICE check list for stream [%i]",stream_index);
}
if (cl){
ms->ice_check_list = cl;
ice_check_list_set_rtp_session(ms->ice_check_list, ms->sessions.rtp_session);
}
}
}
int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
SalMediaDescription *remote = NULL;
bool_t has_video=FALSE;
if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
if (incoming_offer){
remote=sal_call_get_remote_media_description(call->op);
has_video=linphone_core_media_description_contains_video_stream(remote);
}else has_video=call->params.has_video;
_linphone_call_prepare_ice_for_stream(call,0,TRUE);
if (has_video) _linphone_call_prepare_ice_for_stream(call,1,TRUE);
/*start ICE gathering*/
if (incoming_offer)
linphone_core_update_ice_from_remote_media_description(call,remote); /*this may delete the ice session*/
if (call->ice_session && !ice_session_candidates_gathered(call->ice_session)){
if (call->audiostream->ms.state==MSStreamInitialized)
audio_stream_prepare_sound(call->audiostream, NULL, NULL);
#ifdef VIDEO_ENABLED
if (has_video && call->videostream && call->videostream->ms.state==MSStreamInitialized) {
video_stream_prepare_video(call->videostream);
}
#endif
if (linphone_core_gather_ice_candidates(call->core,call)<0) {
/* Ice candidates gathering failed, proceed with the call anyway. */
linphone_call_delete_ice_session(call);
linphone_call_stop_media_streams_for_ice_gathering(call);
return -1;
}
return 1;/*gathering in progress, wait*/
}
}
return 0;
}
void linphone_call_init_audio_stream(LinphoneCall *call){
LinphoneCore *lc=call->core;
AudioStream *audiostream;
@ -1481,18 +1539,11 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port);
rtp_session_set_transports(audiostream->ms.sessions.rtp_session,artp,artcp);
}
if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
rtp_session_set_pktinfo(audiostream->ms.sessions.rtp_session, TRUE);
rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session, FALSE);
if (ice_session_check_list(call->ice_session, 0) == NULL) {
ice_session_add_check_list(call->ice_session, ice_check_list_new());
}
audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.sessions.rtp_session);
}
call->audiostream_app_evq = ortp_ev_queue_new();
rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq);
_linphone_call_prepare_ice_for_stream(call,0,FALSE);
}
void linphone_call_init_video_stream(LinphoneCall *call){
@ -1503,7 +1554,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){
int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
int dscp=linphone_core_get_video_dscp(lc);
const char *display_filter=linphone_core_get_video_display_filter(lc);
if (call->sessions[1].rtp_session==NULL){
call->videostream=video_stream_new(call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port, call->af==AF_INET6);
}else{
@ -1527,23 +1578,11 @@ void linphone_call_init_video_stream(LinphoneCall *call){
}
call->videostream_app_evq = ortp_ev_queue_new();
rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq);
_linphone_call_prepare_ice_for_stream(call,1,FALSE);
#ifdef TEST_EXT_RENDERER
video_stream_set_render_callback(call->videostream,rendercb,NULL);
#endif
}
/*eventually re-create the ICE check list that may have been destroyed if the stream wasn't used recently*/
if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
rtp_session_set_pktinfo(call->videostream->ms.sessions.rtp_session, TRUE);
rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session, FALSE);
if (ice_session_check_list(call->ice_session, 1) == NULL) {
ice_session_add_check_list(call->ice_session, ice_check_list_new());
}
call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.sessions.rtp_session);
ms_message ("creating new ice video check list [%p] for session [%p]",call->videostream->ms.ice_check_list,call->videostream->ms.sessions.rtp_session);
}
#else
call->videostream=NULL;
#endif
@ -1657,17 +1696,65 @@ static void post_configure_audio_streams(LinphoneCall*call){
linphone_call_start_recording(call);
}
static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){
int remote_bw=0;
int upload_bw;
int total_upload_bw=linphone_core_get_upload_bandwidth(call->core);
const LinphoneCallParams *params=&call->params;
bool_t will_use_video=linphone_core_media_description_contains_video_stream(md);
bool_t forced=FALSE;
if (desc->bandwidth>0) remote_bw=desc->bandwidth;
else if (md->bandwidth>0) {
/*case where b=AS is given globally, not per stream*/
remote_bw=md->bandwidth;
}
if (params->up_bw>0){
forced=TRUE;
upload_bw=params->up_bw;
}else upload_bw=total_upload_bw;
upload_bw=get_min_bandwidth(upload_bw,remote_bw);
if (!will_use_video || forced) return upload_bw;
if (bandwidth_is_greater(upload_bw,512)){
upload_bw=100;
}else if (bandwidth_is_greater(upload_bw,256)){
upload_bw=64;
}else if (bandwidth_is_greater(upload_bw,128)){
upload_bw=40;
}else if (bandwidth_is_greater(upload_bw,0)){
upload_bw=24;
}
return upload_bw;
}
static int get_video_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){
int remote_bw=0;
int bw;
if (desc->bandwidth>0) remote_bw=desc->bandwidth;
else if (md->bandwidth>0) {
/*case where b=AS is given globally, not per stream*/
remote_bw=get_remaining_bandwidth_for_video(md->bandwidth,call->audio_bw);
}
bw=get_min_bandwidth(get_remaining_bandwidth_for_video(linphone_core_get_upload_bandwidth(call->core),call->audio_bw),remote_bw);
return bw;
}
static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
int bw=0;
const MSList *elem;
RtpProfile *prof=rtp_profile_new("Call profile");
bool_t first=TRUE;
int remote_bw=0;
LinphoneCore *lc=call->core;
int up_ptime=0;
const LinphoneCallParams *params=&call->params;
*used_pt=-1;
if (desc->type==SalAudio)
bw=get_ideal_audio_bw(call,md,desc);
else if (desc->type==SalVideo)
bw=get_video_bw(call,md,desc);
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
PayloadType *pt=(PayloadType*)elem->data;
int number;
@ -1676,8 +1763,11 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m
pt=payload_type_clone(pt);
if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
/*first codec in list is the selected one*/
if (desc->type==SalAudio){
linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
/*this will update call->audio_bw*/
linphone_core_update_allocated_audio_bandwidth_in_call(call,pt,bw);
bw=call->audio_bw;
if (params->up_ptime)
up_ptime=params->up_ptime;
else up_ptime=linphone_core_get_upload_ptime(lc);
@ -1685,27 +1775,9 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m
*used_pt=payload_type_get_number(pt);
first=FALSE;
}
if (desc->bandwidth>0) remote_bw=desc->bandwidth;
else if (md->bandwidth>0) {
/*case where b=AS is given globally, not per stream*/
remote_bw=md->bandwidth;
if (desc->type==SalVideo){
remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
}
}
if (desc->type==SalAudio){
int audio_bw=call->audio_bw;
if (params->up_bw){
if (params->up_bw< audio_bw)
audio_bw=params->up_bw;
}
bw=get_min_bandwidth(audio_bw,remote_bw);
}else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
if (bw>0) pt->normal_bitrate=bw*1000;
else if (desc->type==SalAudio){
pt->normal_bitrate=-1;
}
if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){
pt->normal_bitrate=get_min_bandwidth(pt->normal_bitrate,bw*1000);
} else pt->normal_bitrate=bw*1000;
if (desc->ptime>0){
up_ptime=desc->ptime;
}
@ -1875,12 +1947,10 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
if (crypto_idx >= 0) {
media_stream_set_srtp_recv_key(&call->audiostream->ms,stream->crypto[0].algo,stream->crypto[0].master_key);
media_stream_set_srtp_send_key(&call->audiostream->ms,stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
call->audiostream_encrypted=TRUE;
} else {
ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
call->audiostream_encrypted=FALSE;
}
}else call->audiostream_encrypted=FALSE;
}
configure_rtp_session_for_rtcp_xr(lc, call, SalAudio);
audio_stream_start_full(
call->audiostream,
@ -1925,7 +1995,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
int used_pt=-1;
/* look for savp stream first */
const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpSavp,SalVideo);
@ -1947,8 +2017,9 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,vstream->proto,SalVideo);
call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
if (used_pt!=-1){
VideoStreamDir dir=VideoStreamSendRecv;
MSWebCam *cam=lc->video_conf.device;
@ -1994,14 +2065,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
if (!is_inactive){
if (vstream->proto == SalProtoRtpSavp) {
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag);
if (crypto_idx >= 0) {
media_stream_set_srtp_recv_key(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key);
media_stream_set_srtp_send_key(&call->videostream->ms,vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
call->videostream_encrypted=TRUE;
}else call->videostream_encrypted=FALSE;
}else{
call->videostream_encrypted=FALSE;
}
}
configure_rtp_session_for_rtcp_xr(lc, call, SalVideo);
@ -2062,13 +2129,19 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
OrtpZrtpParams params;
/*will be set later when zrtp is activated*/
call->current_params.media_encryption=LinphoneMediaEncryptionNone;
memset(&params,0,sizeof(OrtpZrtpParams));
/*call->current_params.media_encryption will be set later when zrtp is activated*/
params.zid_file=lc->zrtp_secrets_cache;
params.uri= linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->from : call->log->to);
audio_stream_enable_zrtp(call->audiostream,&params);
#if VIDEO_ENABLED
if (media_stream_is_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
/*audio stream is already encrypted and video stream is active*/
memset(&params,0,sizeof(OrtpZrtpParams));
video_stream_enable_zrtp(call->videostream,call->audiostream,&params);
}
#endif
}else{
call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
@ -2084,19 +2157,10 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
linphone_address_destroy(me);
}
void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
audio_stream_prepare_sound(call->audiostream, NULL, NULL);
#ifdef VIDEO_ENABLED
if (call->videostream) {
video_stream_prepare_video(call->videostream);
}
#endif
}
void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
audio_stream_unprepare_sound(call->audiostream);
if(call->audiostream && call->audiostream->ms.state==MSStreamPreparing) audio_stream_unprepare_sound(call->audiostream);
#ifdef VIDEO_ENABLED
if (call->videostream) {
if (call->videostream && call->videostream->ms.state==MSStreamPreparing) {
video_stream_unprepare_video(call->videostream);
}
#endif
@ -2121,14 +2185,13 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript
SalStreamDescription *old_stream;
SalStreamDescription *new_stream;
const SalStreamDescription *local_st_desc;
local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
if (call->audiostream && local_st_desc && old_stream && new_stream &&
update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->audiostream->ms)){
call->audiostream_encrypted = TRUE;
}else call->audiostream_encrypted = FALSE;
}
#ifdef VIDEO_ENABLED
local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
@ -2136,9 +2199,7 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript
new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
if (call->videostream && local_st_desc && old_stream && new_stream &&
update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->videostream->ms)){
call->videostream_encrypted = TRUE;
}
call->videostream_encrypted = FALSE;
#endif
}
@ -2183,6 +2244,7 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
void linphone_call_stop_audio_stream(LinphoneCall *call) {
if (call->audiostream!=NULL) {
linphone_reporting_update(call, LINPHONE_CALL_STATS_AUDIO);
media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[0]);
rtp_session_unregister_event_queue(call->audiostream->ms.sessions.rtp_session,call->audiostream_app_evq);
ortp_ev_queue_flush(call->audiostream_app_evq);
@ -2211,6 +2273,7 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) {
void linphone_call_stop_video_stream(LinphoneCall *call) {
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL){
linphone_reporting_update(call, LINPHONE_CALL_STATS_VIDEO);
media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[1]);
rtp_session_unregister_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq);
ortp_ev_queue_flush(call->videostream_app_evq);
@ -2620,11 +2683,17 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
int ping_time;
if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
LinphoneCallParams params;
_linphone_call_params_copy(&params,&call->current_params);
if (call->params.media_encryption == LinphoneMediaEncryptionZRTP) {
/* preserve media encryption param because at that time ZRTP negociation may still be ongoing*/
params.media_encryption=call->params.media_encryption;
}
switch (ice_session_state(call->ice_session)) {
case IS_Completed:
ice_session_select_candidates(call->ice_session);
if (ice_session_role(call->ice_session) == IR_Controlling) {
linphone_core_update_call(call->core, call, &call->current_params);
linphone_core_update_call(call->core, call, &params);
}
break;
case IS_Failed:
@ -2632,7 +2701,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
ice_session_select_candidates(call->ice_session);
if (ice_session_role(call->ice_session) == IR_Controlling) {
/* At least one ICE session has succeeded, so perform a call update. */
linphone_core_update_call(call->core, call, &call->current_params);
linphone_core_update_call(call->core, call, &params);
}
}
break;
@ -2673,8 +2742,10 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
break;
}
} else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
linphone_core_start_accept_call_update(call->core, call);
linphone_core_update_ice_state_in_call_stats(call);
if (call->state==LinphoneCallUpdatedByRemote){
linphone_core_start_accept_call_update(call->core, call);
linphone_core_update_ice_state_in_call_stats(call);
}
} else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
ice_session_restart(call->ice_session);
ice_session_set_role(call->ice_session, IR_Controlling);
@ -2682,8 +2753,92 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
}
}
/*do not change the prototype of this function, it is also used internally in linphone-daemon.*/
void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev){
OrtpEventType evt=ortp_event_get_type(ev);
OrtpEventData *evd=ortp_event_get_data(ev);
if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
stats->round_trip_delay = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session);
if(stats->received_rtcp != NULL)
freemsg(stats->received_rtcp);
stats->received_rtcp = evd->packet;
evd->packet = NULL;
stats->updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE;
update_local_stats(stats,ms);
} else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
memcpy(&stats->jitter_stats, rtp_session_get_jitter_stats(ms->sessions.rtp_session), sizeof(jitter_stats_t));
if (stats->sent_rtcp != NULL)
freemsg(stats->sent_rtcp);
stats->sent_rtcp = evd->packet;
evd->packet = NULL;
stats->updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE;
update_local_stats(stats,ms);
}
}
void linphone_call_notify_stats_updated(LinphoneCall *call, int stream_index){
LinphoneCallStats *stats=&call->stats[stream_index];
LinphoneCore *lc=call->core;
if (stats->updated){
linphone_reporting_call_stats_updated(call, stream_index);
if (lc->vtable.call_stats_updated)
lc->vtable.call_stats_updated(lc, call, stats);
stats->updated = 0;
}
}
void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){
MediaStream *ms=stream_index==0 ? (MediaStream *)call->audiostream : (MediaStream *)call->videostream; /*assumption to remove*/
OrtpEvQueue *evq;
OrtpEvent *ev;
if (ms==NULL) return;
/* Ensure there is no dangling ICE check list. */
if (call->ice_session == NULL) ms->ice_check_list = NULL;
switch(ms->type){
case AudioStreamType:
audio_stream_iterate((AudioStream*)ms);
break;
case VideoStreamType:
#ifdef VIDEO_ENABLED
video_stream_iterate((VideoStream*)ms);
#endif
break;
default:
ms_error("linphone_call_handle_stream_events(): unsupported stream type.");
return;
break;
}
/*yes the event queue has to be taken at each iteration, because ice events may perform operations re-creating the streams*/
while ((evq=stream_index==0 ? call->audiostream_app_evq : call->videostream_app_evq) && (NULL != (ev=ortp_ev_queue_get(evq)))){
OrtpEventType evt=ortp_event_get_type(ev);
OrtpEventData *evd=ortp_event_get_data(ev);
linphone_call_stats_fill(&call->stats[stream_index],ms,ev);
linphone_call_notify_stats_updated(call,stream_index);
if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
if (ms->type==AudioStreamType)
linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
else if (ms->type==VideoStreamType)
propagate_encryption_changed(call);
} else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
if (ms->type==AudioStreamType)
linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
} else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
|| (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
handle_ice_events(call, ev);
} else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
linphone_core_dtmf_received(call->core,evd->info.telephone_event);
}
ortp_event_destroy(ev);
}
}
void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
LinphoneCore* lc = call->core;
int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
bool_t disconnected=FALSE;
@ -2705,96 +2860,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
linphone_upnp_call_process(call);
#endif //BUILD_UPNP
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL) {
OrtpEvent *ev;
/* Ensure there is no dangling ICE check list. */
if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
// Beware that the application queue should not depend on treatments fron the
// mediastreamer queue.
video_stream_iterate(call->videostream);
while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
OrtpEventType evt=ortp_event_get_type(ev);
OrtpEventData *evd=ortp_event_get_data(ev);
if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
} else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.sessions.rtp_session);
if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
evd->packet = NULL;
call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE;
update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream);
if (lc->vtable.call_stats_updated)
lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
} else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.sessions.rtp_session), sizeof(jitter_stats_t));
if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
evd->packet = NULL;
call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE;
update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream);
if (lc->vtable.call_stats_updated)
lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
} else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
|| (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
handle_ice_events(call, ev);
}
ortp_event_destroy(ev);
}
}
#endif
if (call->audiostream!=NULL) {
OrtpEvent *ev;
/* Ensure there is no dangling ICE check list. */
if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
// Beware that the application queue should not depend on treatments fron the
// mediastreamer queue.
audio_stream_iterate(call->audiostream);
while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
OrtpEventType evt=ortp_event_get_type(ev);
OrtpEventData *evd=ortp_event_get_data(ev);
if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
} else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
} else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.sessions.rtp_session);
if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
evd->packet = NULL;
call->stats[LINPHONE_CALL_STATS_AUDIO].updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE;
update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream);
if (lc->vtable.call_stats_updated)
lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
} else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.sessions.rtp_session), sizeof(jitter_stats_t));
if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
evd->packet = NULL;
call->stats[LINPHONE_CALL_STATS_AUDIO].updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE;
update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream);
if (lc->vtable.call_stats_updated)
lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
} else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
|| (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
handle_ice_events(call, ev);
} else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
linphone_core_dtmf_received(lc,evd->info.telephone_event);
}
ortp_event_destroy(ev);
}
}
linphone_call_handle_stream_events(call,0);
linphone_call_handle_stream_events(call,1);
if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
if (disconnected)

View file

@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "sipsetup.h"
#include "lpconfig.h"
#include "private.h"
#include "quality_reporting.h"
#include <math.h>
#include <ortp/telephonyevents.h>
@ -127,6 +128,9 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *fro
cl->to=to;
cl->status=LinphoneCallAborted; /*default status*/
cl->quality=-1;
cl->reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new();
cl->reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new();
return cl;
}
@ -390,6 +394,9 @@ void linphone_call_log_destroy(LinphoneCallLog *cl){
if (cl->to!=NULL) linphone_address_destroy(cl->to);
if (cl->refkey!=NULL) ms_free(cl->refkey);
if (cl->call_id) ms_free(cl->call_id);
if (cl->reports[LINPHONE_CALL_STATS_AUDIO]!=NULL) linphone_reporting_destroy(cl->reports[LINPHONE_CALL_STATS_AUDIO]);
if (cl->reports[LINPHONE_CALL_STATS_VIDEO]!=NULL) linphone_reporting_destroy(cl->reports[LINPHONE_CALL_STATS_VIDEO]);
ms_free(cl);
}
@ -607,7 +614,7 @@ static void sound_config_read(LinphoneCore *lc)
linphone_core_set_play_file(lc,lp_config_get_string(lc->config,"sound","hold_music",PACKAGE_SOUND_DIR "/" HOLD_MUSIC));
lc->sound_conf.latency=0;
#ifndef __ios
#ifndef __ios
tmp=TRUE;
#else
tmp=FALSE; /* on iOS we have builtin echo cancellation.*/
@ -626,7 +633,7 @@ static void sound_config_read(LinphoneCore *lc)
/*just parse requested stream feature once at start to print out eventual errors*/
linphone_core_get_audio_features(lc);
_linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL);
}
@ -640,7 +647,7 @@ static void certificates_config_read(LinphoneCore *lc)
#endif
linphone_core_set_root_ca(lc,rootca);
linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE));
linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE));
linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE));
}
static void sip_config_read(LinphoneCore *lc)
@ -655,6 +662,7 @@ static void sip_config_read(LinphoneCore *lc)
sal_use_session_timers(lc->sal,200);
}
sal_use_no_initial_route(lc->sal,lp_config_get_int(lc->config,"sip","use_no_initial_route",0));
sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1));
ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1);
@ -663,17 +671,17 @@ static void sip_config_read(LinphoneCore *lc)
}
linphone_core_enable_ipv6(lc,ipv6);
memset(&tr,0,sizeof(tr));
tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",5060);
tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",5060);
/*we are not listening inbound connection for tls, port has no meaning*/
tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",LC_SIP_TRANSPORT_RANDOM);
certificates_config_read(lc);
/*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/
sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc));
/*start listening on ports*/
linphone_core_set_sip_transports(lc,&tr);
linphone_core_set_sip_transports(lc,&tr);
tmpstr=lp_config_get_string(lc->config,"sip","contact",NULL);
if (tmpstr==NULL || linphone_core_set_primary_contact(lc,tmpstr)==-1) {
@ -705,7 +713,7 @@ static void sip_config_read(LinphoneCore *lc)
tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0);
linphone_core_set_in_call_timeout(lc,tmp);
tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4);
linphone_core_set_delayed_timeout(lc,tmp);
@ -839,7 +847,7 @@ static bool_t get_codec(LinphoneCore *lc, const char* type, int index, PayloadTy
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 : "");
mime,rate,fmtp ? fmtp : "");
*ret=pt;
return TRUE;
}
@ -897,7 +905,7 @@ static MSList *add_missing_codecs(LinphoneCore *lc, SalStreamType mtype, MSList
if (mtype==SalVideo && pt->type!=PAYLOAD_VIDEO)
pt=NULL;
else if (mtype==SalAudio && (pt->type!=PAYLOAD_AUDIO_PACKETIZED
&& pt->type!=PAYLOAD_AUDIO_CONTINUOUS)){
&& pt->type!=PAYLOAD_AUDIO_CONTINUOUS)){
pt=NULL;
}
if (pt && ms_filter_codec_supported(pt->mime_type)){
@ -907,7 +915,7 @@ static MSList *add_missing_codecs(LinphoneCore *lc, SalStreamType mtype, MSList
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 : "");
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);
}
}
@ -977,8 +985,8 @@ static void video_config_read(LinphoneCore *lc){
int capture, display, self_view;
int automatic_video=1;
#endif
const char *str;
#ifdef VIDEO_ENABLED
const char *str;
#ifdef VIDEO_ENABLED
LinphoneVideoPolicy vpol;
memset(&vpol, 0, sizeof(LinphoneVideoPolicy));
#endif
@ -1041,7 +1049,7 @@ bool_t linphone_core_tunnel_available(void){
/**
* Enable adaptive rate control.
*
*
* @ingroup media_parameters
*
* Adaptive rate control consists in using RTCP feedback provided information to dynamically
@ -1055,7 +1063,7 @@ void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled
/**
* Returns whether adaptive rate control is enabled.
*
*
* @ingroup media_parameters
*
* See linphone_core_enable_adaptive_rate_control().
@ -1075,7 +1083,7 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){
* calls (within SDP messages) so that the remote end can have
* sufficient knowledge to properly configure its audio & video
* codec output bitrate to not overflow available bandwidth.
*
*
* @ingroup media_parameters
*
* @param lc the LinphoneCore object
@ -1161,7 +1169,7 @@ void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){
* Set audio packetization time linphone will send (in absence of requirement from peer)
* A value of 0 stands for the current codec default packetization time.
*
*
*
* @ingroup media_parameters
**/
int linphone_core_get_upload_ptime(LinphoneCore *lc){
@ -1182,14 +1190,7 @@ const char * linphone_core_get_version(void){
static void linphone_core_assign_payload_type(LinphoneCore *lc, PayloadType *const_pt, int number, const char *recv_fmtp){
PayloadType *pt;
#ifdef ANDROID
if (const_pt->channels==2){
ms_message("Stereo %s codec not supported on this platform.",const_pt->mime_type);
return;
}
#endif
pt=payload_type_clone(const_pt);
if (number==-1){
/*look for a free number */
@ -1253,10 +1254,10 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const
static void misc_config_read(LinphoneCore *lc) {
LpConfig *config=lc->config;
const char *uuid;
lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",15);
lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS);
uuid=lp_config_get_string(config,"misc","uuid",NULL);
if (!uuid){
char tmp[64];
@ -1292,12 +1293,12 @@ static void linphone_core_start(LinphoneCore * lc) {
void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message) {
if (lc->vtable.configuring_status)
lc->vtable.configuring_status(lc, state, message);
if (state == LinphoneConfiguringSuccessful) {
if (linphone_core_is_provisioning_transient(lc) == TRUE)
linphone_core_set_provisioning_uri(lc, NULL);
}
linphone_core_start(lc);
}
@ -1306,7 +1307,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
const char *remote_provisioning_uri = NULL;
ms_message("Initializing LinphoneCore %s", linphone_core_get_version());
memset (lc, 0, sizeof (LinphoneCore));
lc->config=config;
lc->config=lp_config_ref(config);
lc->data=userdata;
lc->ringstream_autorelease=TRUE;
@ -1344,7 +1345,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
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);
linphone_core_assign_payload_type(lc,&payload_type_x_snow,-1,NULL);
/* due to limited space in SDP, we have to disable this h264 line which is normally no more necessary */
@ -1371,10 +1372,10 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
linphone_core_assign_payload_type(lc,&payload_type_g729,18,"annexb=no");
linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5");
linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5");
linphone_core_assign_payload_type(lc,&payload_type_opus,-1,"useinbandfec=1; usedtx=0; cbr=1");
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();
/* create a mediastreamer2 event queue and set it as global */
/* This allows to run event's callback in linphone_core_iterate() */
@ -1386,15 +1387,15 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
sal_set_user_pointer(lc->sal,lc);
sal_set_callbacks(lc->sal,&linphone_sal_callbacks);
lc->network_last_check = 0;
lc->network_last_status = FALSE;
lc->network_last_check = 0;
lc->network_last_status = FALSE;
lc->http_provider = belle_sip_stack_create_http_provider(sal_get_belle_sip_stack(lc->sal), "0.0.0.0");
lc->http_verify_policy = belle_tls_verify_policy_new();
belle_http_provider_set_tls_verify_policy(lc->http_provider,lc->http_verify_policy);
certificates_config_read(lc);
remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
if (remote_provisioning_uri == NULL) {
linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL);
@ -1423,8 +1424,11 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
const char *config_path, const char *factory_config_path, void * userdata)
{
LinphoneCore *lc;
LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path);
return linphone_core_new_with_config(vtable, config, userdata);
lc=linphone_core_new_with_config(vtable, config, userdata);
lp_config_unref(config);
return lc;
}
LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata)
@ -1493,7 +1497,7 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact)
void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result){
const char *ip;
if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress
&& (ip=linphone_core_get_nat_address_resolved(lc))!=NULL){
&& (ip=linphone_core_get_nat_address_resolved(lc))!=NULL){
strncpy(result,ip,LINPHONE_IPADDR_SIZE);
return;
}
@ -1518,7 +1522,9 @@ void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result){
strncpy(result,"::1",LINPHONE_IPADDR_SIZE);
return;
}
}else af=AF_INET;
}
/*in all other cases use IPv4*/
af=AF_INET;
}
if (linphone_core_get_local_ip_for(af,NULL,result)==0)
return;
@ -1948,7 +1954,7 @@ static int apply_transports(LinphoneCore *lc){
/*first of all invalidate all current registrations so that we can register again with new transports*/
__linphone_core_invalidate_registers(lc);
if (lc->sip_conf.ipv6_enabled)
anyaddr="::0";
else
@ -1958,7 +1964,6 @@ static int apply_transports(LinphoneCore *lc){
if (tr->udp_port!=0){
if (sal_listen_port (sal,anyaddr,tr->udp_port,SalTransportUDP,FALSE)!=0){
transport_error(lc,"udp",tr->udp_port);
return -1;
}
}
if (tr->tcp_port!=0){
@ -1966,9 +1971,11 @@ static int apply_transports(LinphoneCore *lc){
transport_error(lc,"tcp",tr->tcp_port);
}
}
if (tr->tls_port!=0){
if (sal_listen_port (sal,anyaddr,tr->tls_port,SalTransportTLS,TRUE)!=0){
transport_error(lc,"tls",tr->tls_port);
if (linphone_core_sip_transport_supported(lc,LinphoneTransportTls)){
if (tr->tls_port!=0){
if (sal_listen_port (sal,anyaddr,tr->tls_port,SalTransportTLS,TRUE)!=0){
transport_error(lc,"tls",tr->tls_port);
}
}
}
apply_user_agent(lc);
@ -2092,23 +2099,32 @@ void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){
static void monitor_network_state(LinphoneCore *lc, time_t curtime){
char result[LINPHONE_IPADDR_SIZE];
bool_t new_status=lc->network_last_status;
char newip[LINPHONE_IPADDR_SIZE];
/* only do the network up checking every five seconds */
if (lc->network_last_check==0 || (curtime-lc->network_last_check)>=5){
linphone_core_get_local_ip(lc,AF_UNSPEC,result);
if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){
linphone_core_get_local_ip(lc,AF_UNSPEC,newip);
if (strcmp(newip,"::1")!=0 && strcmp(newip,"127.0.0.1")!=0){
new_status=TRUE;
}else new_status=FALSE;
lc->network_last_check=curtime;
}else new_status=FALSE; /*no network*/
if (new_status==lc->network_last_status && new_status==TRUE && strcmp(newip,lc->localip)!=0){
/*IP address change detected*/
ms_message("IP address change detected.");
set_network_reachable(lc,FALSE,curtime);
lc->network_last_status=FALSE;
}
strncpy(lc->localip,newip,sizeof(lc->localip));
if (new_status!=lc->network_last_status) {
if (new_status){
ms_message("New local ip address is %s",result);
ms_message("New local ip address is %s",lc->localip);
}
set_network_reachable(lc,new_status, curtime);
lc->network_last_status=new_status;
}
lc->network_last_check=curtime;
}
}
@ -2218,7 +2234,7 @@ void linphone_core_iterate(LinphoneCore *lc){
int elapsed;
bool_t one_second_elapsed=FALSE;
const char *remote_provisioning_uri = NULL;
if (linphone_core_get_global_state(lc) == LinphoneGlobalStartup) {
if (sal_get_root_ca(lc->sal)) {
belle_tls_verify_policy_t *tls_policy = belle_tls_verify_policy_new();
@ -2229,7 +2245,7 @@ void linphone_core_iterate(LinphoneCore *lc){
if (lc->vtable.display_status)
lc->vtable.display_status(lc, _("Configuring"));
linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring");
remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
if (remote_provisioning_uri) {
int err = linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri);
@ -2252,7 +2268,7 @@ void linphone_core_iterate(LinphoneCore *lc){
if (ecs==LinphoneEcCalibratorDone){
int len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
int margin=len/2;
lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-margin,0));
} else if (ecs == LinphoneEcCalibratorFailed) {
lp_config_set_int(lc->config, "sound", "ec_delay", -1);/*use default value from soundcard*/
@ -2272,7 +2288,7 @@ void linphone_core_iterate(LinphoneCore *lc){
}
if (lc->ringstream && lc->ringstream_autorelease && lc->dmfs_playing_start_time!=0
&& (curtime-lc->dmfs_playing_start_time)>5){
&& (curtime-lc->dmfs_playing_start_time)>5){
MSPlayerState state;
bool_t stop=TRUE;
if (lc->ringstream->source && ms_filter_call_method(lc->ringstream->source,MS_PLAYER_GET_STATE,&state)==0){
@ -2365,7 +2381,7 @@ void linphone_core_iterate(LinphoneCore *lc){
/**
* Interpret a call destination as supplied by the user, and returns a fully qualified
* LinphoneAddress.
*
*
* @ingroup call_control
*
* A sip address should look like DisplayName <sip:username@domain:port> .
@ -2384,7 +2400,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url)
LinphoneProxyConfig *proxy=lc->default_proxy;
char *tmpurl;
LinphoneAddress *uri;
if (*url=='\0') return NULL;
if (is_enum(url,&enum_domain)){
@ -2425,7 +2441,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url)
}
linphone_address_set_display_name(uri,NULL);
linphone_proxy_config_normalize_number(proxy,url,normalized_username,
sizeof(normalized_username));
sizeof(normalized_username));
linphone_address_set_username(uri,normalized_username);
return uri;
}else return NULL;
@ -2434,7 +2450,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url)
if (uri!=NULL){
return uri;
}
return NULL;
}
@ -2472,7 +2488,7 @@ const char * linphone_core_get_route(LinphoneCore *lc){
* Start a new call as a consequence of a transfer request received from a call.
* This function is for advanced usage: the execution of transfers is automatically managed by the LinphoneCore. However if an application
* wants to have control over the call parameters for the new call, it should call this function immediately during the LinphoneCallRefered notification.
* @see LinphoneCoreVTable::call_state_changed
* @see LinphoneCoreVTable::call_state_changed
* @param lc the LinphoneCore
* @param call a call that has just been notified about LinphoneCallRefered state event.
* @param params the call parameters to be applied to the new call.
@ -2481,13 +2497,13 @@ const char * linphone_core_get_route(LinphoneCore *lc){
LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
LinphoneCallParams *cp=params ? linphone_call_params_copy(params) : linphone_core_create_default_call_parameters(lc);
LinphoneCall *newcall;
if (call->state!=LinphoneCallPaused){
ms_message("Automatically pausing current call to accept transfer.");
_linphone_core_pause_call(lc,call);
call->was_automatically_paused=TRUE;
}
if (!params){
cp->has_video = call->current_params.has_video; /*start the call to refer-target with video enabled if original call had video*/
}
@ -2527,7 +2543,7 @@ void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, L
nodes with the basic SIP routing policy in order to get a workable
system.
*/
static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneAddress *dest){
MSList *ret=NULL;
const char *local_route=linphone_proxy_config_get_route(proxy);
@ -2822,7 +2838,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
bool_t defer = FALSE;
linphone_core_preempt_sound_resources(lc);
if(!linphone_core_can_we_add_call(lc)){
if (lc->vtable.display_warning)
lc->vtable.display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls"));
@ -2852,22 +2868,16 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
/* this call becomes now the current one*/
lc->current_call=call;
linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call");
call->log->start_date_time=time(NULL);
linphone_call_init_media_streams(call);
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
/* Defer the start of the call after the ICE gathering process. */
linphone_call_start_media_streams_for_ice_gathering(call);
call->log->start_date_time=time(NULL);
if (linphone_core_gather_ice_candidates(lc,call)<0) {
/* Ice candidates gathering failed, proceed with the call anyway. */
linphone_call_delete_ice_session(call);
linphone_call_stop_media_streams_for_ice_gathering(call);
} else {
defer = TRUE;
}
if (linphone_call_prepare_ice(call,FALSE)==1)
defer=TRUE;
}
else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
#ifdef BUILD_UPNP
call->log->start_date_time=time(NULL);
if (linphone_core_update_upnp(lc,call)<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
@ -2889,11 +2899,10 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
call->ping_op=sal_op_new(lc->sal);
sal_ping(call->ping_op,from,real_url);
sal_op_set_user_pointer(call->ping_op,call);
call->log->start_date_time=time(NULL);
defer = TRUE;
}
}
if (defer==FALSE) linphone_core_start_invite(lc,call,NULL);
if (real_url!=NULL) ms_free(real_url);
@ -2906,7 +2915,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
* @ingroup call_control
* The remote endpoint is expected to issue a new call to the specified destination.
* The current call remains active and thus can be later paused or terminated.
*
*
* It is possible to follow the progress of the transfer provided that transferee sends notification about it.
* In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party.
* The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected.
@ -2938,7 +2947,7 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char
* @param lc linphone core object
* @param call a running call you want to transfer
* @param dest a running call whose remote person will receive the transfer
*
*
* @ingroup call_control
*
* The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately.
@ -2946,7 +2955,7 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char
* This method will send a transfer request to the transfered person. The phone of the transfered is then
* expected to automatically call to the destination of the transfer. The receiver of the transfer will then automatically
* close the call with us (the 'dest' call).
*
*
* It is possible to follow the progress of the transfer provided that transferee sends notification about it.
* In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party.
* The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected.
@ -2971,7 +2980,7 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){
bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md){
int i;
if (md->n_active_streams==0) return FALSE;
for(i=0;i<md->n_active_streams;i++){
const SalStreamDescription *sd=&md->streams[i];
if (sd->proto!=SalProtoRtpSavp){
@ -3011,10 +3020,10 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
tmp=linphone_address_as_string(from_parsed);
linphone_address_destroy(from_parsed);
barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
(sal_call_autoanswer_asked(call->op)) ?_(" and asked autoanswer."):_("."));
(sal_call_autoanswer_asked(call->op)) ?_(" and asked autoanswer."):_("."));
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,barmesg);
lc->vtable.display_status(lc,barmesg);
/* play the ring if this is the only call*/
if (ms_list_size(lc->calls)==1){
@ -3044,11 +3053,11 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
if (call->state==LinphoneCallIncomingReceived){
/*try to be best-effort in giving real local or routable contact address for 100Rel case*/
linphone_call_set_contact_op(call);
if (propose_early_media || ringback_tone!=NULL){
linphone_core_accept_early_media(lc,call);
}else sal_call_notify_ringing(call->op,FALSE);
if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){
linphone_core_accept_call(lc,call);
}
@ -3074,7 +3083,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, const LinphoneCallParams* params) {
if (call->state==LinphoneCallIncomingReceived){
SalMediaDescription* md;
/*try to be best-effort in giving real local or routable contact address for 100Rel case*/
linphone_call_set_contact_op(call);
@ -3085,7 +3094,7 @@ int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall*
sal_call_set_local_media_description ( call->op,call->localdesc );
sal_op_set_sent_custom_header ( call->op,params->custom_headers );
}
sal_call_notify_ringing(call->op,TRUE);
linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media");
@ -3115,9 +3124,7 @@ int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call){
int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
const char *subject;
if (call->ice_session != NULL) {
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
}
linphone_call_make_local_media_description(lc,call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
@ -3164,10 +3171,6 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
// Video removing
if((call->videostream != NULL) && !params->has_video) {
if (call->ice_session != NULL) {
ice_session_remove_check_list(call->ice_session, call->videostream->ms.ice_check_list);
call->videostream->ms.ice_check_list = NULL;
}
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
if (linphone_core_update_upnp(lc, call)<0) {
@ -3180,27 +3183,18 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
#endif /* VIDEO_ENABLED */
_linphone_call_params_copy(&call->params,params);
linphone_call_make_local_media_description(lc, call);
err=linphone_call_prepare_ice(call,FALSE);
if (err==1) {
ms_message("Defer call update to gather ICE candidates");
return 0;
}
#ifdef VIDEO_ENABLED
// Video adding
if (!has_video && call->params.has_video) {
if (call->ice_session != NULL) {
/* Defer call update until the ICE candidates gathering process has finished. */
ms_message("Defer call update to gather ICE candidates");
linphone_call_init_video_stream(call);
video_stream_prepare_video(call->videostream);
if (linphone_core_gather_ice_candidates(lc,call)<0) {
/* Ice candidates gathering failed, proceed with the call anyway. */
linphone_call_delete_ice_session(call);
} else {
return err;
}
}
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
ms_message("Defer call update to add uPnP port mappings");
linphone_call_init_video_stream(call);
video_stream_prepare_video(call->videostream);
if (linphone_core_update_upnp(lc, call)<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
@ -3211,7 +3205,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
}
#endif //BUILD_UPNP
}
#endif
#endif //VIDEO_ENABLED
err = linphone_core_start_update_call(lc, call);
}else{
#ifdef VIDEO_ENABLED
@ -3230,15 +3224,15 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
/**
* @ingroup call_control
* When receiving a #LinphoneCallUpdatedByRemote state notification, prevent LinphoneCore from performing an automatic answer.
*
*
* When receiving a #LinphoneCallUpdatedByRemote state notification (ie an incoming reINVITE), the default behaviour of
* LinphoneCore is to automatically answer the reINIVTE with call parameters unchanged.
* However when for example when the remote party updated the call to propose a video stream, it can be useful
* to prompt the user before answering. This can be achieved by calling linphone_core_defer_call_update() during
* to prompt the user before answering. This can be achieved by calling linphone_core_defer_call_update() during
* the call state notifiacation, to deactivate the automatic answer that would just confirm the audio but reject the video.
* Then, when the user responds to dialog prompt, it becomes possible to call linphone_core_accept_call_update() to answer
* the reINVITE, with eventually video enabled in the LinphoneCallParams argument.
*
*
* @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a #LinphoneCallUpdatedByRemote notification, which is illegal.
**/
int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call){
@ -3257,13 +3251,9 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call)
/* Defer the sending of the answer until there are no losing pairs left. */
return 0;
}
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
}
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
}
#endif //BUILD_UPNP
linphone_call_make_local_media_description(lc,call);
linphone_call_update_remote_session_id_and_ver(call);
sal_call_set_local_media_description(call->op,call->localdesc);
sal_call_accept(call->op);
@ -3300,7 +3290,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call)
int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
if (call->state!=LinphoneCallUpdatedByRemote){
ms_error("linphone_core_accept_update(): invalid state %s to call this function.",
linphone_call_state_to_string(call->state));
linphone_call_state_to_string(call->state));
return -1;
}
return _linphone_core_accept_call_update(lc, call, params);
@ -3309,7 +3299,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const
int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
SalMediaDescription *remote_desc;
bool_t keep_sdp_version;
#ifdef VIDEO_ENABLED
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
bool_t old_has_video = call->params.has_video;
#endif
@ -3337,20 +3327,9 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons
}
call->params.has_video &= linphone_core_media_description_contains_video_stream(remote_desc);
linphone_call_init_media_streams(call); /*so that video stream is initialized if necessary*/
linphone_call_make_local_media_description(lc,call);
if (call->ice_session != NULL) {
linphone_core_update_ice_from_remote_media_description(call, remote_desc);
#ifdef VIDEO_ENABLED
if ((call->ice_session != NULL) && !ice_session_candidates_gathered(call->ice_session)) {
if ((call->params.has_video) && (call->params.has_video != old_has_video)) {
video_stream_prepare_video(call->videostream);
if (linphone_core_gather_ice_candidates(lc,call)<0) {
/* Ice candidates gathering failed, proceed with the call anyway. */
linphone_call_delete_ice_session(call);
} else return 0;
}
}
#endif //VIDEO_ENABLED
if (linphone_call_prepare_ice(call,TRUE)==1)
return 0;/*deferred to completion of ICE gathering*/
}
#ifdef BUILD_UPNP
@ -3427,7 +3406,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
LinphoneCall *rc=(LinphoneCall*)sal_op_get_user_pointer (replaced);
if (rc){
ms_message("Call %p replaces call %p. This last one is going to be terminated automatically.",
call,rc);
call,rc);
linphone_core_terminate_call(lc,rc);
}
}
@ -3459,7 +3438,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
sal_call_set_local_media_description(call->op,call->localdesc);
sal_op_set_sent_custom_header(call->op,params->custom_headers);
}
/*give a chance a set card prefered sampling frequency*/
if (call->localdesc->streams[0].max_rate>0) {
ms_message ("configuring prefered card sampling rate to [%i]",call->localdesc->streams[0].max_rate);
@ -3468,7 +3447,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
if (lc->sound_conf.capt_sndcard)
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate);
}
if (!was_ringing && call->audiostream->ms.state==MSStreamInitialized){
audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
}
@ -3586,9 +3565,9 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call)
/**
* Decline a pending incoming call, with a reason.
*
*
* @ingroup call_control
*
*
* @param lc the linphone core
* @param call the LinphoneCall, must be in the IncomingReceived state.
* @param reason the reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy
@ -3674,9 +3653,6 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
return -1;
}
linphone_call_make_local_media_description(lc,call);
if (call->ice_session != NULL) {
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
}
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
@ -3725,12 +3701,12 @@ int linphone_core_pause_all_calls(LinphoneCore *lc){
void linphone_core_preempt_sound_resources(LinphoneCore *lc){
LinphoneCall *current_call;
if (linphone_core_is_in_conference(lc)){
linphone_core_leave_conference(lc);
return;
}
current_call=linphone_core_get_current_call(lc);
if(current_call != NULL){
ms_message("Pausing automatically the current call.");
@ -3749,7 +3725,7 @@ void linphone_core_preempt_sound_resources(LinphoneCore *lc){
int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){
char temp[255]={0};
const char *subject="Call resuming";
if(call->state!=LinphoneCallPaused ){
ms_warning("we cannot resume a call that has not been established and paused before");
return -1;
@ -3764,15 +3740,12 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){
}
call->was_automatically_paused=FALSE;
/* Stop playing music immediately. If remote side is a conference it
prevents the participants to hear it while the 200OK comes back.*/
if (call->audiostream) audio_stream_play(call->audiostream, NULL);
linphone_call_make_local_media_description(lc,call);
if (call->ice_session != NULL) {
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
}
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
@ -3803,7 +3776,7 @@ static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *rad
* @param lc
* @param remote_address
* @return the LinphoneCall of the call if found
*
*
* @ingroup call_control
*/
LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address){
@ -3814,7 +3787,7 @@ LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const c
}
int linphone_core_send_publish(LinphoneCore *lc,
LinphonePresenceModel *presence)
LinphonePresenceModel *presence)
{
const MSList *elem;
for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=ms_list_next(elem)){
@ -4171,7 +4144,7 @@ static MSSndCard *get_card_from_string_id(const char *devid, unsigned int cap){
if (sndcard==NULL){/*looks like a bug! take the first one !*/
const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get());
if (elem) sndcard=(MSSndCard*)elem->data;
}
}
}
if (sndcard==NULL) ms_error("Could not find a suitable soundcard !");
return sndcard;
@ -4406,7 +4379,7 @@ const char *linphone_core_get_root_ca(LinphoneCore *lc){
/**
* Specify whether the tls server certificate must be verified when connecting to a SIP/TLS server.
*
*
* @ingroup initializing
**/
void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){
@ -4523,7 +4496,7 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){
if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){
audio_stream_mute_rtp(st,val);
}
}
}
@ -4609,7 +4582,7 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){
if (server)
lc->net_conf.stun_server=ms_strdup(server);
else lc->net_conf.stun_server=NULL;
/* each time the stun server is changed, we must clean the resolved cached addrinfo*/
if (lc->net_conf.stun_addrinfo){
freeaddrinfo(lc->net_conf.stun_addrinfo);
@ -4619,7 +4592,7 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){
if (lc->net_conf.stun_server){
linphone_core_resolve_stun_server(lc);
}
if (linphone_core_ready(lc))
lp_config_set_string(lc->config,"net","stun_server",lc->net_conf.stun_server);
}
@ -4676,7 +4649,7 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc)
char ipstring [INET6_ADDRSTRLEN];
if (lc->net_conf.nat_address==NULL) return NULL;
if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len, 5060)<0) {
return lc->net_conf.nat_address;
}
@ -5045,7 +5018,7 @@ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path) {
const char *linphone_core_get_static_picture(LinphoneCore *lc) {
const char *path=NULL;
#ifdef VIDEO_ENABLED
path=ms_static_image_get_default_image();
path=ms_static_image_get_default_image();
#else
ms_warning("Video support not compiled.");
#endif
@ -5082,7 +5055,7 @@ float linphone_core_get_static_picture_fps(LinphoneCore *lc) {
if (vs && vs->source) {
if (ms_filter_get_id(vs->source) == MS_STATIC_IMAGE_ID) {
float fps;
float fps;
ms_filter_call_method(vs->source, MS_FILTER_GET_FPS,(void *)&fps);
return fps;
@ -5120,7 +5093,7 @@ static void unset_video_window_id(LinphoneCore *lc, bool_t preview, unsigned lon
LinphoneCall *call;
MSList *elem;
#endif
if (id!=0 && id!=-1) {
ms_error("Invalid use of unset_video_window_id()");
return;
@ -5284,7 +5257,7 @@ static MSVideoSizeDef supported_resolutions[]={
#if !TARGET_OS_MAC || TARGET_OS_IPHONE /* OS_MAC is 1 for iPhone, but we need QVGA */
{ { MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H } , "qvga" },
#endif
{ { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H } , "qcif" },
{ { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H } , "qcif" },
{ { 0,0 } , NULL }
};
@ -5529,7 +5502,7 @@ void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){
def.frequencies[0]=620;
def.interval=250;
def.repeat_count=3;
break;
default:
ms_warning("Unhandled tone id.");
@ -5595,7 +5568,7 @@ int linphone_core_get_mtu(const LinphoneCore *lc){
* Sets the maximum transmission unit size in bytes.
* This information is useful for sending RTP packets.
* Default value is 1500.
*
*
* @ingroup media_parameters
**/
void linphone_core_set_mtu(LinphoneCore *lc, int mtu){
@ -5689,7 +5662,7 @@ void sip_config_uninit(LinphoneCore *lc)
int i;
sip_config_t *config=&lc->sip_conf;
bool_t still_registered=TRUE;
lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname);
lp_config_set_string(lc->config,"sip","contact",config->contact);
lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout);
@ -5704,7 +5677,7 @@ void sip_config_uninit(LinphoneCore *lc)
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
linphone_proxy_config_edit(cfg); /* to unregister */
}
ms_message("Unregistration started.");
for (i=0;i<20&&still_registered;i++){
@ -5736,7 +5709,7 @@ void sip_config_uninit(LinphoneCore *lc)
ms_message("Tunnel destroyed.");
}
#endif
sal_reset_transports(lc->sal);
sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/
if (lc->http_provider) {
@ -5942,7 +5915,7 @@ static void linphone_core_uninit(LinphoneCore *lc)
linphone_presence_model_unref(lc->presence_model);
}
linphone_core_free_payload_types(lc);
linphone_core_message_storage_close(lc);
ms_exit();
linphone_core_set_state(lc,LinphoneGlobalOff,"Off");
@ -5951,7 +5924,7 @@ static void linphone_core_uninit(LinphoneCore *lc)
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){
// second get the list of available proxies
const MSList *elem=linphone_core_get_proxy_config_list(lc);
if (lc->network_reachable==isReachable) return; // no change, ignore.
ms_message("Network state is now [%s]",isReachable?"UP":"DOWN");
@ -5968,7 +5941,7 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu
}
lc->netup_time=curtime;
lc->network_reachable=isReachable;
if (!lc->network_reachable){
linphone_core_invalidate_friend_subscriptions(lc);
sal_reset_transports(lc->sal);
@ -6442,7 +6415,7 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption
LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) {
const char* menc = lp_config_get_string(lc->config, "sip", "media_encryption", NULL);
if (menc == NULL)
return LinphoneMediaEncryptionNone;
else if (strcmp(menc, "srtp")==0)
@ -6478,10 +6451,10 @@ const char* linphone_core_get_device_identifier(const LinphoneCore *lc) {
/**
* Set the DSCP field for SIP signaling channel.
*
*
* @ingroup network_parameters
* * The DSCP defines the quality of service in IP packets.
*
*
**/
void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){
sal_set_dscp(lc->sal,dscp);
@ -6493,10 +6466,10 @@ void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){
/**
* Get the DSCP field for SIP signaling channel.
*
*
* @ingroup network_parameters
* * The DSCP defines the quality of service in IP packets.
*
*
**/
int linphone_core_get_sip_dscp(const LinphoneCore *lc){
return lp_config_get_int(lc->config,"sip","dscp",0x1a);
@ -6507,7 +6480,7 @@ int linphone_core_get_sip_dscp(const LinphoneCore *lc){
*
* @ingroup network_parameters
* The DSCP defines the quality of service in IP packets.
*
*
**/
void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){
if (linphone_core_ready(lc))
@ -6519,7 +6492,7 @@ void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){
*
* @ingroup network_parameters
* The DSCP defines the quality of service in IP packets.
*
*
**/
int linphone_core_get_audio_dscp(const LinphoneCore *lc){
return lp_config_get_int(lc->config,"rtp","audio_dscp",0x2e);
@ -6530,12 +6503,12 @@ int linphone_core_get_audio_dscp(const LinphoneCore *lc){
*
* @ingroup network_parameters
* The DSCP defines the quality of service in IP packets.
*
*
**/
void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){
if (linphone_core_ready(lc))
lp_config_set_int_hex(lc->config,"rtp","video_dscp",dscp);
}
/**
@ -6543,7 +6516,7 @@ void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){
*
* @ingroup network_parameters
* The DSCP defines the quality of service in IP packets.
*
*
**/
int linphone_core_get_video_dscp(const LinphoneCore *lc){
return lp_config_get_int(lc->config,"rtp","video_dscp",0);

View file

@ -177,7 +177,7 @@ enum _LinphoneReason{
LinphoneReasonNotAcceptable, /**<Operation like call update rejected by peer*/
LinphoneReasonNoMatch, /**<Operation could not be executed by server or remote client because it didn't have any context for it*/
LinphoneReasonMovedPermanently, /**<Resource moved permanently*/
LinphoneReasonGone, /**<Resource no longer exists*/
LinphoneReasonGone, /**<Resource no longer exists*/
LinphoneReasonTemporarilyUnavailable, /**<Temporarily unavailable*/
LinphoneReasonAddressIncomplete, /**<Address incomplete*/
LinphoneReasonNotImplemented, /**<Not implemented*/
@ -684,7 +684,6 @@ LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call);
LINPHONE_PUBLIC const char *linphone_call_get_remote_user_agent(LinphoneCall *call);
LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(LinphoneCall *call);
LINPHONE_PUBLIC LinphoneAddress *linphone_call_get_remote_contact_address(LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_get_play_volume(LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_get_record_volume(LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_get_current_quality(LinphoneCall *call);
@ -790,6 +789,7 @@ LINPHONE_PUBLIC int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *o
LINPHONE_PUBLIC int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity);
LINPHONE_PUBLIC int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route);
LINPHONE_PUBLIC void linphone_proxy_config_set_expires(LinphoneProxyConfig *obj, int expires);
#define linphone_proxy_config_expires linphone_proxy_config_set_expires
/**
* Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig .
@ -809,9 +809,35 @@ LINPHONE_PUBLIC int linphone_proxy_config_done(LinphoneProxyConfig *obj);
*
*/
LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val);
/**
* Set the publish expiration time in second.
* @param obj proxy config
* @param exires in second
* */
LINPHONE_PUBLIC void linphone_proxy_config_set_publish_expires(LinphoneProxyConfig *obj, int expires);
/**
* get the publish expiration time in second. Default value is the registration expiration value.
* @param obj proxy config
* @return expires in second
* */
LINPHONE_PUBLIC int linphone_proxy_config_get_publish_expires(const LinphoneProxyConfig *obj);
LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val);
LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix);
/**
* Indicates either or not, quality statistics during call should be stored and sent to a collector at termination.
* @param cfg #LinphoneProxyConfig object
* @param val if true, quality statistics publish will be stored and sent to the collector
*
*/
LINPHONE_PUBLIC void linphone_proxy_config_enable_statistics(LinphoneProxyConfig *cfg, bool_t val);
LINPHONE_PUBLIC bool_t linphone_proxy_config_send_statistics_enabled(LinphoneProxyConfig *cfg);
LINPHONE_PUBLIC void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, const char *collector);
LINPHONE_PUBLIC const char *linphone_proxy_config_get_statistics_collector(const LinphoneProxyConfig *obj);
/**
* Get the registration state of the given proxy config.
* @param[in] obj #LinphoneProxyConfig object.
@ -1556,6 +1582,33 @@ LINPHONE_PUBLIC int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *cod
*/
LINPHONE_PUBLIC bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt);
/**
* Tells whether the specified payload type represents a variable bitrate codec.
* @param[in] lc #LinphoneCore object.
* @param[in] pt The #PayloadType we want to know
* @returns TRUE if the payload type represents a VBR codec, FALSE if disabled.
* @ingroup media_parameters
*/
LINPHONE_PUBLIC bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const PayloadType *pt);
/**
* Set an explicit bitrate (IP bitrate, not codec bitrate) for a given codec, in kbit/s.
* @param[in] lc the #LinphoneCore object
* @param[in] pt the #PayloadType to modify.
* @param[in] bitrate the IP bitrate in kbit/s.
* @ingroup media_parameters
**/
LINPHONE_PUBLIC void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, PayloadType *pt, int bitrate);
/**
* Get the bitrate explicitely set with linphone_core_set_payload_type_bitrate().
* @param[in] lc the #LinphoneCore object
* @param[in] pt the #PayloadType to modify.
* @return bitrate the IP bitrate in kbit/s, or -1 if an error occured.
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const PayloadType *pt);
/**
* Enable or disable the use of the specified payload type.
* @param[in] lc #LinphoneCore object.
@ -1592,7 +1645,7 @@ LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, cons
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, PayloadType *pt);
LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const PayloadType *pt);
/**
* Create a proxy config with default values from Linphone core.

View file

@ -1240,6 +1240,22 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isPayloadTypeEnabled
,jlong pt) {
return (jboolean) linphone_core_payload_type_enabled((LinphoneCore*)lc, (PayloadType*)pt);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPayloadTypeBitrate(JNIEnv* env
,jobject thiz
,jlong lc
,jlong pt
,jint bitrate) {
linphone_core_set_payload_type_bitrate((LinphoneCore*)lc,(PayloadType*)pt,bitrate);
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getPayloadTypeBitrate(JNIEnv* env
,jobject thiz
,jlong lc
,jlong pt) {
return (jint)linphone_core_get_payload_type_bitrate((LinphoneCore*)lc,(PayloadType*)pt);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableEchoCancellation(JNIEnv* env
,jobject thiz
,jlong lc

View file

@ -63,6 +63,7 @@ typedef struct _LpSection{
} LpSection;
struct _LpConfig{
int refcnt;
FILE *file;
char *filename;
MSList *sections;
@ -293,6 +294,8 @@ LpConfig * lp_config_new_from_buffer(const char *buffer){
char* strtok_storage = NULL;
char* line = strtok_r(ptr, "\n", &strtok_storage);
conf->refcnt=1;
while( line != NULL ){
current_section = lp_config_parse_line(conf,line,current_section);
line = strtok_r(NULL, "\n", &strtok_storage);
@ -305,7 +308,7 @@ LpConfig * lp_config_new_from_buffer(const char *buffer){
LpConfig *lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename) {
LpConfig *lpconfig=lp_new0(LpConfig,1);
lpconfig->refcnt=1;
if (config_filename!=NULL){
ms_message("Using (r/w) config information from %s", config_filename);
lpconfig->filename=ortp_strdup(config_filename);
@ -354,13 +357,28 @@ void lp_item_set_value(LpItem *item, const char *value){
}
void lp_config_destroy(LpConfig *lpconfig){
static void _lp_config_destroy(LpConfig *lpconfig){
if (lpconfig->filename!=NULL) ortp_free(lpconfig->filename);
ms_list_for_each(lpconfig->sections,(void (*)(void*))lp_section_destroy);
ms_list_free(lpconfig->sections);
free(lpconfig);
}
LpConfig *lp_config_ref(LpConfig *lpconfig){
lpconfig->refcnt++;
return lpconfig;
}
void lp_config_unref(LpConfig *lpconfig){
lpconfig->refcnt--;
if (lpconfig->refcnt==0)
_lp_config_destroy(lpconfig);
}
void lp_config_destroy(LpConfig *lpconfig){
lp_config_unref(lpconfig);
}
void lp_section_remove_item(LpSection *sec, LpItem *item){
sec->items=ms_list_remove(sec->items,(void *)item);
lp_item_destroy(item);

View file

@ -57,7 +57,7 @@ extern "C" {
/**
* Instantiates a LpConfig object from a user config file.
*
* The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed.
* @ingroup misc
* @param filename the filename of the config file to read to fill the instantiated LpConfig
* @see lp_config_new_with_factory
@ -66,7 +66,7 @@ LINPHONE_PUBLIC LpConfig * lp_config_new(const char *filename);
/**
* Instantiates a LpConfig object from a user provided buffer.
*
* The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed.
* @ingroup misc
* @param buffer the buffer from which the lpconfig will be retrieved. We expect the buffer to be null-terminated.
* @see lp_config_new_with_factory
@ -76,7 +76,7 @@ LINPHONE_PUBLIC LpConfig * lp_config_new_from_buffer(const char *buffer);
/**
* Instantiates a LpConfig object from a user config file and a factory config file.
*
* The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed.
* @ingroup misc
* @param config_filename the filename of the user config file to read to fill the instantiated LpConfig
* @param factory_config_filename the filename of the factory config file to read to fill the instantiated LpConfig
@ -259,6 +259,19 @@ LINPHONE_PUBLIC const char* lp_config_get_default_string(const LpConfig *lpconfi
**/
LINPHONE_PUBLIC const char* lp_config_get_section_param_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value);
/**
* increment reference count
* @ingroup misc
**/
LINPHONE_PUBLIC LpConfig *lp_config_ref(LpConfig *lpconfig);
/**
* Decrement reference count, which will eventually free the object.
* @ingroup misc
**/
LINPHONE_PUBLIC void lp_config_unref(LpConfig *lpconfig);
#ifdef __cplusplus
}
#endif

View file

@ -77,6 +77,11 @@ bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *p
return FALSE;
}
bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const PayloadType *pt){
if (pt->type==PAYLOAD_VIDEO) return TRUE;
return !!(pt->flags & PAYLOAD_TYPE_IS_VBR);
}
int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enabled){
if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
payload_type_set_enable(pt,enabled);
@ -88,7 +93,7 @@ int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t
}
int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt){
return payload_type_get_number(pt);
return payload_type_get_number(pt);
}
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
@ -103,77 +108,134 @@ const char *linphone_core_get_payload_type_description(LinphoneCore *lc, Payload
return NULL;
}
/*this function makes a special case for speex/8000.
This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
int upload_bw=linphone_core_get_upload_bandwidth(lc);
if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) {
if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){
return 15000;
void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, PayloadType *pt, int bitrate){
if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){
if (pt->type==PAYLOAD_VIDEO || pt->flags & PAYLOAD_TYPE_IS_VBR){
pt->normal_bitrate=bitrate*1000;
pt->flags|=PAYLOAD_TYPE_BITRATE_OVERRIDE;
}else{
ms_error("Cannot set an explicit bitrate for codec %s/%i, because it is not VBR.",pt->mime_type,pt->clock_rate);
return;
}
}
return pt->normal_bitrate;
ms_error("linphone_core_set_payload_type_bitrate() payload type not in audio or video list !");
}
/*
*((codec-birate*ptime/8) + RTP header + UDP header + IP header)*8/ptime;
*ptime=1/npacket
*/
static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
static double get_audio_payload_bandwidth_from_codec_bitrate(const PayloadType *pt){
double npacket=50;
double packet_size;
int bitrate;
if (strcmp(payload_type_get_mime(&payload_type_aaceld_44k), payload_type_get_mime(pt))==0) {
/*special case of aac 44K because ptime= 10ms*/
npacket=100;
}else if (strcmp(payload_type_get_mime(&payload_type_ilbc), payload_type_get_mime(pt))==0) {
npacket=1000/30.0;
}
bitrate=get_codec_bitrate(lc,pt);
bitrate=pt->normal_bitrate;
packet_size= (((double)bitrate)/(npacket*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
return packet_size*8.0*npacket;
}
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt){
call->audio_bw=(int)(ceil(get_audio_payload_bandwidth(call->core,pt)/1000.0)); /*rounding codec bandwidth should be avoid, specially for AMR*/
typedef struct vbr_codec_bitrate{
int max_avail_bitrate;
int min_rate;
int recomended_bitrate;
}vbr_codec_bitrate_t;
static vbr_codec_bitrate_t defauls_vbr[]={
//{ 100, 44100, 100 },
{ 64, 44100, 50 },
{ 64, 16000, 40 },
{ 32, 16000, 32 },
{ 32, 8000, 32 },
{ 0 , 8000, 24 },
{ 0 , 0, 0 }
};
static int lookup_vbr_typical_bitrate(int maxbw, int clock_rate){
vbr_codec_bitrate_t *it;
if (maxbw<=0) maxbw=defauls_vbr[0].max_avail_bitrate;
for(it=defauls_vbr;it->min_rate!=0;it++){
if (maxbw>=it->max_avail_bitrate && clock_rate>=it->min_rate)
return it->recomended_bitrate;
}
ms_error("lookup_vbr_typical_bitrate(): should not happen.");
return 32;
}
static int get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt, int maxbw){
if (linphone_core_payload_type_is_vbr(lc,pt)){
if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){
ms_message("PayloadType %s/%i has bitrate override",pt->mime_type,pt->clock_rate);
return pt->normal_bitrate/1000;
}
return lookup_vbr_typical_bitrate(maxbw,pt->clock_rate);
}else return (int)ceil(get_audio_payload_bandwidth_from_codec_bitrate(pt)/1000.0);/*rounding codec bandwidth should be avoid, specially for AMR*/
}
int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const PayloadType *pt){
int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
linphone_core_get_upload_bandwidth(lc));
if (pt->type==PAYLOAD_AUDIO_CONTINUOUS || pt->type==PAYLOAD_AUDIO_PACKETIZED){
return get_audio_payload_bandwidth(lc,pt,maxbw);
}else if (pt->type==PAYLOAD_VIDEO){
int video_bw;
linphone_core_update_allocated_audio_bandwidth(lc);
if (maxbw<=0) {
video_bw=1500; /*default bitrate for video stream when no bandwidth limit is set, around 1.5 Mbit/s*/
}else{
video_bw=get_remaining_bandwidth_for_video(maxbw,lc->audio_bw);
}
return video_bw;
}
return 0;
}
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw){
call->audio_bw=get_audio_payload_bandwidth(call->core,pt,maxbw);
ms_message("Audio bandwidth for this call is %i",call->audio_bw);
}
void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
const MSList *elem;
PayloadType *max=NULL;
int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
linphone_core_get_upload_bandwidth(lc));
int max_codec_bitrate=0;
for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
PayloadType *pt=(PayloadType*)elem->data;
if (payload_type_enabled(pt)){
int pt_bitrate=get_codec_bitrate(lc,pt);
if (max==NULL) max=pt;
else if (max->normal_bitrate<pt_bitrate){
max=pt;
int pt_bitrate=get_audio_payload_bandwidth(lc,pt,maxbw);
if (max_codec_bitrate==0) {
max_codec_bitrate=pt_bitrate;
}else if (max_codec_bitrate<pt_bitrate){
max_codec_bitrate=pt_bitrate;
}
}
}
if (max) {
lc->audio_bw=(int)(get_audio_payload_bandwidth(lc,max)/1000.0);
if (max_codec_bitrate) {
lc->audio_bw=max_codec_bitrate;
}
}
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit)
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit)
{
double codec_band;
bool_t ret=FALSE;
switch (pt->type){
case PAYLOAD_AUDIO_CONTINUOUS:
case PAYLOAD_AUDIO_PACKETIZED:
codec_band=get_audio_payload_bandwidth(lc,pt);
codec_band=get_audio_payload_bandwidth(lc,pt,bandwidth_limit);
ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band);
/*hack to avoid using uwb codecs when having low bitrate and video*/
if (bandwidth_is_greater(199,bandwidth_limit)){
if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
ret=FALSE;
}
}
//ms_message("Payload %s: %g",pt->mime_type,codec_band);
break;
case PAYLOAD_VIDEO:
@ -187,43 +249,8 @@ bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, Payl
}
/* return TRUE if codec can be used with bandwidth, FALSE else*/
bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt)
{
double codec_band;
int allowed_bw,video_bw;
bool_t ret=FALSE;
linphone_core_update_allocated_audio_bandwidth(lc);
allowed_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
linphone_core_get_upload_bandwidth(lc));
if (allowed_bw==0) {
allowed_bw=-1;
video_bw=1500; /*around 1.5 Mbit/s*/
}else
video_bw=get_video_bandwidth(allowed_bw,lc->audio_bw);
switch (pt->type){
case PAYLOAD_AUDIO_CONTINUOUS:
case PAYLOAD_AUDIO_PACKETIZED:
codec_band=get_audio_payload_bandwidth(lc,pt);
ret=bandwidth_is_greater(allowed_bw*1000,codec_band);
/*hack to avoid using uwb codecs when having low bitrate and video*/
if (bandwidth_is_greater(199,allowed_bw)){
if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
ret=FALSE;
}
}
//ms_message("Payload %s: %g",pt->mime_type,codec_band);
break;
case PAYLOAD_VIDEO:
if (video_bw>0){
pt->normal_bitrate=video_bw*1000;
ret=TRUE;
}
else ret=FALSE;
break;
}
return ret;
bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const PayloadType *pt){
return linphone_core_is_payload_type_usable_for_bandwidth(lc, pt, linphone_core_get_payload_type_bitrate(lc,pt));
}
bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
@ -278,7 +305,7 @@ static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t ad
char buf[STUN_MAX_MESSAGE_SIZE];
int len = STUN_MAX_MESSAGE_SIZE;
StunAtrString username;
StunAtrString password;
StunAtrString password;
StunMessage req;
int err;
memset(&req, 0, sizeof(StunMessage));
@ -301,9 +328,9 @@ static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t ad
int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port){
char tmphost[NI_MAXHOST]={0};
char *p1, *p2;
if ((sscanf(input, "[%64[^]]]:%d", tmphost, port) == 2) || (sscanf(input, "[%64[^]]]", tmphost) == 1)) {
} else {
p1 = strchr(input, ':');
p2 = strrchr(input, ':');
@ -324,9 +351,9 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock
char host[NI_MAXHOST];
int port_int=default_port;
int ret;
linphone_parse_host_port(server,host,sizeof(host),&port_int);
snprintf(port, sizeof(port), "%d", port_int);
memset(&hints,0,sizeof(hints));
hints.ai_family=AF_UNSPEC;
@ -346,7 +373,7 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock
static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
char buf[STUN_MAX_MESSAGE_SIZE];
int len = STUN_MAX_MESSAGE_SIZE;
int len = STUN_MAX_MESSAGE_SIZE;
StunMessage resp;
len=recv(sock,buf,len,0);
if (len>0){
@ -370,7 +397,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
const char *server=linphone_core_get_stun_server(lc);
StunCandidate *ac=&call->ac;
StunCandidate *vc=&call->vc;
if (lc->sip_conf.ipv6_enabled){
ms_warning("stun support is not implemented for ipv6");
return -1;
@ -389,7 +416,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
struct timeval init,cur;
double elapsed;
int ret=0;
if (ai==NULL){
ms_error("Could not obtain stun server addrinfo.");
return -1;
@ -408,7 +435,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
got_video=FALSE;
ortp_gettimeofday(&init,NULL);
do{
int id;
if (loops%20==0){
ms_message("Sending stun requests...");
@ -487,7 +514,7 @@ void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, Linphone
if (ping_time_ms>0 && lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){
ms_message("Stun server ping time is %i ms",ping_time_ms);
threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500);
if (ping_time_ms>threshold){
/* we might be in a 2G network*/
params->low_bandwidth=TRUE;
@ -536,7 +563,7 @@ void linphone_core_resolve_stun_server(LinphoneCore *lc){
* - have a cache of the stun server addrinfo
* - this cached value is returned when it is non-null
* - an asynchronous resolution is asked each time this function is called to ensure frequent refreshes of the cached value.
* - if no cached value exists, block for a short time; this case must be unprobable because the resolution will be asked each time the stun server value is
* - if no cached value exists, block for a short time; this case must be unprobable because the resolution will be asked each time the stun server value is
* changed.
**/
const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc){
@ -957,7 +984,7 @@ unsigned int linphone_core_get_audio_features(LinphoneCore *lc){
p=n;
}
}else ret=AUDIO_STREAM_FEATURE_ALL;
if (ret==AUDIO_STREAM_FEATURE_ALL){
/*since call recording is specified before creation of the stream in linphonecore,
* it will be requested on demand. It is not necessary to include it all the time*/
@ -973,12 +1000,12 @@ bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc){
#ifdef HAVE_GETIFADDRS
#include <ifaddrs.h>
static int get_local_ip_with_getifaddrs(int type, char *address, int size)
{
static int get_local_ip_with_getifaddrs(int type, char *address, int size){
struct ifaddrs *ifp;
struct ifaddrs *ifpstart;
int ret = 0;
char retaddr[LINPHONE_IPADDR_SIZE]={0};
bool_t found=FALSE;
if (getifaddrs(&ifpstart) < 0) {
return -1;
}
@ -987,7 +1014,7 @@ static int get_local_ip_with_getifaddrs(int type, char *address, int size)
#else
#define UP_FLAG IFF_RUNNING /* resources allocated */
#endif
for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
&& (ifp->ifa_flags & UP_FLAG) && !(ifp->ifa_flags & IFF_LOOPBACK))
@ -995,17 +1022,18 @@ static int get_local_ip_with_getifaddrs(int type, char *address, int size)
if(getnameinfo(ifp->ifa_addr,
(type == AF_INET6) ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
address, size, NULL, 0, NI_NUMERICHOST) == 0) {
if (strchr(address, '%') == NULL) { /*avoid ipv6 link-local addresses */
retaddr, size, NULL, 0, NI_NUMERICHOST) == 0) {
if (strchr(retaddr, '%') == NULL) { /*avoid ipv6 link-local addresses */
/*ms_message("getifaddrs() found %s",address);*/
ret++;
found=TRUE;
break;
}
}
}
}
freeifaddrs(ifpstart);
return ret;
if (found) strncpy(address,retaddr,size);
return found;
}
#endif
@ -1042,8 +1070,8 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
if (err<0) {
/*the network isn't reachable*/
if (getSocketErrorCode()!=ENETUNREACH) ms_error("Error in connect: %s",strerror(errno));
freeaddrinfo(res);
close_socket(sock);
freeaddrinfo(res);
close_socket(sock);
return -1;
}
freeaddrinfo(res);
@ -1067,7 +1095,7 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
ms_error("getnameinfo error: %s",strerror(errno));
}
/*avoid ipv6 link-local addresses*/
if (type==AF_INET6 && strchr(result,'%')!=NULL){
if (p_addr->sa_family==AF_INET6 && strchr(result,'%')!=NULL){
strcpy(result,"::1");
close_socket(sock);
return -1;
@ -1078,19 +1106,19 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
int err;
strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
if (dest==NULL){
if (type==AF_INET)
dest="87.98.157.38"; /*a public IP address*/
else dest="2a00:1450:8002::68";
}
err=get_local_ip_for_with_connect(type,dest,result);
err=get_local_ip_for_with_connect(type,dest,result);
if (err==0) return 0;
/* if the connect method failed, which happens when no default route is set,
/* if the connect method failed, which happens when no default route is set,
* try to find 'the' running interface with getifaddrs*/
#ifdef HAVE_GETIFADDRS
/*we use getifaddrs for lookup of default interface */
int found_ifs;
@ -1103,7 +1131,7 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
return -1;
}
#endif
return 0;
return 0;
}
SalReason linphone_reason_to_sal(LinphoneReason reason){

View file

@ -39,11 +39,20 @@ 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){
(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){
@ -56,7 +65,7 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload
mode2=atoi(value);
}
if (mode1==mode2)
break; /*exact match */
break; /*exact match */
}
}else break;
}
@ -69,7 +78,7 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t
MSList *res=NULL;
PayloadType *matched;
bool_t found_codec=FALSE;
for(e2=remote;e2!=NULL;e2=e2->next){
PayloadType *p2=(PayloadType*)e2->data;
matched=find_payload_type_best_match(local,p2);
@ -85,7 +94,7 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t
}else found_codec=TRUE;
}
}
newp=payload_type_clone(matched);
if (p2->send_fmtp)
payload_type_set_send_fmtp(newp,p2->send_fmtp);
@ -95,7 +104,7 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t
payload_type_set_number(newp,remote_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);
newp->mime_type, local_number, remote_number);
/*
We must add this payload type with our local numbering in order to be able to receive it.
Indeed despite we must sent with the remote numbering, we must be able to receive with
@ -106,7 +115,9 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t
res=ms_list_append(res,newp);
}
}else{
ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
if (p2->channels>0)
ms_message("No match for %s/%i/%i",p2->mime_type,p2->clock_rate,p2->channels);
else ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
}
}
if (reading_response){
@ -132,28 +143,28 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t
return res;
}
static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCryptoAlgo* remote,
static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCryptoAlgo* remote,
SalSrtpCryptoAlgo* result, unsigned int* choosen_local_tag, bool_t use_local_key) {
int i,j;
for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
if (remote[i].algo == 0)
break;
/* Look for a local enabled crypto algo that matches one of the proposed by remote */
/* Look for a local enabled crypto algo that matches one of the proposed by remote */
for(j=0; j<SAL_CRYPTO_ALGO_MAX; j++) {
if (remote[i].algo == local[j].algo) {
result->algo = remote[i].algo;
/* We're answering an SDP offer. Supply our master key, associated with the remote supplied tag */
/* We're answering an SDP offer. Supply our master key, associated with the remote supplied tag */
if (use_local_key) {
strncpy(result->master_key, local[j].master_key, 41);
result->tag = remote[i].tag;
*choosen_local_tag = local[j].tag;
*choosen_local_tag = local[j].tag;
}
/* We received an answer to our SDP crypto proposal. Copy matching algo remote master key to result, and memorize local tag */
else {
else {
strncpy(result->master_key, remote[i].master_key, 41);
result->tag = local[j].tag;
*choosen_local_tag = local[j].tag;
*choosen_local_tag = local[j].tag;
}
result->master_key[40] = '\0';
return TRUE;
@ -205,8 +216,8 @@ static SalStreamDir compute_dir_incoming(SalStreamDir local, SalStreamDir offere
}
static void initiate_outgoing(const SalStreamDescription *local_offer,
const SalStreamDescription *remote_answer,
SalStreamDescription *result){
const SalStreamDescription *remote_answer,
SalStreamDescription *result){
if (remote_answer->rtp_port!=0)
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
result->proto=remote_answer->proto;
@ -233,8 +244,8 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
static void initiate_incoming(const SalStreamDescription *local_cap,
const SalStreamDescription *remote_offer,
SalStreamDescription *result, bool_t one_matching_codec){
const SalStreamDescription *remote_offer,
SalStreamDescription *result, bool_t one_matching_codec){
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
result->proto=remote_offer->proto;
result->type=local_cap->type;
@ -254,7 +265,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
memset(result->crypto, 0, sizeof(result->crypto));
if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE))
result->rtp_port = 0;
}
strcpy(result->ice_pwd, local_cap->ice_pwd);
strcpy(result->ice_ufrag, local_cap->ice_ufrag);
@ -388,7 +399,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
strcpy(result->ice_ufrag, local_capabilities->ice_ufrag);
result->ice_lite = local_capabilities->ice_lite;
result->ice_completed = local_capabilities->ice_completed;
strcpy(result->name,local_capabilities->name);
// Handle session RTCP XR attribute

View file

@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef offeranswer_h
#define offeranswer_h
/**
/**
This header files defines the SDP offer answer API.
It can be used by implementations of SAL directly.
**/
@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**/
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
const SalMediaDescription *remote_answer,
SalMediaDescription *result);
SalMediaDescription *result);
/**
* Returns a media description to run the streams with, based on the local capabilities and
@ -41,7 +41,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
**/
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
const SalMediaDescription *remote_offer,
SalMediaDescription *result, bool_t one_matching_codec);
SalMediaDescription *result, bool_t one_matching_codec);
#endif

View file

@ -170,7 +170,7 @@ static time_t parse_timestamp(const char *timestamp) {
return seconds - timezone;
}
static char * timestamp_to_string(time_t timestamp) {
char * linphone_timestamp_to_rfc3339_string(time_t timestamp) {
char timestamp_str[22];
struct tm *ret;
#ifndef WIN32
@ -1467,7 +1467,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
char *tmp;
LinphoneAddress *uri;
LinphoneProxyConfig *cfg;
uri=linphone_address_new(from);
linphone_address_clean(uri);
tmp=linphone_address_as_string(uri);
@ -1482,7 +1482,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
}
}
}
/* check if we answer to this subscription */
if (linphone_find_friend_by_address(lc->friends,uri,&lf)!=NULL){
lf->insub=op;
@ -1604,7 +1604,7 @@ static void write_xml_presence_note_obj(LinphonePresenceNote *note, struct _pres
static int write_xml_presence_timestamp(xmlTextWriterPtr writer, time_t timestamp) {
int err;
char *timestamp_str = timestamp_to_string(timestamp);
char *timestamp_str = linphone_timestamp_to_rfc3339_string(timestamp);
err = xmlTextWriterWriteElement(writer, (const xmlChar *)"timestamp", (const xmlChar *)timestamp_str);
if (timestamp_str) ms_free(timestamp_str);
return err;

View file

@ -34,6 +34,7 @@ extern "C" {
#include "linphonecore_utils.h"
#include "sal/sal.h"
#include "sipsetup.h"
#include "quality_reporting.h"
#include <belle-sip/object.h>
#include <belle-sip/dict.h>
@ -115,6 +116,8 @@ struct _LinphoneCallLog{
float quality;
time_t start_date_time; /**Start date of the call in seconds as expressed in a time_t */
char* call_id; /**unique id of a call*/
reporting_session_report_t * reports[2]; /**<Quality statistics of the call (rfc6035) */
bool_t video_enabled;
};
@ -191,6 +194,7 @@ struct _LinphoneCall
StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
MSAudioEndpoint *endpoint; /*used for conferencing*/
char *refer_to;
LinphoneCallParams params;
@ -224,8 +228,6 @@ struct _LinphoneCall
bool_t owns_call_log;
bool_t ringing_beep; /* whether this call is ringing through an already existent current call*/
bool_t videostream_encrypted;
bool_t audiostream_encrypted;
bool_t auth_token_verified;
bool_t defer_update;
@ -290,7 +292,7 @@ static inline bool_t bandwidth_is_greater(int bw1, int bw2){
else return bw1>=bw2;
}
static inline int get_video_bandwidth(int total, int audio){
static inline int get_remaining_bandwidth_for_video(int total, int audio){
if (total<=0) return 0;
return total-audio-10;
}
@ -305,6 +307,7 @@ static 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
void linphone_process_authentication(LinphoneCore* lc, SalOp *op);
void linphone_authentication_ok(LinphoneCore *lc, SalOp *op);
@ -319,7 +322,7 @@ void linphone_subscription_answered(LinphoneCore *lc, SalOp *op);
void linphone_subscription_closed(LinphoneCore *lc, SalOp *op);
void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt);
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw);
int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_resolve_stun_server(LinphoneCore *lc);
@ -327,6 +330,7 @@ const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc);
void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params);
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call);
void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev);
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md);
@ -401,10 +405,12 @@ struct _LinphoneProxyConfig
char *reg_proxy;
char *reg_identity;
char *reg_route;
char *statistics_collector;
char *realm;
char *contact_params;
char *contact_uri_params;
int expires;
int publish_expires;
SalOp *op;
char *type;
struct _SipSetupContext *ssctx;
@ -417,6 +423,7 @@ struct _LinphoneProxyConfig
bool_t publish;
bool_t dial_escape_plus;
bool_t send_publish;
bool_t send_statistics;
bool_t pad[3];
void* user_data;
time_t deletion_date;
@ -649,7 +656,7 @@ struct _LinphoneCore
char *play_file;
char *rec_file;
time_t prevtime;
int audio_bw;
int audio_bw; /*IP bw consumed by audio codec, set as soon as used codec is known, its purpose is to know the remaining bw for video*/
LinphoneCoreWaitingCallback wait_cb;
void *wait_ctx;
unsigned long video_window_id;
@ -671,10 +678,11 @@ struct _LinphoneCore
bool_t use_preview_window;
time_t network_last_check;
bool_t network_last_status;
bool_t ringstream_autorelease;
bool_t pad[2];
char localip[LINPHONE_IPADDR_SIZE];
int device_rotation;
int max_calls;
LinphoneTunnel *tunnel;
@ -705,10 +713,9 @@ struct _LinphoneEvent{
void *userdata;
int refcnt;
char *name;
LinphoneAddress *from;
LinphoneAddress *resource_addr;
int expires;
bool_t terminating;
bool_t is_out_of_dialog_op; /*used for out of dialog notify*/
};
@ -727,7 +734,7 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md);
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit);
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit);
#define linphone_core_ready(lc) ((lc)->state==LinphoneGlobalOn || (lc)->state==LinphoneGlobalShutdown)
void _linphone_core_configure_resolver();
@ -805,13 +812,19 @@ bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc);
const char *linphone_core_create_uuid(LinphoneCore *lc);
void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact);
void linphone_call_create_op(LinphoneCall *call);
int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer);
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body);
void linphone_content_uninit(LinphoneContent * obj);
LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref);
SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc);
SalReason linphone_reason_to_sal(LinphoneReason reason);
LinphoneReason linphone_reason_from_sal(SalReason reason);
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires);
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name);
/**
* Useful for out of dialog notify
* */
LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name);
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state);
void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state);
LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss);
@ -854,11 +867,18 @@ char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *
void linphone_free_xml_text_content(const char *text);
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
/*****************************************************************************
* OTHER UTILITY FUNCTIONS *
****************************************************************************/
char * linphone_timestamp_to_rfc3339_string(time_t timestamp);
static inline const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){
if (op==NULL) return (LinphoneErrorInfo*)sal_error_info_none();
return (const LinphoneErrorInfo*)sal_op_get_error_info(op);
}
/** Belle Sip-based objects need unique ids
*/

View file

@ -17,7 +17,7 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphonecore.h"
#include "sipsetup.h"
#include "lpconfig.h"
@ -31,7 +31,7 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){
MSList *elem;
int i;
if (!linphone_core_ready(lc)) return;
for(elem=lc->sip_conf.proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
linphone_proxy_config_write_to_config_file(lc->config,cfg,i);
@ -46,9 +46,10 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob
const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL;
const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL;
const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL;
const char *statistics_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "statistics_collector", NULL) : NULL;
const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL;
const char *contact_uri_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_uri_parameters", NULL) : NULL;
memset(obj, 0, sizeof(LinphoneProxyConfig));
obj->magic = linphone_proxy_config_magic;
obj->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600;
@ -59,8 +60,11 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob
obj->reg_identity = identity ? ms_strdup(identity) : NULL;
obj->reg_proxy = proxy ? ms_strdup(proxy) : NULL;
obj->reg_route = route ? ms_strdup(route) : NULL;
obj->statistics_collector = statistics_collector ? ms_strdup(statistics_collector) : NULL;
obj->send_statistics = lc ? lp_config_get_default_int(lc->config, "proxy", "send_statistics", 0) : 0;
obj->contact_params = contact_params ? ms_strdup(contact_params) : NULL;
obj->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL;
obj->publish_expires=-1;
}
/**
@ -85,7 +89,7 @@ LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) {
/**
* Destroys a proxy config.
*
*
* @note: LinphoneProxyConfig that have been removed from LinphoneCore with
* linphone_core_remove_proxy_config() must not be freed.
**/
@ -93,6 +97,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){
if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy);
if (obj->reg_identity!=NULL) ms_free(obj->reg_identity);
if (obj->reg_route!=NULL) ms_free(obj->reg_route);
if (obj->statistics_collector!=NULL) ms_free(obj->statistics_collector);
if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx);
if (obj->realm!=NULL) ms_free(obj->realm);
if (obj->type!=NULL) ms_free(obj->type);
@ -123,10 +128,10 @@ bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){
int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){
LinphoneAddress *addr=NULL;
char *modified=NULL;
if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy);
obj->reg_proxy=NULL;
if (server_addr!=NULL && strlen(server_addr)>0){
if (strstr(server_addr,"sip:")==NULL && strstr(server_addr,"sips:")==NULL){
modified=ms_strdup_printf("sip:%s",server_addr);
@ -149,7 +154,7 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *
/**
* Sets the user identity as a SIP address.
*
* This identity is normally formed with display name, username and domain, such
* This identity is normally formed with display name, username and domain, such
* as:
* Alice <sip:alice@example.net>
* The REGISTER messages will have from and to set to this identity.
@ -297,14 +302,14 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){
LinphoneAddress *ret=NULL;
LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy);
const char *host;
if (proxy==NULL) return NULL;
host=linphone_address_get_domain(proxy);
if (host!=NULL){
int localport = -1;
const char *localip = NULL;
LinphoneAddress *contact=linphone_address_new(obj->reg_identity);
linphone_address_clean(contact);
if (obj->contact_params) {
@ -374,7 +379,7 @@ void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj){
/**
* Sets a dialing prefix to be automatically prepended when inviting a number with
* Sets a dialing prefix to be automatically prepended when inviting a number with
* linphone_core_invite();
* This dialing prefix shall usually be the country code of the country where the user is living.
*
@ -390,7 +395,7 @@ void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char
/**
* Returns dialing prefix.
*
*
*
**/
const char *linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg){
return cfg->dial_prefix;
@ -413,6 +418,37 @@ void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t
bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg){
return cfg->dial_escape_plus;
}
void linphone_proxy_config_enable_statistics(LinphoneProxyConfig *cfg, bool_t val){
cfg->send_statistics = val;
}
bool_t linphone_proxy_config_send_statistics_enabled(LinphoneProxyConfig *cfg){
// ensure that collector address is set too!
return cfg->send_statistics && cfg->statistics_collector != NULL;
}
void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, const char *collector){
if (collector!=NULL && strlen(collector)>0){
LinphoneAddress *addr=linphone_address_new(collector);
if (!addr || linphone_address_get_username(addr)==NULL){
ms_warning("Invalid sip collector identity: %s",collector);
if (addr)
linphone_address_destroy(addr);
} else {
if (cfg->statistics_collector != NULL)
ms_free(cfg->statistics_collector);
cfg->statistics_collector = ms_strdup(collector);
linphone_address_destroy(addr);
}
}
}
const char *linphone_proxy_config_get_statistics_collector(const LinphoneProxyConfig *cfg){
return cfg->statistics_collector;
}
/*
* http://en.wikipedia.org/wiki/Telephone_numbering_plan
* http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe
@ -423,7 +459,7 @@ typedef struct dial_plan{
char ccc[8]; /*country calling code*/
int nnl; /*maximum national number length*/
const char * icp; /*international call prefix, ex: 00 in europe*/
}dial_plan_t;
/* TODO: fill with information for all countries over the world*/
@ -708,7 +744,7 @@ static void lookup_dial_plan(const char *ccc, dial_plan_t *plan){
static bool_t is_a_phone_number(const char *username){
const char *p;
for(p=username;*p!='\0';++p){
if (isdigit(*p) ||
if (isdigit(*p) ||
*p==' ' ||
*p=='.' ||
*p=='-' ||
@ -736,12 +772,12 @@ static char *flatten_number(const char *number){
static void replace_plus(const char *src, char *dest, size_t destlen, const char *icp){
int i=0;
if (icp && src[0]=='+' && (destlen>(i=strlen(icp))) ){
src++;
strcpy(dest,icp);
}
for(;(i<destlen-1) && *src!='\0';++i){
dest[i]=*src;
src++;
@ -756,7 +792,7 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const cha
char *flatten;
flatten=flatten_number(username);
ms_message("Flattened number is '%s'",flatten);
if (proxy->dial_prefix==NULL || proxy->dial_prefix[0]=='\0'){
/*no prefix configured, nothing else to do*/
strncpy(result,flatten,result_len);
@ -824,7 +860,7 @@ void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm
int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePresenceModel *presence){
int err=0;
if (proxy->state==LinphoneRegistrationOk || proxy->state==LinphoneRegistrationCleared){
if (proxy->publish_op==NULL){
proxy->publish_op=sal_op_new(proxy->lc->sal);
@ -837,7 +873,11 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePrese
sal_address_unref(addr);
}
}
err=sal_publish_presence(proxy->publish_op,NULL,NULL,proxy->expires,(SalPresenceModel *)presence);
err=sal_publish_presence(proxy->publish_op
,NULL
,NULL
,linphone_proxy_config_get_publish_expires(proxy)
,(SalPresenceModel *)presence);
}else proxy->send_publish=TRUE; /*otherwise do not send publish if registration is in progress, this will be done later*/
return err;
}
@ -1015,7 +1055,7 @@ void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *conf
lc->default_proxy=config;
if (linphone_core_ready(lc))
lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL));
}
}
void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index){
if (index<0) linphone_core_set_default_proxy(lc,NULL);
@ -1059,6 +1099,9 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
if (obj->reg_route!=NULL){
lp_config_set_string(config,key,"reg_route",obj->reg_route);
}
if (obj->statistics_collector!=NULL){
lp_config_set_string(config,key,"statistics_collector",obj->statistics_collector);
}
if (obj->reg_identity!=NULL){
lp_config_set_string(config,key,"reg_identity",obj->reg_identity);
}
@ -1072,6 +1115,7 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister);
lp_config_set_int(config,key,"publish",obj->publish);
lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus);
lp_config_set_int(config,key,"send_statistics",obj->send_statistics);
lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix);
lp_config_set_int(config,key,"privacy",obj->privacy);
}
@ -1085,7 +1129,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config
const char *proxy;
LinphoneProxyConfig *cfg;
char key[50];
sprintf(key,"proxy_%i",index);
if (!lp_config_has_section(config,key)){
@ -1094,29 +1138,33 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config
cfg=linphone_proxy_config_new();
identity=lp_config_get_string(config,key,"reg_identity",NULL);
identity=lp_config_get_string(config,key,"reg_identity",NULL);
proxy=lp_config_get_string(config,key,"reg_proxy",NULL);
linphone_proxy_config_set_identity(cfg,identity);
linphone_proxy_config_set_server_addr(cfg,proxy);
tmp=lp_config_get_string(config,key,"reg_route",NULL);
if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp);
tmp=lp_config_get_string(config,key,"statistics_collector",NULL);
if (tmp!=NULL) linphone_proxy_config_set_statistics_collector(cfg,tmp);
linphone_proxy_config_enable_statistics(cfg,lp_config_get_int(config,key,"send_statistics",0));
linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL));
linphone_proxy_config_set_contact_uri_parameters(cfg,lp_config_get_string(config,key,"contact_uri_parameters",NULL));
linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",lp_config_get_default_int(config,"proxy","reg_expires",600)));
linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0));
linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0));
linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",lp_config_get_default_int(config,"proxy","dial_escape_plus",0)));
linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",lp_config_get_default_string(config,"proxy","dial_prefix",NULL)));
tmp=lp_config_get_string(config,key,"type",NULL);
if (tmp!=NULL && strlen(tmp)>0)
if (tmp!=NULL && strlen(tmp)>0)
linphone_proxy_config_set_sip_setup(cfg,tmp);
linphone_proxy_config_set_privacy(cfg,lp_config_get_int(config,key,"privacy",lp_config_get_default_int(config,"proxy","privacy",LinphonePrivacyDefault)));
@ -1155,7 +1203,7 @@ static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){
ms_error("Could not retrieve proxy uri !");
}
}
}
SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg){
@ -1170,7 +1218,7 @@ static bool_t can_register(LinphoneProxyConfig *cfg){
LinphoneCore *lc=cfg->lc;
#ifdef BUILD_UPNP
if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp){
if(lc->sip_conf.register_only_when_upnp_is_ok &&
if(lc->sip_conf.register_only_when_upnp_is_ok &&
(lc->upnp == NULL || !linphone_upnp_context_is_ready_for_register(lc->upnp))) {
return FALSE;
}
@ -1326,7 +1374,7 @@ void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) {
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){
LinphoneCore *lc=cfg->lc;
bool_t update_friends=FALSE;
if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/
ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg,
linphone_proxy_config_get_identity(cfg),
@ -1337,7 +1385,7 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
|| (state!=LinphoneRegistrationOk && cfg->state==LinphoneRegistrationOk);
}
cfg->state=state;
if (update_friends){
linphone_core_update_friends_subscriptions(lc,cfg,TRUE);
}
@ -1413,3 +1461,14 @@ void linphone_proxy_config_set_privacy(LinphoneProxyConfig *params, LinphonePriv
LinphonePrivacyMask linphone_proxy_config_get_privacy(const LinphoneProxyConfig *params) {
return params->privacy;
}
void linphone_proxy_config_set_publish_expires(LinphoneProxyConfig *obj, int expires) {
obj->publish_expires=expires;
}
int linphone_proxy_config_get_publish_expires(const LinphoneProxyConfig *obj) {
if (obj->publish_expires<0) {
return obj->expires; /*default value is same as register*/
} else {
return obj->publish_expires;
}
}

527
coreapi/quality_reporting.c Normal file
View file

@ -0,0 +1,527 @@
/*
linphone
Copyright (C) 2014 - Belledonne Communications, Grenoble, France
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "linphonecore.h"
#include "private.h"
#include "sal/sal.h"
#include "ortp/rtpsession.h"
#include <math.h>
/***************************************************************************
* TODO / REMINDER LIST
****************************************************************************/
/*For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000).
moslq == moscq
video: what happens if doing stop/resume?
one time value: average? worst value?
rlq value: need algo to compute it*/
/***************************************************************************
* END OF TODO / REMINDER LIST
****************************************************************************/
#define STR_REASSIGN(dest, src) {\
if (dest != NULL) \
ms_free(dest); \
dest = src; \
}
/*since printf family functions are LOCALE dependent, float separator may differ
depending on the user's locale (LC_NUMERIC environment var).*/
static char * float_to_one_decimal_string(float f) {
float rounded_f = floorf(f * 10 + .5f) / 10;
int floor_part = (int) rounded_f;
int one_decimal_part = floorf (10 * (rounded_f - floor_part) + .5f);
return ms_strdup_printf("%d.%d", floor_part, one_decimal_part);
}
static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offset, const char *fmt, va_list args) {
belle_sip_error_code ret;
size_t prevoffset = *offset;
#ifndef WIN32
va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
va_copy(cap,args);
ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, cap);
va_end(cap);
#else
ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, args);
#endif
/*if we are out of memory, we add some size to buffer*/
if (ret == BELLE_SIP_BUFFER_OVERFLOW) {
/*some compilers complain that size_t cannot be formatted as unsigned long, hence forcing cast*/
ms_warning("Buffer was too small to contain the whole report - doubling its size from %lu to %lu",
(unsigned long)*buff_size, (unsigned long)2 * *buff_size);
*buff_size += 2048;
*buff = (char *) ms_realloc(*buff, *buff_size);
*offset = prevoffset;
/*recall myself since we did not write all things into the buffer but
only a part of it*/
append_to_buffer_valist(buff, buff_size, offset, fmt, args);
}
}
static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
append_to_buffer_valist(buff, buff_size, offset, fmt, args);
va_end(args);
}
#define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg)
#define APPEND_IF_NUM_IN_RANGE(buffer, size, offset, fmt, arg, inf, sup) if (inf <= arg && arg <= sup) append_to_buffer(buffer, size, offset, fmt, arg)
#define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (cond) append_to_buffer(buffer, size, offset, fmt, arg)
#define IF_NUM_IN_RANGE(num, inf, sup, statement) if (inf <= num && num <= sup) statement
static bool_t are_metrics_filled(const reporting_content_metrics_t rm) {
IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, return TRUE);
IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, return TRUE);
IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, return TRUE);
IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, return TRUE);
/*since these are same values than local ones, do not check them*/
/*if (rm.session_description.payload_type != -1) return TRUE;*/
/*if (rm.session_description.payload_desc != NULL) return TRUE;*/
/*if (rm.session_description.sample_rate != -1) return TRUE;*/
if (rm.session_description.frame_duration != -1) return TRUE;
/*if (rm.session_description.fmtp != NULL) return TRUE;*/
if (rm.session_description.packet_loss_concealment != -1) return TRUE;
IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, return TRUE);
IF_NUM_IN_RANGE(rm.jitter_buffer.nominal, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.jitter_buffer.max, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, return TRUE);
IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, return TRUE);
if (rm.signal.level != 127) return TRUE;
if (rm.signal.noise_level != 127) return TRUE;
IF_NUM_IN_RANGE(rm.quality_estimates.rlq, 1, 120, return TRUE);
IF_NUM_IN_RANGE(rm.quality_estimates.rcq, 1, 120, return TRUE);
return FALSE;
}
static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t rm) {
char * timestamps_start_str = NULL;
char * timestamps_stop_str = NULL;
char * network_packet_loss_rate_str = NULL;
char * jitter_buffer_discard_rate_str = NULL;
/*char * gap_loss_density_str = NULL;*/
char * moslq_str = NULL;
char * moscq_str = NULL;
if (rm.timestamps.start > 0)
timestamps_start_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.start);
if (rm.timestamps.stop > 0)
timestamps_stop_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.stop);
IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, network_packet_loss_rate_str = float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate / 256));
IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate / 256));
/*IF_NUM_IN_RANGE(rm.burst_gap_loss.gap_loss_density, 0, 10, gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density));*/
IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq));
IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq));
append_to_buffer(buffer, size, offset, "Timestamps:");
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " START=%s", timestamps_start_str);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " STOP=%s", timestamps_stop_str);
append_to_buffer(buffer, size, offset, "\r\nSessionDesc:");
APPEND_IF(buffer, size, offset, " PT=%d", rm.session_description.payload_type, rm.session_description.payload_type != -1);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " PD=%s", rm.session_description.payload_desc);
APPEND_IF(buffer, size, offset, " SR=%d", rm.session_description.sample_rate, rm.session_description.sample_rate != -1);
APPEND_IF(buffer, size, offset, " FD=%d", rm.session_description.frame_duration, rm.session_description.frame_duration != -1);
/*append_to_buffer(buffer, size, offset, " FO=%d", rm.session_description.frame_ocets);*/
/*append_to_buffer(buffer, size, offset, " FPP=%d", rm.session_description.frames_per_sec);*/
/*append_to_buffer(buffer, size, offset, " PPS=%d", rm.session_description.packets_per_sec);*/
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp);
APPEND_IF(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment, rm.session_description.packet_loss_concealment != -1);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " SSUP=%s", rm.session_description.silence_suppression_state);*/
append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:");
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3);
/*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15);*/
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535);
append_to_buffer(buffer, size, offset, "\r\nPacketLoss:");
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str);
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str);
/*append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:");*/
/* append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density);*/
/* append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration);*/
/* APPEND_IF_NOT_NULL_STR(buffer, size, offset, " GLD=%s", gap_loss_density_str);*/
/* append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration);*/
/* append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold);*/
append_to_buffer(buffer, size, offset, "\r\nDelay:");
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535);
/*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay, 0, 65535);*/
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535);
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter, 0, 65535);
append_to_buffer(buffer, size, offset, "\r\nSignal:");
APPEND_IF(buffer, size, offset, " SL=%d", rm.signal.level, rm.signal.level != 127);
APPEND_IF(buffer, size, offset, " NL=%d", rm.signal.noise_level, rm.signal.noise_level != 127);
/*append_to_buffer(buffer, size, offset, " RERL=%d", rm.signal.residual_echo_return_loss);*/
append_to_buffer(buffer, size, offset, "\r\nQualityEst:");
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq, 1, 120);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RLQEstAlg=%s", rm.quality_estimates.rlqestalg);*/
APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq, 1, 120);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RCQEstAlgo=%s", rm.quality_estimates.rcqestalg);*/
/*append_to_buffer(buffer, size, offset, " EXTRI=%d", rm.quality_estimates.extri);*/
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtRIEstAlg=%s", rm.quality_estimates.extriestalg);*/
/*append_to_buffer(buffer, size, offset, " EXTRO=%d", rm.quality_estimates.extro);*/
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtROEstAlg=%s", rm.quality_estimates.extroutestalg);*/
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQ=%s", moslq_str);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQEstAlgo=%s", rm.quality_estimates.moslqestalg);*/
APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str);
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQEstAlgo=%s", rm.quality_estimates.moscqestalg);*/
/*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " QoEEstAlg=%s", rm.quality_estimates.qoestalg);*/
append_to_buffer(buffer, size, offset, "\r\n");
ms_free(timestamps_start_str);
ms_free(timestamps_stop_str);
ms_free(network_packet_loss_rate_str);
ms_free(jitter_buffer_discard_rate_str);
/*ms_free(gap_loss_density_str);*/
ms_free(moslq_str);
ms_free(moscq_str);
}
static void reporting_publish(const LinphoneCall* call, const reporting_session_report_t * report) {
LinphoneContent content = {0};
LinphoneAddress *addr;
int expires = -1;
size_t offset = 0;
size_t size = 2048;
char * buffer;
/*if the call was hung up too early, we might have invalid IPs information
in that case, we abort the report since it's not useful data*/
if (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0
|| report->info.remote_addr.ip == NULL || strlen(report->info.remote_addr.ip) == 0) {
ms_warning("The call was hang up too early (duration: %d sec) and IP could "
"not be retrieved so dropping this report", linphone_call_get_duration(call));
return;
}
buffer = (char *) ms_malloc(size);
content.type = ms_strdup("application");
content.subtype = ms_strdup("vq-rtcpxr");
append_to_buffer(&buffer, &size, &offset, "VQSessionReport: CallTerm\r\n");
append_to_buffer(&buffer, &size, &offset, "CallID: %s\r\n", report->info.call_id);
append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_id);
append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_id);
append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", report->info.orig_id);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_group);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_group);
append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr);
append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc);
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr);
append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n");
append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics);
if (are_metrics_filled(report->remote_metrics)) {
append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n");
append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics);
}
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id);
content.data = buffer;
content.size = strlen((char*)content.data);
addr = linphone_address_new(call->dest_proxy->statistics_collector);
if (addr != NULL) {
linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content);
linphone_address_destroy(addr);
} else {
ms_warning("Asked to submit reporting statistics but no collector address found");
}
linphone_content_uninit(&content);
}
static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) {
int count;
if (smd != NULL) {
for (count = 0; count < smd->n_total_streams; ++count) {
if (smd->streams[count].type == sal_stream_type) {
return &smd->streams[count];
}
}
}
if (smd == NULL || count == smd->n_total_streams) {
ms_warning("Could not find the associated stream of type %d", sal_stream_type);
}
return NULL;
}
static void reporting_update_ip(LinphoneCall * call, int stats_type) {
SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo;
if (call->log->reports[stats_type] != NULL) {
const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type);
const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_type);
/*local info are always up-to-date and correct*/
if (local_desc != NULL) {
call->log->reports[stats_type]->info.local_addr.port = local_desc->rtp_port;
STR_REASSIGN(call->log->reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr));
}
if (remote_desc != NULL) {
/*port is always stored in stream description struct*/
call->log->reports[stats_type]->info.remote_addr.port = remote_desc->rtp_port;
/*for IP it can be not set if we are using a direct route*/
if (remote_desc->rtp_addr != NULL && strlen(remote_desc->rtp_addr) > 0) {
STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr));
} else {
STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr));
}
}
}
}
static bool_t reporting_enabled(const LinphoneCall * call) {
return (call->dest_proxy != NULL && linphone_proxy_config_send_statistics_enabled(call->dest_proxy));
}
void linphone_reporting_update_ip(LinphoneCall * call) {
/*This function can be called in two different cases:
- 1) at start when call is starting, remote ip/port info might be the proxy ones to which callee is registered
- 2) later, if we found a direct route between caller and callee with ICE/Stun, ip/port are updated for the direct route access*/
if (! reporting_enabled(call))
return;
reporting_update_ip(call, LINPHONE_CALL_STATS_AUDIO);
if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) {
reporting_update_ip(call, LINPHONE_CALL_STATS_VIDEO);
}
}
void linphone_reporting_update(LinphoneCall * call, int stats_type) {
reporting_session_report_t * report = call->log->reports[stats_type];
MediaStream * stream = NULL;
const PayloadType * local_payload = NULL;
const PayloadType * remote_payload = NULL;
const LinphoneCallParams * current_params = linphone_call_get_current_params(call);
if (! reporting_enabled(call))
return;
STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id));
STR_REASSIGN(report->info.local_group, ms_strdup_printf("linphone-%s-%s-%s", (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"),
linphone_core_get_user_agent_name(), report->info.call_id));
STR_REASSIGN(report->info.remote_group, ms_strdup_printf("linphone-%s-%s-%s", (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"),
linphone_call_get_remote_user_agent(call), report->info.call_id));
if (call->dir == LinphoneCallIncoming) {
STR_REASSIGN(report->info.remote_id, linphone_address_as_string(call->log->from));
STR_REASSIGN(report->info.local_id, linphone_address_as_string(call->log->to));
STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_id));
} else {
STR_REASSIGN(report->info.remote_id, linphone_address_as_string(call->log->to));
STR_REASSIGN(report->info.local_id, linphone_address_as_string(call->log->from));
STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_id));
}
STR_REASSIGN(report->dialog_id, sal_op_get_dialog_id(call->op));
report->local_metrics.timestamps.start = call->log->start_date_time;
report->local_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call);
/*we use same timestamps for remote too*/
report->remote_metrics.timestamps.start = call->log->start_date_time;
report->remote_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call);
/*yet we use the same payload config for local and remote, since this is the largest use case*/
if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) {
stream = &call->audiostream->ms;
local_payload = linphone_call_params_get_used_audio_codec(current_params);
remote_payload = local_payload;
} else if (stats_type == LINPHONE_CALL_STATS_VIDEO && call->videostream != NULL) {
stream = &call->videostream->ms;
local_payload = linphone_call_params_get_used_video_codec(current_params);
remote_payload = local_payload;
}
if (stream != NULL) {
RtpSession * session = stream->sessions.rtp_session;
report->info.local_addr.ssrc = rtp_session_get_send_ssrc(session);
report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session);
}
if (local_payload != NULL) {
report->local_metrics.session_description.payload_type = local_payload->type;
STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type));
report->local_metrics.session_description.sample_rate = local_payload->clock_rate;
STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp));
}
if (remote_payload != NULL) {
report->remote_metrics.session_description.payload_type = remote_payload->type;
STR_REASSIGN(report->remote_metrics.session_description.payload_desc, ms_strdup(remote_payload->mime_type));
report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate;
STR_REASSIGN(report->remote_metrics.session_description.fmtp, ms_strdup(remote_payload->recv_fmtp));
}
}
void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) {
reporting_session_report_t * report = call->log->reports[stats_type];
reporting_content_metrics_t * metrics = NULL;
LinphoneCallStats stats = call->stats[stats_type];
mblk_t *block = NULL;
if (! reporting_enabled(call))
return;
if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) {
metrics = &report->remote_metrics;
if (rtcp_is_XR(stats.received_rtcp) == TRUE) {
block = stats.received_rtcp;
}
} else if (stats.updated == LINPHONE_CALL_STATS_SENT_RTCP_UPDATE) {
metrics = &report->local_metrics;
if (rtcp_is_XR(stats.sent_rtcp) == TRUE) {
block = stats.sent_rtcp;
}
}
if (block != NULL) {
switch (rtcp_XR_get_block_type(block)) {
case RTCP_XR_VOIP_METRICS: {
uint8_t config;
metrics->quality_estimates.rcq = rtcp_XR_voip_metrics_get_r_factor(block);
metrics->quality_estimates.moslq = rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f;
metrics->quality_estimates.moscq = rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f;
metrics->jitter_buffer.nominal = rtcp_XR_voip_metrics_get_jb_nominal(block);
metrics->jitter_buffer.max = rtcp_XR_voip_metrics_get_jb_maximum(block);
metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(block);
metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(block);
metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(block);
config = rtcp_XR_voip_metrics_get_rx_config(block);
metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3;
metrics->jitter_buffer.adaptive = (config >> 4) & 0x3;
break;
} default: {
break;
}
}
}
}
void linphone_reporting_publish(LinphoneCall* call) {
if (! reporting_enabled(call))
return;
if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) {
reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO]);
}
if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL
&& linphone_call_params_video_enabled(linphone_call_get_current_params(call))) {
reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO]);
}
}
reporting_session_report_t * linphone_reporting_new() {
int i;
reporting_session_report_t * rm = ms_new0(reporting_session_report_t,1);
reporting_content_metrics_t * metrics[2] = {&rm->local_metrics, &rm->remote_metrics};
for (i = 0; i < 2; i++) {
metrics[i]->session_description.payload_type = -1;
metrics[i]->session_description.sample_rate = -1;
metrics[i]->session_description.frame_duration = -1;
metrics[i]->packet_loss.network_packet_loss_rate = -1;
metrics[i]->packet_loss.jitter_buffer_discard_rate = -1;
metrics[i]->session_description.packet_loss_concealment = -1;
metrics[i]->jitter_buffer.adaptive = -1;
/*metrics[i]->jitter_buffer.rate = -1;*/
metrics[i]->jitter_buffer.nominal = -1;
metrics[i]->jitter_buffer.max = -1;
metrics[i]->jitter_buffer.abs_max = -1;
metrics[i]->delay.round_trip_delay = -1;
metrics[i]->delay.end_system_delay = -1;
/*metrics[i]->delay.one_way_delay = -1;*/
metrics[i]->delay.symm_one_way_delay = -1;
metrics[i]->delay.interarrival_jitter = -1;
metrics[i]->delay.mean_abs_jitter = -1;
metrics[i]->signal.level = 127;
metrics[i]->signal.noise_level = 127;
}
return rm;
}
void linphone_reporting_destroy(reporting_session_report_t * report) {
if (report->info.call_id != NULL) ms_free(report->info.call_id);
if (report->info.local_id != NULL) ms_free(report->info.local_id);
if (report->info.remote_id != NULL) ms_free(report->info.remote_id);
if (report->info.orig_id != NULL) ms_free(report->info.orig_id);
if (report->info.local_addr.ip != NULL) ms_free(report->info.local_addr.ip);
if (report->info.remote_addr.ip != NULL) ms_free(report->info.remote_addr.ip);
if (report->info.local_group != NULL) ms_free(report->info.local_group);
if (report->info.remote_group != NULL) ms_free(report->info.remote_group);
if (report->info.local_mac_addr != NULL) ms_free(report->info.local_mac_addr);
if (report->info.remote_mac_addr != NULL) ms_free(report->info.remote_mac_addr);
if (report->dialog_id != NULL) ms_free(report->dialog_id);
if (report->local_metrics.session_description.fmtp != NULL) ms_free(report->local_metrics.session_description.fmtp);
if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc);
if (report->remote_metrics.session_description.fmtp != NULL) ms_free(report->remote_metrics.session_description.fmtp);
if (report->remote_metrics.session_description.payload_desc != NULL) ms_free(report->remote_metrics.session_description.payload_desc);
ms_free(report);
}

164
coreapi/quality_reporting.h Normal file
View file

@ -0,0 +1,164 @@
/*
linphone
Copyright (C) 2014 - Belledonne Communications, Grenoble, France
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef quality_reporting_h
#define quality_reporting_h
#include "linphonecore.h"
#ifdef __cplusplus
extern "C"{
#endif
/**
* Linphone quality report sub object storing address related information (ip / port / MAC).
*/
typedef struct reporting_addr {
char * ip;
int port;
uint32_t ssrc;
} reporting_addr_t;
/**
* Linphone quality report sub object storing media metrics information as required by RFC035.
*/
typedef struct reporting_content_metrics {
// timestamps - mandatory
struct {
time_t start;
time_t stop;
} timestamps;
// session description - optional
struct {
int payload_type;
char * payload_desc; // mime type
int sample_rate; // clock rate
int frame_duration; // to check (ptime?) - audio only
char * fmtp;
int packet_loss_concealment; // in voip metrics - audio only
} session_description;
// jitter buffet - optional
struct {
int adaptive; // constant
int nominal; // no may vary during the call <- average? worst score?
int max; // no may vary during the call <- average?
int abs_max; // constant
} jitter_buffer;
// packet loss - optional
struct {
float network_packet_loss_rate;
float jitter_buffer_discard_rate;
} packet_loss;
// delay - optional
struct {
int round_trip_delay; // no - vary
int end_system_delay; // no - not implemented yet
int symm_one_way_delay; // no - vary (depends on round_trip_delay) + not implemented (depends on end_system_delay)
int interarrival_jitter; // no - not implemented yet
int mean_abs_jitter; // to check
} delay;
// signal - optional
struct {
int level; // no - vary
int noise_level; // no - vary
} signal;
// quality estimates - optional
struct {
int rlq; // linked to moslq - in [0..120]
int rcq; //voip metrics R factor - no - vary or avg in [0..120]
float moslq; // no - vary or avg - voip metrics - in [0..4.9]
float moscq; // no - vary or avg - voip metrics - in [0..4.9]
} quality_estimates;
} reporting_content_metrics_t;
/**
* Linphone quality report main object created by function linphone_reporting_new().
* It contains all fields required by RFC6035
*/
typedef struct reporting_session_report {
struct {
char * call_id;
char * local_id;
char * remote_id;
char * orig_id;
reporting_addr_t local_addr;
reporting_addr_t remote_addr;
char * local_group;
char * remote_group;
char * local_mac_addr; // optional
char * remote_mac_addr; // optional
} info;
reporting_content_metrics_t local_metrics;
reporting_content_metrics_t remote_metrics; // optional
char * dialog_id; // optional
} reporting_session_report_t;
reporting_session_report_t * linphone_reporting_new();
void linphone_reporting_destroy(reporting_session_report_t * report);
/**
* Fill media information about a given call. This function must be called before
* stopping the media stream.
* @param call #LinphoneCall object to consider
* @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO)
*
*/
void linphone_reporting_update(LinphoneCall * call, int stats_type);
/**
* Fill IP information about a given call. This function must be called each
* time state is 'LinphoneCallStreamsRunning' since IP might be updated (if we
* found a direct route between caller and callee for example).
* @param call #LinphoneCall object to consider
*
*/
void linphone_reporting_update_ip(LinphoneCall * call);
/**
* Publish the report on the call end.
* @param call #LinphoneCall object to consider
*
*/
void linphone_reporting_publish(LinphoneCall* call);
/**
* Update publish report data with fresh RTCP stats, if needed.
* @param call #LinphoneCall object to consider
* @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO)
*
*/
void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -57,11 +57,15 @@ static int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char*
FILE* f = fopen(file_path, "r");
if( f ){
long fsize;
char* provisioning;
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fsize = ftell(f);
fseek(f, 0, SEEK_SET);
char* provisioning = ms_malloc(fsize + 1);
provisioning = ms_malloc(fsize + 1);
provisioning[fsize]='\0';
if (fread(provisioning, fsize, 1, f)==0){
ms_error("Could not read xml provisioning file from %s",file_path);
status=-1;

View file

@ -17,9 +17,9 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**
/**
This header files defines the Signaling Abstraction Layer.
The purpose of this layer is too allow experiment different call signaling
The purpose of this layer is too allow experiment different call signaling
protocols and implementations under linphone, for example SIP, JINGLE...
**/
#ifdef HAVE_CONFIG_H
@ -39,7 +39,7 @@ const char* sal_transport_to_string(SalTransport transport) {
default: {
ms_fatal("Unexpected transport [%i]",transport);
return NULL;
}
}
}
}
@ -82,7 +82,7 @@ void sal_media_description_unref(SalMediaDescription *md){
}
SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
SalMediaProto proto, SalStreamType type){
SalMediaProto proto, SalStreamType type){
int i;
for(i=0;i<md->n_active_streams;++i){
SalStreamDescription *ss=&md->streams[i];
@ -161,7 +161,7 @@ static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){
*/
/*
if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
!fmtp_equals(p1->send_fmtp,p2->send_fmtp))
!fmtp_equals(p1->send_fmtp,p2->send_fmtp))
return FALSE;
*/
return TRUE;
@ -372,6 +372,14 @@ const char *sal_op_get_network_origin(const SalOp *op){
const char* sal_op_get_call_id(const SalOp *op) {
return ((SalOpBase*)op)->call_id;
}
char* sal_op_get_dialog_id(const SalOp *op) {
if (op->dialog != NULL) {
return ms_strdup_printf("%s;to-tag=%s;from-tag=%s", ((SalOpBase*)op)->call_id,
belle_sip_dialog_get_remote_tag(op->dialog), belle_sip_dialog_get_local_tag(op->dialog));
}
return NULL;
}
void __sal_op_init(SalOp *b, Sal *sal){
memset(b,0,sizeof(SalOpBase));
((SalOpBase*)b)->root=sal;
@ -401,17 +409,17 @@ void __sal_op_free(SalOp *op){
sal_address_destroy(b->to_address);
b->to_address=NULL;
}
if (b->service_route){
sal_address_destroy(b->service_route);
b->service_route=NULL;
}
if (b->origin_address){
sal_address_destroy(b->origin_address);
b->origin_address=NULL;
}
if (b->from) {
ms_free(b->from);
b->from=NULL;
@ -616,7 +624,7 @@ static int line_get_value(const char *input, const char *key, char *value, size_
int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size){
int read=0;
do{
if (line_get_value(data,key,value,value_size,&read))
return TRUE;
@ -626,7 +634,7 @@ int sal_lines_get_value(const char *data, const char *key, char *value, size_t v
}
int sal_body_has_type(const SalBody *body, const char *type, const char *subtype){
return body->type && body->subtype
return body->type && body->subtype
&& strcmp(body->type,type)==0
&& strcmp(body->subtype,subtype)==0;
}

View file

@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define UPNP_ADD_MAX_RETRY 4
#define UPNP_REMOVE_MAX_RETRY 4
#define UPNP_SECTION_NAME "uPnP"
#define UPNP_CORE_READY_CHECK 1
#define UPNP_CORE_READY_CHECK 1
#define UPNP_CORE_RETRY_DELAY 10
#define UPNP_CALL_RETRY_DELAY 3
#define UPNP_UUID_LEN 128
@ -79,7 +79,7 @@ struct _UpnpContext {
ms_mutex_t mutex;
ms_cond_t empty_cond;
time_t last_ready_check;
LinphoneUpnpState last_ready_state;
};
@ -91,13 +91,13 @@ bool_t linphone_upnp_is_blacklisted(UpnpContext *ctx);
UpnpPortBinding *linphone_upnp_port_binding_new();
UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port);
UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port);
UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port);
UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port);
void linphone_upnp_port_binding_set_device_id(UpnpPortBinding *port, const char * device_id);
bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2);
UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port);
UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port);
void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay);
void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay);
void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port);
void linphone_upnp_port_binding_release(UpnpPortBinding *port);
void linphone_upnp_update_config(UpnpContext *lupnp);
@ -108,7 +108,7 @@ MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc, const cha
void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
// uPnP
// uPnP
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry);
int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry);
@ -141,7 +141,7 @@ char * linphone_upnp_format_device_id(const char *device_id) {
char *ret = NULL;
char *tmp;
char tchar;
bool_t copy;
bool_t copy;
if(device_id == NULL) {
return ret;
}
@ -366,7 +366,7 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
linphone_core_remove_iterate_hook(lupnp->lc, linphone_core_upnp_hook, lupnp);
ms_mutex_lock(&lupnp->mutex);
if(lupnp->lc->network_reachable) {
/* Send port binding removes */
if(lupnp->sip_udp != NULL) {
@ -391,7 +391,7 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
upnp_igd_destroy(lupnp->upnp_igd_ctxt);
lupnp->upnp_igd_ctxt = NULL;
}
/* No more multi threading here */
/* Run one more time configuration update and proxy */
@ -419,7 +419,7 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
lupnp->removing_configs = ms_list_free(lupnp->removing_configs);
ms_list_for_each(lupnp->pending_bindings,(void (*)(void*))linphone_upnp_port_binding_release);
lupnp->pending_bindings = ms_list_free(lupnp->pending_bindings);
ms_mutex_destroy(&lupnp->mutex);
ms_cond_destroy(&lupnp->empty_cond);
@ -439,17 +439,17 @@ LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *lupnp) {
bool_t _linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) {
bool_t ready = TRUE;
// 1 Check global uPnP state
ready = (lupnp->state == LinphoneUpnpStateOk);
// 2 Check external ip address
if(ready) {
if (upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt) == NULL) {
ready = FALSE;
}
}
// 3 Check sip ports bindings
if(ready) {
if(lupnp->sip_udp != NULL) {
@ -468,7 +468,7 @@ bool_t _linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) {
ready = FALSE;
}
}
return ready;
}
@ -486,7 +486,7 @@ int linphone_upnp_context_get_external_port(UpnpContext *lupnp) {
int port = -1;
if(lupnp != NULL) {
ms_mutex_lock(&lupnp->mutex);
if(lupnp->sip_udp != NULL) {
if(lupnp->sip_udp->state == LinphoneUpnpStateOk) {
port = lupnp->sip_udp->external_port;
@ -500,7 +500,7 @@ int linphone_upnp_context_get_external_port(UpnpContext *lupnp) {
port = lupnp->sip_tls->external_port;
}
}
ms_mutex_unlock(&lupnp->mutex);
}
return port;
@ -508,7 +508,7 @@ int linphone_upnp_context_get_external_port(UpnpContext *lupnp) {
bool_t linphone_upnp_is_blacklisted(UpnpContext *lupnp) {
const char * device_model_name = upnp_igd_get_device_model_name(lupnp->upnp_igd_ctxt);
const char * device_model_number = upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt);
const char * device_model_number = upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt);
const char * blacklist = lp_config_get_string(lupnp->lc->config, "net", "upnp_blacklist", NULL);
bool_t blacklisted = FALSE;
char *str;
@ -521,7 +521,7 @@ bool_t linphone_upnp_is_blacklisted(UpnpContext *lupnp) {
return FALSE;
}
// Find in the list
// Find in the list
str = strdup(blacklist);
pch = strtok(str, ";");
while (pch != NULL && !blacklisted) {
@ -537,7 +537,7 @@ bool_t linphone_upnp_is_blacklisted(UpnpContext *lupnp) {
if(model_number == NULL || strcmp(model_number, device_model_number) == 0) {
blacklisted = TRUE;
}
}
}
pch = strtok(NULL, ";");
}
free(str);
@ -563,7 +563,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind
upnp_igd_port_mapping mapping;
char description[128];
int ret;
if(lupnp->state != LinphoneUpnpStateOk) {
return -2;
}
@ -587,7 +587,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind
return 0;
}
}
// No retry if specified
if(port->retry != 0 && !retry) {
return -1;
@ -626,7 +626,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) {
upnp_igd_port_mapping mapping;
int ret;
if(lupnp->state != LinphoneUpnpStateOk) {
return -2;
}
@ -649,7 +649,7 @@ int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortB
return 0;
}
}
// No retry if specified
if(port->retry != 0 && !retry) {
return 1;
@ -697,19 +697,19 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
/*
* Audio part
*/
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp,
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp,
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtp_port:0, UPNP_CALL_RETRY_DELAY);
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp,
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp,
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtcp_port:0, UPNP_CALL_RETRY_DELAY);
/*
* Video part
*/
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp,
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp,
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtp_port:0, UPNP_CALL_RETRY_DELAY);
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp,
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp,
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtcp_port:0, UPNP_CALL_RETRY_DELAY);
}
@ -756,16 +756,16 @@ void linphone_upnp_update_stream_state(UpnpStream *stream) {
if((stream->rtp == NULL || stream->rtp->state == LinphoneUpnpStateOk || stream->rtp->state == LinphoneUpnpStateIdle) &&
(stream->rtcp == NULL || stream->rtcp->state == LinphoneUpnpStateOk || stream->rtcp->state == LinphoneUpnpStateIdle)) {
stream->state = LinphoneUpnpStateOk;
} else if((stream->rtp != NULL &&
(stream->rtp->state == LinphoneUpnpStateAdding || stream->rtp->state == LinphoneUpnpStateRemoving)) ||
(stream->rtcp != NULL &&
(stream->rtcp->state == LinphoneUpnpStateAdding || stream->rtcp->state == LinphoneUpnpStateRemoving))) {
} else if((stream->rtp != NULL &&
(stream->rtp->state == LinphoneUpnpStateAdding || stream->rtp->state == LinphoneUpnpStateRemoving)) ||
(stream->rtcp != NULL &&
(stream->rtcp->state == LinphoneUpnpStateAdding || stream->rtcp->state == LinphoneUpnpStateRemoving))) {
stream->state = LinphoneUpnpStatePending;
} else if((stream->rtp != NULL && stream->rtp->state == LinphoneUpnpStateKo) ||
(stream->rtcp != NULL && stream->rtcp->state == LinphoneUpnpStateKo)) {
stream->state = LinphoneUpnpStateKo;
} else {
ms_error("Invalid stream %p state", stream);
ms_error("Invalid stream %p state", stream);
}
}
@ -799,7 +799,7 @@ int linphone_upnp_call_process(LinphoneCall *call) {
* Update stat
*/
linphone_core_update_upnp_state_in_call_stats(call);
/*
* Update session state
*/
@ -820,7 +820,7 @@ int linphone_upnp_call_process(LinphoneCall *call) {
}
ms_mutex_unlock(&lupnp->mutex);
/* When change is done proceed update */
if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo &&
(newState == LinphoneUpnpStateOk || newState == LinphoneUpnpStateKo)) {
@ -865,9 +865,9 @@ void linphone_upnp_update(UpnpContext *lupnp) {
UpnpPortBinding *port_mapping, *port_mapping2;
ms_message("uPnP IGD: Name:%s", linphone_core_upnp_get_charptr_null(upnp_igd_get_device_name(lupnp->upnp_igd_ctxt)));
ms_message("uPnP IGD: Device:%s %s",
linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_name(lupnp->upnp_igd_ctxt)),
linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt)));
ms_message("uPnP IGD: Device:%s %s",
linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_name(lupnp->upnp_igd_ctxt)),
linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt)));
ms_message("uPnP IGD: Refresh mappings");
if(lupnp->sip_udp != NULL) {
@ -939,7 +939,7 @@ void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **por
if(*port_mapping == NULL) {
*port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, port);
}
// Get addresses
local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
@ -972,7 +972,7 @@ void linphone_upnp_update_config(UpnpContext* lupnp) {
char key[64];
const MSList *item;
UpnpPortBinding *port_mapping;
/* Add configs */
for(item = lupnp->adding_configs;item!=NULL;item=item->next) {
port_mapping = (UpnpPortBinding *)item->data;
@ -1006,7 +1006,7 @@ void linphone_upnp_update_proxy(UpnpContext* lupnp, bool_t force) {
LinphoneUpnpState ready_state;
const MSList *item;
time_t now = (force)? (lupnp->last_ready_check + UPNP_CORE_READY_CHECK) : time(NULL);
/* Refresh registers if we are ready */
if(now - lupnp->last_ready_check >= UPNP_CORE_READY_CHECK) {
lupnp->last_ready_check = now;
@ -1046,7 +1046,7 @@ bool_t linphone_core_upnp_hook(void *data) {
linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tls, UPNP_IGD_IP_PROTOCOL_TCP, transport.tls_port, UPNP_CORE_RETRY_DELAY);
}
linphone_upnp_update_proxy(lupnp, FALSE);
linphone_upnp_update_proxy(lupnp, FALSE);
linphone_upnp_update_config(lupnp);
ms_mutex_unlock(&lupnp->mutex);
@ -1090,7 +1090,7 @@ UpnpPortBinding *linphone_upnp_port_binding_new() {
port = ms_new0(UpnpPortBinding,1);
ms_mutex_init(&port->mutex, NULL);
port->state = LinphoneUpnpStateIdle;
port->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
port->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
port->device_id = NULL;
port->local_addr[0] = '\0';
port->local_port = -1;
@ -1114,20 +1114,20 @@ UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_prot
UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port) {
UpnpPortBinding *tmp_binding;
UpnpPortBinding *end_binding;
// Seek an binding with same protocol and local port
end_binding = linphone_upnp_port_binding_new_with_parameters(protocol, local_port, -1);
tmp_binding = linphone_upnp_port_binding_equivalent_in_list(list, end_binding);
// Must be not attached to any struct
// Must be not attached to any struct
if(tmp_binding != NULL && tmp_binding->ref == 1) {
linphone_upnp_port_binding_release(end_binding);
end_binding = linphone_upnp_port_binding_retain(tmp_binding);
} else {
end_binding->external_port = external_port;
}
return end_binding;
}
return end_binding;
}
UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port) {
UpnpPortBinding *new_port = NULL;
@ -1174,8 +1174,8 @@ void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBi
// Return true if the binding are equivalent. (Note external_port == -1 means "don't care")
bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2) {
return port1->protocol == port2->protocol &&
port1->local_port == port2->local_port &&
(port1->external_port == -1 || port2->external_port == -1 || port1->external_port == port2->external_port);
port1->local_port == port2->local_port &&
(port1->external_port == -1 || port2->external_port == -1 || port1->external_port == port2->external_port);
}
UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port) {
@ -1220,7 +1220,7 @@ void linphone_upnp_port_binding_release(UpnpPortBinding *port) {
UpnpStream* linphone_upnp_stream_new() {
UpnpStream *stream = ms_new0(UpnpStream,1);
stream->state = LinphoneUpnpStateIdle;
stream->rtp = NULL;
stream->rtp = NULL;
stream->rtcp = NULL;
return stream;
}
@ -1269,10 +1269,10 @@ void linphone_upnp_session_destroy(UpnpSession *session) {
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp, TRUE);
}
}
session->call->stats[LINPHONE_CALL_STATS_AUDIO].upnp_state = LinphoneUpnpStateKo;
session->call->stats[LINPHONE_CALL_STATS_VIDEO].upnp_state = LinphoneUpnpStateKo;
linphone_upnp_stream_destroy(session->audio);
linphone_upnp_stream_destroy(session->video);
ms_free(session);
@ -1302,12 +1302,12 @@ static void linphone_upnp_config_list_port_bindings_cb(const char *entry, struct
int ret;
bool_t valid = TRUE;
UpnpPortBinding *port;
ret = sscanf(entry, "%"UPNP_UUID_LEN_STR"[^-]-%3s-%i-%i", device_id, protocol_str, &external_port, &local_port);
if(ret == 4) {
// Handle only wanted device bindings
if(device_id != NULL && strcmp(cookie->device_id, device_id) != 0) {
return;
return;
}
if(linphone_upnp_strncmpi(protocol_str, "TCP", 3) == 0) {
protocol = UPNP_IGD_IP_PROTOCOL_TCP;
@ -1344,7 +1344,7 @@ MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc, const cha
void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) {
MSList *list;
UpnpPortBinding *list_port;
if(port->device_id == NULL) {
ms_error("Can't remove port binding without device_id");
return;

View file

@ -29,7 +29,7 @@ struct _xml2lpc_context {
LpConfig *lpc;
xml2lpc_function cbf;
void *ctx;
xmlDoc *doc;
xmlDoc *xsd;
char errorBuffer[XML2LPC_BZ];
@ -43,7 +43,7 @@ xml2lpc_context* xml2lpc_context_new(xml2lpc_function cbf, void *ctx) {
xmlCtx->lpc = NULL;
xmlCtx->cbf = cbf;
xmlCtx->ctx = ctx;
xmlCtx->doc = NULL;
xmlCtx->xsd = NULL;
xmlCtx->errorBuffer[0]='\0';
@ -70,19 +70,19 @@ static void xml2lpc_context_clear_logs(xml2lpc_context *ctx) {
}
static void xml2lpc_log(xml2lpc_context *xmlCtx, int level, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
va_list args;
va_start(args, fmt);
if(xmlCtx->cbf != NULL) {
xmlCtx->cbf((xmlCtx)->ctx, level, fmt, args);
}
va_end(args);
va_end(args);
}
static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) {
xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
int sl = strlen(xmlCtx->errorBuffer);
va_list args;
va_start(args, fmt);
va_list args;
va_start(args, fmt);
vsnprintf(xmlCtx->errorBuffer + sl, XML2LPC_BZ-sl, fmt, args);
va_end(args);
}
@ -90,25 +90,25 @@ static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) {
static void xml2lpc_genericxml_warning(void *ctx, const char *fmt, ...) {
xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx;
int sl = strlen(xmlCtx->warningBuffer);
va_list args;
va_start(args, fmt);
va_list args;
va_start(args, fmt);
vsnprintf(xmlCtx->warningBuffer + sl, XML2LPC_BZ-sl, fmt, args);
va_end(args);
}
#if 0
static void dumpNodes(int level, xmlNode * a_node, xml2lpc_context *ctx) {
xmlNode *cur_node = NULL;
xmlNode *cur_node = NULL;
for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: Element, name: %s", level, cur_node->name);
} else {
xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name);
}
for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: Element, name: %s", level, cur_node->name);
} else {
xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name);
}
dumpNodes(level + 1, cur_node->children, ctx);
}
dumpNodes(level + 1, cur_node->children, ctx);
}
}
#endif
@ -162,7 +162,7 @@ static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_co
} else {
xml2lpc_log(ctx, XML2LPC_WARNING, "ignored entry with no \"name\" attribute line:%d",xmlGetLineNo((xmlNode*)element));
}
return 0;
return 0;
}
static int processSection(xmlElement *element, xml2lpc_context *ctx) {
@ -185,13 +185,13 @@ static int processSection(xmlElement *element, xml2lpc_context *ctx) {
processEntry((xmlElement*)cur_node, name, ctx);
}
}
}
} else {
xml2lpc_log(ctx, XML2LPC_WARNING, "ignored section with no \"name\" attribute, line:%d", xmlGetLineNo((xmlNode*)element));
}
return 0;
}
} else {
xml2lpc_log(ctx, XML2LPC_WARNING, "ignored section with no \"name\" attribute, line:%d", xmlGetLineNo((xmlNode*)element));
}
return 0;
}
static int processConfig(xmlElement *element, xml2lpc_context *ctx) {
@ -199,19 +199,19 @@ static int processConfig(xmlElement *element, xml2lpc_context *ctx) {
for (cur_node = element->children; cur_node; cur_node = cur_node->next) {
dumpNode(cur_node, ctx);
if (cur_node->type == XML_ELEMENT_NODE &&
if (cur_node->type == XML_ELEMENT_NODE &&
strcmp((const char*)cur_node->name, "section") == 0 ) {
processSection((xmlElement*)cur_node, ctx);
}
}
}
}
return 0;
}
static int processDoc(xmlNode *node, xml2lpc_context *ctx) {
dumpNode(node, ctx);
if (node->type == XML_ELEMENT_NODE &&
if (node->type == XML_ELEMENT_NODE &&
strcmp((const char*)node->name, "config") == 0 ) {
processConfig((xmlElement*)node, ctx);
} else {

View file

@ -268,6 +268,49 @@ void linphone_gtk_start_play_record_sound(GtkWidget *w,gpointer data){
}
}
void display_popup(GtkMessageType type,const gchar *message){
GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(audio_assistant),
GTK_DIALOG_DESTROY_WITH_PARENT,
type,
GTK_BUTTONS_CLOSE,
"%s",
(const gchar*)message);
/* Destroy the dialog when the user responds to it (e.g. clicks a button) */
g_signal_connect_swapped (G_OBJECT (dialog), "response",
G_CALLBACK (gtk_widget_destroy),
G_OBJECT (dialog));
gtk_widget_show(dialog);
}
static void open_mixer(){
GError *error = NULL;
#ifdef WIN32
if(!g_spawn_command_line_async("control mmsys.cpl",&error)){
display_popup(GTK_MESSAGE_WARNING,"Sound preferences not found ");
g_error_free(error);
}
#elif __APPLE__
if(!g_spawn_command_line_async("open /System/Library/PreferencePanes/Sound.prefPane",&error)){
display_popup(GTK_MESSAGE_WARNING,"Sound preferences not found ");
g_error_free(error);
}
#else
if(!g_spawn_command_line_async("gnome-volume-control",&error)){
if(!g_spawn_command_line_async("gnome-control-center sound",&error)){
if(!g_spawn_command_line_async("kmix",&error)){
if(!g_spawn_command_line_async("mate-volume-control",&error)){
if(!g_spawn_command_line_async("xterm alsamixer",&error)){
display_popup(GTK_MESSAGE_WARNING,"Cannot launch system sound control ");
g_error_free(error);
}
}
}
}
}
#endif
}
static GtkWidget *create_intro(){
GtkWidget *vbox=gtk_vbox_new(FALSE,2);
GtkWidget *label=gtk_label_new(_("Welcome !\nThis assistant will help you to configure audio settings for Linphone"));
@ -286,6 +329,11 @@ static GtkWidget *create_mic_page(){
GtkWidget *capture_device=gtk_combo_box_new();
GtkWidget *box = gtk_vbox_new(FALSE,0);
GtkWidget *label_audiolevel=gtk_label_new(_("No voice"));
GtkWidget *mixer_button=gtk_button_new_with_label("System sound preferences");
GtkWidget *image;
image=gtk_image_new_from_stock(GTK_STOCK_PREFERENCES,GTK_ICON_SIZE_MENU);
gtk_button_set_image(GTK_BUTTON(mixer_button),image);
gtk_box_pack_start(GTK_BOX(box),mic_audiolevel,TRUE,TRUE,1);
gtk_box_pack_start(GTK_BOX(box),label_audiolevel,FALSE,FALSE,1);
@ -294,6 +342,7 @@ static GtkWidget *create_mic_page(){
gtk_table_attach_defaults(GTK_TABLE(vbox), capture_device, 1, 2, 0, 1);
gtk_table_attach_defaults(GTK_TABLE(vbox), labelMicLevel, 0, 1, 1, 2);
gtk_table_attach_defaults(GTK_TABLE(vbox), box, 1, 2, 1, 2);
gtk_table_attach(GTK_TABLE(vbox), mixer_button, 0, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 0,0);
gtk_table_set_row_spacings(GTK_TABLE(vbox),10);
@ -306,23 +355,30 @@ static GtkWidget *create_mic_page(){
gtk_widget_show_all(vbox);
g_signal_connect(G_OBJECT(capture_device),"changed",(GCallback)capture_device_changed,capture_device);
g_signal_connect(G_OBJECT(mixer_button),"clicked",(GCallback)open_mixer,vbox);
return vbox;
}
static GtkWidget *create_speaker_page(){
GtkWidget *vbox=gtk_table_new(2,2,FALSE);
GtkWidget *vbox=gtk_table_new(3,2,FALSE);
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *labelSpeakerChoice=gtk_label_new(_("Playback device"));
GtkWidget *labelSpeakerLevel=gtk_label_new(_("Play three beeps"));
GtkWidget *spk_button=gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
GtkWidget *playback_device=gtk_combo_box_new();
GtkWidget *mixer_button=gtk_button_new_with_label("System sound preferences");
GtkWidget *image;
image=gtk_image_new_from_stock(GTK_STOCK_PREFERENCES,GTK_ICON_SIZE_MENU);
gtk_button_set_image(GTK_BUTTON(mixer_button),image);
gtk_table_attach_defaults(GTK_TABLE(vbox), labelSpeakerChoice, 0, 1, 0, 1);
gtk_table_attach_defaults(GTK_TABLE(vbox), playback_device, 1, 2, 0, 1);
gtk_table_attach(GTK_TABLE(vbox), playback_device, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0,0);
gtk_table_attach_defaults(GTK_TABLE(vbox), labelSpeakerLevel, 0, 1, 1, 2);
gtk_table_attach(GTK_TABLE(vbox), spk_button, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0,0);
gtk_table_attach(GTK_TABLE(vbox), mixer_button, 0, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 0,0);
gtk_table_set_row_spacings(GTK_TABLE(vbox),10);
@ -334,6 +390,7 @@ static GtkWidget *create_speaker_page(){
set_widget_to_assistant("speaker_page",vbox);
g_signal_connect(G_OBJECT(playback_device),"changed",(GCallback)playback_device_changed,playback_device);
g_signal_connect(G_OBJECT(spk_button),"clicked",(GCallback)linphone_gtk_start_sound,vbox);
g_signal_connect(G_OBJECT(mixer_button),"clicked",(GCallback)open_mixer,vbox);
return vbox;
}

View file

@ -565,7 +565,7 @@ static void linphone_gtk_init_codec_list(GtkTreeView *listview){
"foreground",CODEC_COLOR,
NULL);
gtk_tree_view_append_column (listview, column);
column = gtk_tree_view_column_new_with_attributes (_("Bitrate (kbit/s)"),
column = gtk_tree_view_column_new_with_attributes (_("IP Bitrate (kbit/s)"),
renderer,
"text", CODEC_BITRATE,
"foreground",CODEC_COLOR,
@ -621,7 +621,7 @@ static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codecl
}
/* get an iterator */
gtk_list_store_append(store,&iter);
bitrate=payload_type_get_bitrate(pt)/1000.0;
bitrate=linphone_core_get_payload_type_bitrate(linphone_gtk_get_core(),pt);
rate=payload_type_get_rate(pt);
if (pt->recv_fmtp!=NULL) params=pt->recv_fmtp;
gtk_list_store_set(store,&iter, CODEC_NAME,payload_type_get_mime(pt),
@ -657,7 +657,7 @@ static void linphone_gtk_check_codec_bandwidth(GtkTreeView *v){
gfloat bitrate;
gtk_tree_model_get(model,&iter,CODEC_PRIVDATA,&pt,-1);
bitrate=payload_type_get_bitrate(pt)/1000.0;
bitrate=linphone_core_get_payload_type_bitrate(linphone_gtk_get_core(),pt);
gtk_list_store_set(GTK_LIST_STORE(model),&iter,CODEC_COLOR, (gpointer)get_codec_color(linphone_gtk_get_core(),pt),
CODEC_BITRATE, bitrate,-1);
}while(gtk_tree_model_iter_next(model,&iter));

View file

@ -17,9 +17,9 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**
/**
This header files defines the Signaling Abstraction Layer.
The purpose of this layer is too allow experiment different call signaling
The purpose of this layer is too allow experiment different call signaling
protocols and implementations under linphone, for example SIP, JINGLE...
**/
@ -30,9 +30,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "config.h"
#endif
#include "mediastreamer2/mscommon.h"
#include "mediastreamer2/mediastream.h"
#include "ortp/rtpsession.h"
#include "ortp/ortp_srtp.h"
#include "belle-sip/belle-sip.h"
#ifndef LINPHONE_PUBLIC
@ -171,7 +170,7 @@ typedef struct SalIceRemoteCandidate {
typedef struct SalSrtpCryptoAlgo {
unsigned int tag;
enum ortp_srtp_crypto_suite_t algo;
MSCryptoSuite algo;
char master_key[SAL_SRTP_KEY_SIZE];
} SalSrtpCryptoAlgo;
@ -531,6 +530,7 @@ void sal_verify_server_cn(Sal *ctx, bool_t verify);
void sal_set_uuid(Sal*ctx, const char *uuid);
int sal_create_uuid(Sal*ctx, char *uuid, size_t len);
void sal_enable_test_features(Sal*ctx, bool_t enabled);
void sal_use_no_initial_route(Sal *ctx, bool_t enabled);
int sal_iterate(Sal *sal);
MSList * sal_get_pending_auths(Sal *sal);
@ -572,6 +572,7 @@ const SalAddress *sal_op_get_network_origin_address(const SalOp *op);
const char *sal_op_get_remote_ua(const SalOp *op);
void *sal_op_get_user_pointer(const SalOp *op);
const char* sal_op_get_call_id(const SalOp *op);
char* sal_op_get_dialog_id(const SalOp *op);
const SalAddress* sal_op_get_service_route(const SalOp *op);
void sal_op_set_service_route(SalOp *op,const SalAddress* service_route);

View file

@ -693,6 +693,20 @@ public interface LinphoneCore {
*/
boolean isPayloadTypeEnabled(PayloadType pt);
/**
* Set an explicit bitrate (IP bitrate, not codec bitrate) for a given codec, in kbit/s.
* @param pt the payload type
* @param bitrate target IP bitrate in kbit/s
*/
void setPayloadTypeBitrate(PayloadType pt, int bitrate);
/**
* Get target bitrate previously set by setPayloadTypeBitrate().
* @param pt
* @return IP bitrate in kbit/s
*/
int getPayloadTypeBitrate(PayloadType pt);
/**
* Enables or disable echo cancellation.
* @param enable

View file

@ -1188,5 +1188,15 @@ class LinphoneCoreImpl implements LinphoneCore {
public void stopRinging() {
stopRinging(nativePtr);
}
private native void setPayloadTypeBitrate(long coreptr, long payload_ptr, int bitrate);
@Override
public void setPayloadTypeBitrate(PayloadType pt, int bitrate) {
setPayloadTypeBitrate(nativePtr, ((PayloadTypeImpl)pt).nativePtr, bitrate);
}
private native int getPayloadTypeBitrate(long coreptr, long payload_ptr);
@Override
public int getPayloadTypeBitrate(PayloadType pt) {
return getPayloadTypeBitrate(nativePtr, ((PayloadTypeImpl)pt).nativePtr);
}
}

@ -1 +1 @@
Subproject commit 13d0cee33672690daca1a7252c9f3a7022da95bd
Subproject commit d51333b63b6f61c96bb861ad07e8165321c50f59

2
oRTP

@ -1 +1 @@
Subproject commit ebd87c21d3d5c8b4775ef08af18e27c4bf4fa3ac
Subproject commit c93363ac023c2122bfdfb8b0d99b811dffbad827

View file

@ -22,6 +22,8 @@ liblinphonetester_la_SOURCES = tester.c \
stun_tester.c \
remote_provisioning_tester.c
liblinphonetester_la_LDFLAGS= -no-undefined
liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS)
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/coreapi
AM_CFLAGS = $(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS)
@ -31,7 +33,7 @@ if !BUILD_IOS
noinst_PROGRAMS = liblinphone_tester
liblinphone_tester_SOURCES = liblinphone_tester.c
liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la liblinphonetester.la $(SIPSTACK_LIBS) $(LIBXML2_LIBS) $(CUNIT_LIBS)
liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la liblinphonetester.la
endif

View file

@ -24,6 +24,8 @@
#include "private.h"
#include "liblinphone_tester.h"
static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy);
static void disable_all_codecs_except_one(LinphoneCore *lc, const char *mime);
void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){
char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to);
@ -59,7 +61,22 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState
CU_FAIL("unexpected event");break;
}
}
void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token) {
char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to);
char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from);
stats* counters;
ms_message(" %s call from [%s] to [%s], is now [%s]",linphone_call_get_call_log(call)->dir==LinphoneCallIncoming?"Incoming":"Outgoing"
,from
,to
,(on?"encrypted":"unencrypted"));
ms_free(to);
ms_free(from);
counters = get_stats(lc);
if (on)
counters->number_of_LinphoneCallEncryptedOn++;
else
counters->number_of_LinphoneCallEncryptedOff++;
}
void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) {
char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to);
char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from);
@ -103,10 +120,10 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana
c1=linphone_core_get_current_call(caller->lc);
c2=linphone_core_get_current_call(callee->lc);
CU_ASSERT_PTR_NOT_NULL(c1);
CU_ASSERT_PTR_NOT_NULL(c2);
if (!c1 || !c2) return;
for (i=0; i<24 /*=12s need at least one exchange of SR to maybe 10s*/; i++) {
@ -198,12 +215,19 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr
&&
wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+1);
if (linphone_core_get_media_encryption(caller_mgr->lc)
&& linphone_core_get_media_encryption(callee_mgr->lc)) {
if (linphone_core_get_media_encryption(caller_mgr->lc) != LinphoneMediaEncryptionNone
&& linphone_core_get_media_encryption(callee_mgr->lc) != LinphoneMediaEncryptionNone) {
/*wait for encryption to be on, in case of zrtp, it can take a few seconds*/
if (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP)
wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_caller.number_of_LinphoneCallEncryptedOn+1);
if (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP)
wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_callee.number_of_LinphoneCallEncryptedOn+1);
{
const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee_mgr->lc));
CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc));
call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc));
CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc));
}
}
return result;
}
@ -226,6 +250,39 @@ static void simple_call(void) {
linphone_core_manager_destroy(pauline);
}
static void call_with_specified_codec_bitrate(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
const LinphoneCallStats *pauline_stats,*marie_stats;
bool_t call_ok;
if (linphone_core_find_payload_type(marie->lc,"opus",48000,-1)==NULL){
ms_warning("opus codec not supported, test skipped.");
goto end;
}
disable_all_codecs_except_one(marie->lc,"opus");
disable_all_codecs_except_one(pauline->lc,"opus");
linphone_core_set_payload_type_bitrate(marie->lc,
linphone_core_find_payload_type(marie->lc,"opus",48000,-1),
50);
linphone_core_set_payload_type_bitrate(pauline->lc,
linphone_core_find_payload_type(pauline->lc,"opus",48000,-1),
24);
CU_ASSERT_TRUE((call_ok=call(pauline,marie)));
if (!call_ok) goto end;
liblinphone_tester_check_rtcp(marie,pauline);
marie_stats=linphone_call_get_audio_stats(linphone_core_get_current_call(marie->lc));
pauline_stats=linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE(marie_stats->download_bandwidth<30);
CU_ASSERT_TRUE(pauline_stats->download_bandwidth>45);
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void simple_call_compatibility_mode(void) {
char route[256];
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
@ -316,7 +373,7 @@ static void cancelled_call(void) {
static void disable_all_codecs_except_one(LinphoneCore *lc, const char *mime){
const MSList *elem=linphone_core_get_audio_codecs(lc);
PayloadType *pt;
for(;elem!=NULL;elem=elem->next){
pt=(PayloadType*)elem->data;
linphone_core_enable_payload_type(lc,pt,FALSE);
@ -351,7 +408,7 @@ static void call_with_dns_time_out(void) {
LinphoneCoreManager* marie = linphone_core_manager_new2( "empty_rc", FALSE);
LCSipTransports transport = {9773,0,0,0};
int i;
linphone_core_set_sip_transports(marie->lc,&transport);
linphone_core_iterate(marie->lc);
sal_set_dns_timeout(marie->lc->sal,0);
@ -359,7 +416,7 @@ static void call_with_dns_time_out(void) {
for(i=0;i<10;i++){
ms_usleep(200000);
linphone_core_iterate(marie->lc);
}
}
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,1);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1);
@ -372,21 +429,21 @@ static void early_cancelled_call(void) {
LinphoneCoreManager* pauline = linphone_core_manager_new2( "empty_rc",FALSE);
LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1));
linphone_core_terminate_call(pauline->lc,out_call);
/*since everything is executed in a row, no response can be received from the server, thus the CANCEL cannot be sent.
It will ring at Marie's side.*/
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1));
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1));
/* now the CANCEL should have been sent and the the call at marie's side should terminate*/
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1));
linphone_core_manager_destroy(marie);
@ -426,7 +483,7 @@ static void early_declined_call(void) {
CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,33000));
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallError,1);
/* FIXME http://git.linphone.org/mantis/view.php?id=757
CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonBusy);
*/
if (ms_list_size(linphone_core_get_call_logs(pauline->lc))>0) {
@ -466,7 +523,7 @@ static void call_declined(void) {
static void call_terminated_by_caller(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
CU_ASSERT_TRUE(call(pauline,marie));
/*just to sleep*/
linphone_core_terminate_all_calls(pauline->lc);
@ -480,7 +537,7 @@ static void call_terminated_by_caller(void) {
static void call_with_no_sdp(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
linphone_core_enable_sdp_200_ack(marie->lc,TRUE);
CU_ASSERT_TRUE(call(marie,pauline));
@ -500,7 +557,7 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee
c1=linphone_core_get_current_call(caller->lc);
c2=linphone_core_get_current_call(callee->lc);
CU_ASSERT_PTR_NOT_NULL(c1);
CU_ASSERT_PTR_NOT_NULL(c2);
@ -516,18 +573,33 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee
}
ms_usleep(50000);
}
/*make sure encryption mode are preserved*/
if (c1) {
const LinphoneCallParams* call_param = linphone_call_get_current_params(c1);
CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc));
}
if (c2) {
const LinphoneCallParams* call_param = linphone_call_get_current_params(c2);
CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(callee->lc));
}
return success;
}
static void _call_with_ice(bool_t random_ports) {
static void _call_with_ice(bool_t caller_with_ice, bool_t callee_with_ice, bool_t random_ports) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
linphone_core_set_stun_server(marie->lc,"stun.linphone.org");
linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce);
linphone_core_set_stun_server(pauline->lc,"stun.linphone.org");
if (callee_with_ice){
linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
linphone_core_set_stun_server(marie->lc,"stun.linphone.org");
}
if (caller_with_ice){
linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce);
linphone_core_set_stun_server(pauline->lc,"stun.linphone.org");
}
if (random_ports){
linphone_core_set_audio_port(marie->lc,-1);
linphone_core_set_video_port(marie->lc,-1);
@ -537,11 +609,15 @@ static void _call_with_ice(bool_t random_ports) {
CU_ASSERT_TRUE(call(pauline,marie));
CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
/*wait for the ICE reINVITE to complete*/
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));
if (callee_with_ice && caller_with_ice) {
check_ice(pauline,marie,LinphoneIceStateHostConnection);
/*wait for the ICE reINVITE to complete*/
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));
CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
}
liblinphone_tester_check_rtcp(marie,pauline);
/*then close the call*/
linphone_core_terminate_all_calls(pauline->lc);
@ -553,11 +629,19 @@ static void _call_with_ice(bool_t random_ports) {
}
static void call_with_ice(void){
_call_with_ice(FALSE);
_call_with_ice(TRUE,TRUE,FALSE);
}
static void call_with_ice_random_ports(void){
_call_with_ice(TRUE);
_call_with_ice(TRUE,TRUE,TRUE);
}
static void ice_to_not_ice(void){
_call_with_ice(TRUE,FALSE,FALSE);
}
static void not_ice_to_ice(void){
_call_with_ice(FALSE,TRUE,FALSE);
}
static void call_with_custom_headers(void) {
@ -579,17 +663,17 @@ static void call_with_custom_headers(void) {
ms_free(tmp);
linphone_address_destroy(marie->identity);
marie->identity=marie_identity;
params=linphone_core_create_default_call_parameters(marie->lc);
linphone_call_params_add_custom_header(params,"Weather","bad");
linphone_call_params_add_custom_header(params,"Working","yes");
CU_ASSERT_TRUE(call_with_caller_params(pauline,marie,params));
linphone_call_params_destroy(params);
call_marie=linphone_core_get_current_call(marie->lc);
call_pauline=linphone_core_get_current_call(pauline->lc);
CU_ASSERT_PTR_NOT_NULL(call_marie);
CU_ASSERT_PTR_NOT_NULL(call_pauline);
@ -701,6 +785,15 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee)
LinphoneVideoPolicy caller_policy;
LinphoneCallParams* callee_params;
LinphoneCall* call_obj;
stats initial_caller_stat=caller->stat;
stats initial_callee_stat=callee->stat;
if (linphone_call_get_state(linphone_core_get_current_call(callee->lc)) != LinphoneCallStreamsRunning
|| linphone_call_get_state(linphone_core_get_current_call(caller->lc)) != LinphoneCallStreamsRunning ) {
ms_warning("bad state for adding video");
return FALSE;
}
caller_policy.automatically_accept=TRUE;
caller_policy.automatically_initiate=TRUE;
linphone_core_enable_video_capture(callee->lc, TRUE);
@ -708,8 +801,8 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee)
linphone_core_enable_video_capture(caller->lc, TRUE);
linphone_core_enable_video_display(caller->lc, FALSE);
linphone_core_set_video_policy(caller->lc,&caller_policy);
stats initial_caller_stat=caller->stat;
stats initial_callee_stat=callee->stat;
if ((call_obj = linphone_core_get_current_call(callee->lc))) {
callee_params = linphone_call_params_copy(linphone_call_get_current_params(call_obj));
@ -724,6 +817,21 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee)
CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc))));
CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc))));
if (linphone_core_get_media_encryption(caller->lc) != LinphoneMediaEncryptionNone
&& linphone_core_get_media_encryption(callee->lc) != LinphoneMediaEncryptionNone) {
/*wait for encryption to be on, in case of zrtp, it can take a few seconds*/
if (linphone_core_get_media_encryption(caller->lc) == LinphoneMediaEncryptionZRTP)
wait_for(callee->lc,caller->lc,&caller->stat.number_of_LinphoneCallEncryptedOn,initial_caller_stat.number_of_LinphoneCallEncryptedOn+1);
if (linphone_core_get_media_encryption(callee->lc) == LinphoneMediaEncryptionZRTP)
wait_for(callee->lc,caller->lc,&callee->stat.number_of_LinphoneCallEncryptedOn,initial_callee_stat.number_of_LinphoneCallEncryptedOn+1);
{
const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee->lc));
CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc));
call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc));
CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc));
}
}
linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,callee->lc);
/*send vfu*/
@ -750,12 +858,12 @@ static void call_with_video_added(void) {
static void call_with_video_added_random_ports(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
linphone_core_set_audio_port(marie->lc,-1);
linphone_core_set_video_port(marie->lc,-1);
linphone_core_set_audio_port(pauline->lc,-1);
linphone_core_set_video_port(pauline->lc,-1);
CU_ASSERT_TRUE(call(pauline,marie));
CU_ASSERT_TRUE(add_video(pauline,marie));
@ -822,19 +930,21 @@ static void video_call(void) {
marie_call=linphone_core_get_current_call(marie->lc);
pauline_call=linphone_core_get_current_call(pauline->lc);
CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call)));
CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call)));
if (marie_call && pauline_call ) {
CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call)));
CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call)));
/*check video path*/
linphone_call_set_next_video_frame_decoded_callback(marie_call,linphone_call_cb,marie->lc);
linphone_call_send_vfu_request(marie_call);
CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1));
/*check video path*/
linphone_call_set_next_video_frame_decoded_callback(marie_call,linphone_call_cb,marie->lc);
linphone_call_send_vfu_request(marie_call);
CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1));
liblinphone_tester_check_rtcp(marie,pauline);
liblinphone_tester_check_rtcp(marie,pauline);
linphone_core_terminate_all_calls(pauline->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));
linphone_core_terminate_all_calls(pauline->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));
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
@ -846,17 +956,17 @@ static void _call_with_media_relay(bool_t random_ports) {
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL);
linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL);
if (random_ports){
linphone_core_set_audio_port(marie->lc,-1);
linphone_core_set_video_port(marie->lc,-1);
linphone_core_set_audio_port(pauline->lc,-1);
linphone_core_set_video_port(pauline->lc,-1);
}
CU_ASSERT_TRUE(call(pauline,marie));
liblinphone_tester_check_rtcp(pauline,marie);
#ifdef VIDEO_ENABLED
CU_ASSERT_TRUE(add_video(pauline,marie));
liblinphone_tester_check_rtcp(pauline,marie);
@ -942,7 +1052,7 @@ static void call_with_privacy2(void) {
LinphoneProxyConfig* pauline_proxy;
params=linphone_core_create_default_call_parameters(pauline->lc);
linphone_call_params_set_privacy(params,LinphonePrivacyId);
linphone_core_get_default_proxy(pauline->lc,&pauline_proxy);
linphone_proxy_config_edit(pauline_proxy);
linphone_proxy_config_enable_register(pauline_proxy,FALSE);
@ -1136,46 +1246,16 @@ static void simple_conference(void) {
ms_list_free(lcs);
}
static void encrypted_call(LinphoneMediaEncryption mode) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
if (linphone_core_media_encryption_supported(marie->lc,mode)) {
linphone_core_set_media_encryption(marie->lc,mode);
linphone_core_set_media_encryption(pauline->lc,mode);
CU_ASSERT_TRUE(call(pauline,marie));
CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),mode);
CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),mode);
if (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP
&& linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) {
/*check SAS*/
CU_ASSERT_STRING_EQUAL(linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc))
,linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc)));
}
liblinphone_tester_check_rtcp(pauline,marie);
/*just to sleep*/
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));
} else {
ms_warning ("Not tested because %s not available", linphone_media_encryption_to_string(mode));
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void srtp_call() {
encrypted_call(LinphoneMediaEncryptionSRTP);
call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyNoFirewall);
}
/*
* future work
static void zrtp_call() {
encrypted_call(LinphoneMediaEncryptionZRTP);
}*/
call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall);
}
static void zrtp_video_call() {
call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall);
}
static void call_with_declined_srtp(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
@ -1195,58 +1275,103 @@ static void call_with_declined_srtp(void) {
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
#ifdef VIDEO_ENABLED
static void srtp_video_ice_call(void) {
int i=0;
#else
static void srtp_ice_call(void) {
#endif
static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
if (enable_relay) {
linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL);
linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL);
}
if (linphone_core_media_encryption_supported(marie->lc,mode)) {
linphone_core_set_media_encryption(marie->lc,mode);
linphone_core_set_media_encryption(pauline->lc,mode);
if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) {
linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP);
linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP);
linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
linphone_core_set_firewall_policy(marie->lc,policy);
linphone_core_set_stun_server(marie->lc,"stun.linphone.org");
linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce);
linphone_core_set_firewall_policy(pauline->lc,policy);
linphone_core_set_stun_server(pauline->lc,"stun.linphone.org");
CU_ASSERT_TRUE(call(pauline,marie));
if (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP
&& linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) {
/*wait for SAS*/
int i;
for (i=0;i<10;i++) {
if (linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc))
&&
linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc))) {
/*check SAS*/
CU_ASSERT_STRING_EQUAL(linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc))
,linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc)));
liblinphone_tester_check_rtcp(pauline,marie);
break;
}
linphone_core_iterate(marie->lc);
linphone_core_iterate(pauline->lc);
ms_usleep(200000);
}
CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
#ifdef VIDEO_ENABLED
for (i=0;i<100;i++) { /*fixme to workaround a crash*/
ms_usleep(20000);
linphone_core_iterate(marie->lc);
linphone_core_iterate(pauline->lc);
}
add_video(pauline,marie);
if (policy == LinphonePolicyUseIce)
CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
#ifdef VIDEO_ENABLED
if (enable_video) {
int i=0;
if (linphone_core_video_supported(marie->lc)) {
for (i=0;i<100;i++) { /*fixme to workaround a crash*/
ms_usleep(20000);
linphone_core_iterate(marie->lc);
linphone_core_iterate(pauline->lc);
}
CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
liblinphone_tester_check_rtcp(marie,pauline);
/*wait for ice to found the direct path*/
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1));
add_video(pauline,marie);
if (policy == LinphonePolicyUseIce)
CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
liblinphone_tester_check_rtcp(marie,pauline);
/*wait for ice to found the direct path*/
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1));
} else {
ms_warning ("not tested because video not available");
}
}
#endif
/*just to sleep*/
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));
} else {
ms_warning ("not tested because srtp not available");
ms_warning ("not tested because %s not available", linphone_media_encryption_to_string(mode));
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
#ifdef VIDEO_ENABLED
static void srtp_video_ice_call(void) {
call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce);
}
static void zrtp_video_ice_call(void) {
call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce);
}
#endif
static void srtp_ice_call(void) {
call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce);
}
static void zrtp_ice_call(void) {
call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce);
}
static void zrtp_ice_call_with_relay(void) {
call_base(LinphoneMediaEncryptionZRTP,FALSE,TRUE,LinphonePolicyUseIce);
}
static void early_media_call(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_early_rc");
@ -1256,19 +1381,19 @@ static void early_media_call(void) {
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1);
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1);
wait_for_until(pauline->lc,marie->lc,NULL,0,1000);
/*added because a bug related to early-media caused the Connected state to be reached two times*/
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected,1);
/*just to sleep*/
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));
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
@ -1285,7 +1410,7 @@ static void early_media_call_with_ringing(void){
/*
Marie calls Pauline, and after the call has rung, transitions to an early_media session
*/
/*use playfile for callee to avoid locking on capture card*/
linphone_core_use_files (pauline->lc,TRUE);
snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix);
@ -1297,31 +1422,32 @@ static void early_media_call_with_ringing(void){
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000));
/* send a 183 to initiate the early media */
if (linphone_core_inc_invite_pending(pauline->lc)) {
/* send a 183 to initiate the early media */
linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc));
linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) );
CU_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) );
CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) );
CU_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) );
liblinphone_tester_check_rtcp(marie, pauline);
liblinphone_tester_check_rtcp(marie, pauline);
linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc));
linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000));
CU_ASSERT_EQUAL(marie_call, linphone_core_get_current_call(marie->lc));
CU_ASSERT_EQUAL(marie_call, linphone_core_get_current_call(marie->lc));
liblinphone_tester_check_rtcp(marie, pauline);
liblinphone_tester_check_rtcp(marie, pauline);
linphone_core_terminate_all_calls(pauline->lc);
linphone_core_terminate_all_calls(pauline->lc);
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000));
ms_list_free(lcs);
ms_list_free(lcs);
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
@ -1444,9 +1570,9 @@ static void simple_call_transfer(void) {
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPaused,1,2000));
/*marie calling laure*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000));
CU_ASSERT_PTR_NOT_NULL(linphone_call_get_transfer_target_call(marie_calling_pauline));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,2000));
@ -1456,11 +1582,11 @@ static void simple_call_transfer(void) {
CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000));
marie_calling_laure=linphone_core_get_current_call(marie->lc);
CU_ASSERT_PTR_NOT_NULL_FATAL(marie_calling_laure);
CU_ASSERT_TRUE(linphone_call_get_transferer_call(marie_calling_laure)==marie_calling_pauline);
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallConnected,1,2000));
/*terminate marie to pauline call*/
@ -1494,11 +1620,11 @@ static void unattended_call_transfer(void) {
linphone_core_transfer_call(marie->lc,pauline_called_by_marie,laure_identity);
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000));
/*marie ends the call */
linphone_core_terminate_call(marie->lc,pauline_called_by_marie);
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000));
/*Pauline starts the transfer*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000));
@ -1535,21 +1661,21 @@ static void unattended_call_transfer_with_error(void) {
linphone_core_transfer_call(marie->lc,pauline_called_by_marie,"unknown_user");
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000));
/*Pauline starts the transfer*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000));
/* and immediately get an error*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,2000));
/*the error must be reported back to marie*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallError,1,2000));
/*and pauline should resume the call automatically*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallResuming,1,2000));
/*and call should be resumed*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000));
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
ms_list_free(lcs);
@ -1703,7 +1829,7 @@ static void call_established_with_rejected_incoming_reinvite(void) {
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
CU_ASSERT_TRUE(call(pauline,marie));
/*wait for ACK to be transmitted before going to reINVITE*/
wait_for_until(marie->lc,pauline->lc,NULL,0,1000);
@ -1748,7 +1874,7 @@ static void call_redirect(void){
/*
Marie calls Pauline, which will redirect the call to Laure via a 302
*/
/*use playfile for callee to avoid locking on capture card*/
linphone_core_use_files (pauline->lc,TRUE);
linphone_core_use_files (laure->lc,TRUE);
@ -1786,7 +1912,7 @@ static void call_redirect(void){
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000));
ms_list_free(lcs);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(laure);
@ -1875,6 +2001,98 @@ static void call_rejected_without_403_because_wrong_credentials_no_auth_req_cb()
call_rejected_because_wrong_credentials_with_params("tester-no-403",FALSE);
}
void create_call_for_statistics_tests(
LinphoneCoreManager* marie,
LinphoneCoreManager* pauline,
LinphoneCall** call_marie,
LinphoneCall** call_pauline) {
CU_ASSERT_TRUE(call(pauline,marie));
*call_marie = linphone_core_get_current_call(marie->lc);
*call_pauline = linphone_core_get_current_call(pauline->lc);
CU_ASSERT_PTR_NOT_NULL(*call_marie);
CU_ASSERT_PTR_NOT_NULL(*call_pauline);
}
static void statistics_not_used_without_config() {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall* call_marie = NULL;
LinphoneCall* call_pauline = NULL;
create_call_for_statistics_tests(marie, pauline, &call_marie, &call_pauline);
// marie has stats collection enabled since pauline has not
CU_ASSERT_TRUE(linphone_proxy_config_send_statistics_enabled(call_marie->dest_proxy));
CU_ASSERT_FALSE(linphone_proxy_config_send_statistics_enabled(call_pauline->dest_proxy));
CU_ASSERT_EQUAL(strcmp("sip:collector@sip.example.org",
linphone_proxy_config_get_statistics_collector(call_marie->dest_proxy)), 0);
// this field should be already filled
CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->info.local_addr.ip);
CU_ASSERT_PTR_NULL(call_pauline->log->reports[0]->info.local_addr.ip);
// but not this one since it is updated at the end of call
CU_ASSERT_PTR_NULL(call_marie->log->reports[0]->dialog_id);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void statistics_not_sent_if_call_not_started() {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCallLog* out_call_log;
LinphoneCall* out_call;
linphone_core_set_max_calls(pauline->lc,0);
out_call = linphone_core_invite(marie->lc,"pauline");
linphone_call_ref(out_call);
CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallError,1, 10000));
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1);
if (ms_list_size(linphone_core_get_call_logs(marie->lc))>0) {
CU_ASSERT_PTR_NOT_NULL(out_call_log=(LinphoneCallLog*)(linphone_core_get_call_logs(marie->lc)->data));
CU_ASSERT_EQUAL(linphone_call_log_get_status(out_call_log),LinphoneCallAborted);
}
linphone_call_unref(out_call);
// wait a few time...
wait_for(marie->lc,NULL,NULL,0);
// since the callee was busy, there should be no publish to do
CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void statistics_sent_at_call_termination() {
// int return_code = -1;
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall* call_marie = NULL;
LinphoneCall* call_pauline = NULL;
create_call_for_statistics_tests(marie, pauline, &call_marie, &call_pauline);
linphone_core_terminate_all_calls(marie->lc);
CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000));
CU_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000));
CU_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc));
CU_ASSERT_PTR_NULL(linphone_core_get_current_call(pauline->lc));
// now dialog id should be filled
CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->dialog_id);
// PUBLISH submission to the collector should be ok
CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1));
CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishOk,1));
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
#ifdef VIDEO_ENABLED
#endif
@ -1899,17 +2117,20 @@ test_t call_tests[] = {
{ "Call paused resumed", call_paused_resumed },
{ "Call paused resumed from callee", call_paused_resumed_from_callee },
{ "SRTP call", srtp_call },
/*{ "ZRTP call",zrtp_call}, futur work*/
{ "ZRTP call",zrtp_call},
{ "ZRTP video call",zrtp_video_call},
{ "SRTP call with declined srtp", call_with_declined_srtp },
#ifdef VIDEO_ENABLED
{ "Simple video call",video_call},
{ "SRTP ice video call", srtp_video_ice_call },
{ "ZRTP ice video call", zrtp_video_ice_call },
{ "Call with video added", call_with_video_added },
{ "Call with video added (random ports)", call_with_video_added_random_ports },
{ "Call with video declined",call_with_declined_video},
#else
{ "SRTP ice call", srtp_ice_call },
#endif
{ "SRTP ice call", srtp_ice_call },
{ "ZRTP ice call", zrtp_ice_call },
{ "ZRTP ice call with relay", zrtp_ice_call_with_relay},
{ "Call with privacy", call_with_privacy },
{ "Call with privacy 2", call_with_privacy2 },
{ "Call rejected because of wrong credential", call_rejected_because_wrong_credentials},
@ -1924,12 +2145,18 @@ test_t call_tests[] = {
{ "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call },
{ "Call with ICE", call_with_ice },
{ "Call with ICE (random ports)", call_with_ice_random_ports },
{ "Call from ICE to not ICE",ice_to_not_ice},
{ "Call from not ICE to ICE",not_ice_to_ice},
{ "Call with custom headers",call_with_custom_headers},
{ "Call established with rejected INFO",call_established_with_rejected_info},
{ "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite},
{ "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite },
{ "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error},
{ "Call redirected by callee", call_redirect}
{ "Call redirected by callee", call_redirect},
{ "Call statistics not used if no config", statistics_not_used_without_config},
{ "Call statistics not sent if call did not start", statistics_not_sent_if_call_not_started},
{ "Call statistics sent if call ended normally", statistics_sent_at_call_termination},
{ "Call with specified codec bitrate", call_with_specified_codec_bitrate}
};
test_suite_t call_test_suite = {
@ -1939,4 +2166,3 @@ test_suite_t call_test_suite = {
sizeof(call_tests) / sizeof(call_tests[0]),
call_tests
};

View file

@ -48,12 +48,16 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li
stats* counters = get_stats(lc);
LinphoneCoreManager *mgr=get_manager(lc);
LinphoneContent content={0};
const LinphoneAddress* from_addr = linphone_event_get_from(lev);
char* from = linphone_address_as_string(from_addr);
content.type="application";
content.subtype="somexml2";
content.data=(void*)notify_content;
content.size=strlen(notify_content);
ms_message("Subscription state [%s] from [%s]",linphone_subscription_state_to_string(state),from);
ms_free(from);
switch(state){
case LinphoneSubscriptionNone:
break;
@ -95,6 +99,10 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li
void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){
stats* counters = get_stats(lc);
const LinphoneAddress* from_addr = linphone_event_get_from(ev);
char* from = linphone_address_as_string(from_addr);
ms_message("Publish state [%s] from [%s]",linphone_publish_state_to_string(state),from);
ms_free(from);
switch(state){
case LinphonePublishProgress: counters->number_of_LinphonePublishProgress++; break;
case LinphonePublishOk:
@ -132,7 +140,7 @@ static void subscribe_test_declined(void) {
linphone_event_ref(lev);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,21000));/*yes flexisip may wait 20 secs in case of forking*/
ei=linphone_event_get_error_info(lev);
CU_ASSERT_PTR_NOT_NULL(ei);
@ -175,8 +183,8 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes
lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,&content);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,1000));
/*make sure marie receives first notification before terminating*/
@ -230,7 +238,7 @@ static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTe
linphone_event_send_subscribe(lev,&content);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000));
/*check good receipt of custom headers*/
CU_ASSERT_STRING_EQUAL(linphone_event_get_custom_header(pauline->lev,"My-Header"),"pouet");

View file

@ -43,7 +43,7 @@ static void subscribe_forking(void) {
lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,&content);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline2->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000));
@ -71,7 +71,7 @@ static void message_forking(void) {
lcs=ms_list_append(lcs,marie2->lc);
linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,1000));
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1);
@ -101,7 +101,7 @@ static void message_forking_with_unreachable_recipients(void) {
linphone_core_set_network_reachable(marie3->lc,FALSE);
linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,1000));
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1);
CU_ASSERT_TRUE( marie2->stat.number_of_LinphoneMessageReceived==0);
@ -192,7 +192,7 @@ static void call_forking(void){
linphone_core_invite_address(pauline->lc,marie->identity);
/*pauline should hear ringback*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000));
/*all devices from Marie should be ringing*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000));
@ -352,11 +352,11 @@ static void call_forking_declined(bool_t declined_globaly){
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallStreamsRunning,1,2000));
liblinphone_tester_check_rtcp(pauline,marie2);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,3000));
linphone_core_terminate_call(marie2->lc,linphone_core_get_current_call(marie2->lc));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,3000));
}
linphone_core_manager_destroy(pauline);
@ -400,7 +400,7 @@ static void call_forking_with_push_notification_single(void){
linphone_core_set_network_reachable(marie->lc,TRUE);
/*Marie shall receive the call immediately*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,5000));
/*pauline should hear ringback as well*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000));
@ -450,7 +450,7 @@ static void call_forking_with_push_notification_multiple(void){
linphone_core_invite_address(pauline->lc,marie->identity);
/*marie1 will ring*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,5000));
/*pauline should hear ringback as well*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000));
@ -458,7 +458,7 @@ static void call_forking_with_push_notification_multiple(void){
linphone_core_set_network_reachable(marie2->lc,TRUE);
/*Marie shall receive the call immediately*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,5000));
/*marie2 accepts the call*/
linphone_core_accept_call(marie2->lc,linphone_core_get_current_call(marie2->lc));
@ -500,7 +500,7 @@ void call_forking_not_responded(void){
linphone_core_invite_address(pauline->lc,marie->identity);
/*pauline should hear ringback*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000));
/*all devices from Marie should be ringing*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000));
@ -568,9 +568,9 @@ static void early_media_call_forking(void) {
linphone_core_invite_address_with_params(pauline->lc,marie1->identity,params);
linphone_call_params_destroy(params);
CU_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,3000));
pauline_call=linphone_core_get_current_call(pauline->lc);
marie1_call=linphone_core_get_current_call(marie1->lc);
@ -583,8 +583,8 @@ static void early_media_call_forking(void) {
CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>70);
linphone_core_accept_call(marie1->lc,linphone_core_get_current_call(marie1->lc));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,3000));
/*marie2 should get her call terminated*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000));

View file

@ -181,6 +181,9 @@ typedef struct _stats {
int number_of_LinphoneConfiguringSkipped;
int number_of_LinphoneConfiguringFailed;
int number_of_LinphoneConfiguringSuccessful;
int number_of_LinphoneCallEncryptedOn;
int number_of_LinphoneCallEncryptedOff;
}stats;
typedef struct _LinphoneCoreManager {
@ -212,6 +215,7 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, Lin
void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state);
void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content);
void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message);
void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token);
LinphoneAddress * create_linphone_address(const char * domain);
bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value);

View file

@ -123,13 +123,16 @@ static void wait_core(LinphoneCore *core) {
}
}
static void simple_publish(void) {
static void simple_publish_with_expire(int expires) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneProxyConfig* proxy;
LinphonePresenceModel* presence;
linphone_core_get_default_proxy(marie->lc,&proxy);
linphone_proxy_config_edit(proxy);
if (expires >0) {
linphone_proxy_config_set_publish_expires(proxy,expires);
}
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
wait_core(marie->lc);
@ -139,6 +142,14 @@ static void simple_publish(void) {
linphone_core_manager_destroy(marie);
}
static void simple_publish() {
simple_publish_with_expire(-1);
}
static void publish_with_expires() {
simple_publish_with_expire(1);
}
static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) {
stats initial_caller=caller_mgr->stat;
stats initial_callee=callee_mgr->stat;
@ -340,6 +351,7 @@ static void presence_information(void) {
test_t presence_tests[] = {
{ "Simple Subscribe", simple_subscribe },
{ "Simple Publish", simple_publish },
{ "Simple Publish with expires", publish_with_expires },
/*{ "Call with presence", call_with_presence },*/
{ "Unsubscribe while subscribing", unsubscribe_while_subscribing },
{ "Presence information", presence_information },

View file

@ -22,6 +22,8 @@ reg_expires=3600
reg_sendregister=1
publish=0
dial_escape_plus=0
statistics_collector=sip:collector@sip.example.org
send_statistics=1
[friend_0]
url="Paupoche" <sip:pauline@sip.example.org>

View file

@ -0,0 +1,3 @@
[misc]
config-uri=file:///data/data/org.linphone.tester/files/config_files/rcfiles/marie_remote_localfile2_rc

View file

@ -90,8 +90,13 @@ static void remote_provisioning_default_values(void) {
}
static void remote_provisioning_file(void) {
LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_localfile_rc", FALSE);
LinphoneCoreManager* marie;
const LpConfig* conf;
#if ANDROID
marie = linphone_core_manager_new2("marie_remote_localfile_android_rc", FALSE);
#else
marie = linphone_core_manager_new2("marie_remote_localfile_rc", FALSE);
#endif
CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1));
conf = linphone_core_get_config( marie->lc );

View file

@ -141,7 +141,7 @@ bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int va
}
bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) {
return wait_for_until(lc_1, lc_2,counter,value,3000);
return wait_for_until(lc_1, lc_2,counter,value,10000);
}
bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) {
@ -205,6 +205,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f
mgr->v_table.notify_received=linphone_notify_received;
mgr->v_table.publish_state_changed=linphone_publish_state_changed;
mgr->v_table.configuring_status=linphone_configuration_status;
mgr->v_table.call_encryption_changed=linphone_call_encryption_changed;
reset_counters(&mgr->stat);
if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file);