diff --git a/.cproject b/.cproject
index f20bc862b..07ef2412f 100644
--- a/.cproject
+++ b/.cproject
@@ -22,7 +22,7 @@
-
+
@@ -39,20 +39,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.gitignore b/.gitignore
index 0512fc3df..2adb3b20b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,6 +41,7 @@ Specfile
.anjuta_sym_db.db
gtk-glade/version_date.h
share/linphone.desktop
+share/audio-assistant.desktop
Debug/
build/macos/Info-linphone.plist
coreapi/help/Doxyfile
diff --git a/build/android/Android.mk b/build/android/Android.mk
index f009cf295..18fbbdbfd 100755
--- a/build/android/Android.mk
+++ b/build/android/Android.mk
@@ -87,6 +87,9 @@ LOCAL_CFLAGS += -DVIDEO_ENABLED
ifeq ($(BUILD_X264),1)
LOCAL_CFLAGS += -DHAVE_X264
endif
+ifeq ($(BUILD_OPENH264),1)
+LOCAL_CFLAGS += -DHAVE_OPENH264
+endif
endif
ifeq ($(BUILD_CONTACT_HEADER),1)
@@ -175,6 +178,11 @@ LOCAL_STATIC_LIBRARIES += \
libmsx264 \
libx264
endif
+ifeq ($(BUILD_OPENH264),1)
+LOCAL_STATIC_LIBRARIES += \
+ libmsopenh264 \
+ libwels
+endif
endif
ifeq ($(BUILD_UPNP),1)
@@ -199,13 +207,12 @@ LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES)
LOCAL_CFLAGS += $(LIBLINPHONE_EXTENDED_CFLAGS)
-ifeq ($(BUILD_GPLV3_ZRTP),1)
- LOCAL_SHARED_LIBRARIES += libssl-linphone libcrypto-linphone
- LOCAL_SHARED_LIBRARIES += libbzrtp
+ifeq ($(BUILD_ZRTP),1)
+ LOCAL_STATIC_LIBRARIES += libbzrtp
endif
ifeq ($(BUILD_SRTP),1)
- LOCAL_SHARED_LIBRARIES += libsrtp
+ LOCAL_STATIC_LIBRARIES += libsrtp
endif
ifeq ($(BUILD_SQLITE),1)
diff --git a/build/redhat/README b/build/redhat/README
index 7831df9c8..a38bc3143 100644
--- a/build/redhat/README
+++ b/build/redhat/README
@@ -16,13 +16,16 @@ Download and install the repo rpmforge :
$ sudo yum install ffmpeg-devel
$ sudo yum install openldap-devel
+- Install antlr3
+ $ git clone git://git.linphone.org/antlr3.git
+ $ cd antlr3
+ $ sudo cp antlr-3.4-complete.jar /usr/share/java/antlr3.jar
+
- Download and install packages
$ sudo rpm -Uhv ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-1.3.2-1.el6.x86_64.rpm
$ sudo rpm -Uvh ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-devel-1.3.2-1.el6.x86_64.rpm
$ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-3.2-14.fc15.x86_64.rpm
$ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-devel-3.2-14.fc15.x86_64.rpm
- $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-tool-3.2-14.fc15.noarch.rpm
- $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Fedora/i386/os/Packages/antlr3-java-3.2-14.fc15.noarch.rpm
- Git repository
@@ -41,6 +44,9 @@ Download and install the repo rpmforge :
$ ./configure
$ make && make rpm
+- Compile msx264
+ $ ./autogen.sh && ./configure && make
+ $ make rpm
-Create yum repo :
$ cd rpmbuild/RPMS/*arch*/
diff --git a/configure.ac b/configure.ac
index 69b109cb3..786cb6287 100644
--- a/configure.ac
+++ b/configure.ac
@@ -767,7 +767,7 @@ AM_CONDITIONAL(ENABLE_MANUAL, test x$have_sgmltools$build_manual = xyesyes )
dnl for external use of linphone libs
LINPHONE_CFLAGS="-I${includedir} -I${includedir}/linphone"
-LINPHONE_LIBS="-L${libdir} -llinphone -llpc2xml -lxml2lpc"
+LINPHONE_LIBS="-L${libdir} -llinphone"
AC_SUBST(LINPHONE_CFLAGS)
AC_SUBST(LINPHONE_LIBS)
@@ -900,6 +900,7 @@ AC_CONFIG_FILES([
share/xml/Makefile
share/linphone.pc
share/linphone.desktop
+ share/audio-assistant.desktop
scripts/Makefile
tools/Makefile
linphone.spec
diff --git a/console/linphonec.c b/console/linphonec.c
index 4385dbb09..f08c0f94d 100644
--- a/console/linphonec.c
+++ b/console/linphonec.c
@@ -148,6 +148,7 @@ static char last_in_history[256];
#endif
//auto answer (-a) option
static bool_t auto_answer=FALSE;
+static bool_t real_early_media_sending=FALSE;
static bool_t answer_call=FALSE;
static bool_t vcap_enabled=FALSE;
static bool_t display_enabled=FALSE;
@@ -362,10 +363,17 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L
linphone_call_enable_camera (call,linphonec_camera_enabled);
id=(long)linphone_call_get_user_pointer (call);
linphonec_set_caller(from);
+ linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id);
if ( auto_answer) {
answer_call=TRUE;
+ } else if (real_early_media_sending) {
+ linphonec_out("Sending early media using real hardware\n");
+ LinphoneCallParams* callparams = linphone_core_create_default_call_parameters(lc);
+ linphone_call_params_enable_early_media_sending(callparams, TRUE);
+ if (vcap_enabled) linphone_call_params_enable_video(callparams, TRUE);
+ linphone_core_accept_early_media_with_params(lc, call, callparams);
+ linphone_call_params_destroy(callparams);
}
- linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id);
break;
case LinphoneCallOutgoingInit:
linphonec_call_identify(call);
@@ -906,6 +914,7 @@ print_usage (int exit_status)
" -l logfile specify the log file for your SIP phone\n"
" -s sipaddress specify the sip call to do at startup\n"
" -a enable auto answering for incoming calls\n"
+" --real-early-media enable sending early media using real audio/video (beware of privacy issue)\n"
" -V enable video features globally (disabled by default)\n"
" -C enable video capture only (disabled by default)\n"
" -D enable video display only (disabled by default)\n"
@@ -1229,6 +1238,10 @@ linphonec_parse_cmdline(int argc, char **argv)
{
auto_answer = TRUE;
}
+ else if (strncmp ("--real-early-media", argv[arg_num], 2) == 0)
+ {
+ real_early_media_sending = TRUE;
+ }
else if (strncmp ("-C", argv[arg_num], 2) == 0)
{
vcap_enabled = TRUE;
diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c
index 47242cdd5..e4d72e834 100644
--- a/coreapi/bellesip_sal/sal_impl.c
+++ b/coreapi/bellesip_sal/sal_impl.c
@@ -115,7 +115,13 @@ void sal_process_authentication(SalOp *op) {
belle_sip_list_t* auth_list=NULL;
belle_sip_auth_event_t* auth_event;
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));
+ }
if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) {
new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request);
@@ -132,7 +138,7 @@ void sal_process_authentication(SalOp *op) {
return;
}
- if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,&auth_list)) {
+ 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);
} else {
@@ -162,8 +168,8 @@ void sal_process_authentication(SalOp *op) {
static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){
belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_event_get_dialog(event);
SalOp* op = belle_sip_dialog_get_application_data(dialog);
- if (op && op->callbacks.process_dialog_terminated) {
- op->callbacks.process_dialog_terminated(op,event);
+ if (op && op->callbacks && op->callbacks->process_dialog_terminated) {
+ op->callbacks->process_dialog_terminated(op,event);
} else {
ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog);
}
@@ -177,8 +183,8 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e
op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
/*also reset auth count on IO error*/
op->auth_requests=0;
- if (op->callbacks.process_io_error) {
- op->callbacks.process_io_error(op,event);
+ if (op->callbacks && op->callbacks->process_io_error) {
+ op->callbacks->process_io_error(op,event);
}
} else {
/*ms_error("sal process_io_error not implemented yet for non transaction");*/
@@ -290,8 +296,8 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve
sal_op_set_privacy_from_message(op,(belle_sip_message_t*)req);
sal_op_assign_recv_headers(op,(belle_sip_message_t*)req);
- if (op->callbacks.process_request_event) {
- op->callbacks.process_request_event(op,event);
+ if (op->callbacks && op->callbacks->process_request_event) {
+ op->callbacks->process_request_event(op,event);
} else {
ms_error("sal process_request_event not implemented yet");
}
@@ -329,7 +335,7 @@ 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.process_response_event) {
+ if (op->callbacks && op->callbacks->process_response_event) {
/*handle authorization*/
switch (response_code) {
case 200:
@@ -365,7 +371,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
/*not an auth request*/
op->auth_requests=0;
}
- op->callbacks.process_response_event(op,event);
+ op->callbacks->process_response_event(op,event);
} else {
ms_error("Unhandled event response [%p]",event);
}
@@ -375,8 +381,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event);
SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
- if (op && op->callbacks.process_timeout) {
- op->callbacks.process_timeout(op,event);
+ if (op && op->callbacks && op->callbacks->process_timeout) {
+ op->callbacks->process_timeout(op,event);
} else {
ms_error("Unhandled event timeout [%p]",event);
}
@@ -393,8 +399,8 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans
trans=BELLE_SIP_TRANSACTION(server_transaction);
op = (SalOp*)belle_sip_transaction_get_application_data(trans);
- if (op && op->callbacks.process_transaction_terminated) {
- op->callbacks.process_transaction_terminated(op,event);
+ if (op && op->callbacks && op->callbacks->process_transaction_terminated) {
+ op->callbacks->process_transaction_terminated(op,event);
} else {
ms_message("Unhandled transaction terminated [%p]",trans);
}
@@ -443,6 +449,7 @@ Sal * sal_init(){
sal->refresher_retry_after=60000; /*default value in ms*/
return sal;
}
+
void sal_set_user_pointer(Sal *sal, void *user_data){
sal->up=user_data;
}
@@ -536,14 +543,22 @@ int sal_transport_available(Sal *sal, SalTransport t){
int sal_add_listen_port(Sal *ctx, SalAddress* addr){
int result;
- belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack
- ,sal_address_get_domain(addr)
- ,sal_address_get_port(addr)
- ,sal_transport_to_string(sal_address_get_transport(addr)));
+ belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack,
+ sal_address_get_domain(addr),
+ sal_address_get_port(addr),
+ sal_transport_to_string(sal_address_get_transport(addr)));
+ if (sal_address_get_port(addr)==-1 && lp==NULL){
+ int random_port=(0xDFFF&random())+1024;
+ ms_warning("This version of belle-sip doesn't support random port, choosing one here.");
+ lp = belle_sip_stack_create_listening_point(ctx->stack,
+ sal_address_get_domain(addr),
+ random_port,
+ sal_transport_to_string(sal_address_get_transport(addr)));
+ }
if (lp) {
belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive);
result = belle_sip_provider_add_listening_point(ctx->prov,lp);
- set_tls_properties(ctx);
+ if (sal_address_get_transport(addr)==SalTransportTLS) set_tls_properties(ctx);
} else {
return -1;
}
@@ -560,22 +575,34 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i
sal_address_destroy(sal_addr);
return result;
}
+
static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) {
belle_sip_provider_remove_listening_point(prov,lp);
}
+
+int sal_get_listening_port(Sal *ctx, SalTransport tr){
+ const char *tpn=sal_transport_to_string(tr);
+ belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov, tpn);
+ if (lp){
+ return belle_sip_listening_point_get_port(lp);
+ }
+ return 0;
+}
+
int sal_unlisten_ports(Sal *ctx){
const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(ctx->prov);
belle_sip_list_t * tmp_list = belle_sip_list_copy(lps);
belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,ctx->prov);
belle_sip_list_free(tmp_list);
-
ms_message("sal_unlisten_ports done");
return 0;
}
+
ortp_socket_t sal_get_socket(Sal *ctx){
ms_warning("sal_get_socket is deprecated");
return -1;
}
+
void sal_set_user_agent(Sal *ctx, const char *user_agent){
belle_sip_header_user_agent_set_products(ctx->user_agent,NULL);
belle_sip_header_user_agent_add_product(ctx->user_agent,user_agent);
diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h
index 1a38ce7dc..c203c9cb1 100644
--- a/coreapi/bellesip_sal/sal_impl.h
+++ b/coreapi/bellesip_sal/sal_impl.h
@@ -76,7 +76,8 @@ const char* sal_op_type_to_string(SalOpType type);
struct SalOp{
SalOpBase base;
- belle_sip_listener_callbacks_t callbacks;
+ const belle_sip_listener_callbacks_t *callbacks;
+ SalErrorInfo error_info;
belle_sip_client_transaction_t *pending_auth_transaction;
belle_sip_server_transaction_t* pending_server_trans;
belle_sip_server_transaction_t* pending_update_server_trans;
@@ -132,8 +133,10 @@ bool_t sal_op_is_secure(const SalOp* op);
void sal_process_authentication(SalOp *op);
belle_sip_header_contact_t* sal_op_create_contact(SalOp *op) ;
-bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size);
-void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) ;
+bool_t _sal_compute_sal_errors(belle_sip_response_t* response, SalReason* sal_reason, char* reason, size_t reason_size);
+SalReason _sal_reason_from_sip_code(int code);
+
+void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response);
/*presence*/
void sal_op_presence_fill_cbs(SalOp*op);
/*messaging*/
diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c
index 01422e224..e6262c60a 100644
--- a/coreapi/bellesip_sal/sal_op_call.c
+++ b/coreapi/bellesip_sal/sal_op_call.c
@@ -38,19 +38,8 @@ static void call_set_released_and_unref(SalOp* op) {
static void call_set_error(SalOp* op,belle_sip_response_t* response){
- SalError error=SalErrorUnknown;
- SalReason sr=SalReasonUnknown;
- belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
- char* reason=(char*)belle_sip_response_get_reason_phrase(response);
- int code = belle_sip_response_get_status_code(response);
- if (reason_header){
- reason = ms_strdup_printf("%s %s",reason,belle_sip_header_get_unparsed_value(reason_header));
- }
- sal_compute_sal_errors_from_code(code,&error,&sr);
- op->base.root->callbacks.call_failure(op,error,sr,reason,code);
- if (reason_header != NULL){
- ms_free(reason);
- }
+ sal_op_set_error_info_from_response(op,response);
+ op->base.root->callbacks.call_failure(op);
}
static void sdp_process(SalOp *h){
@@ -127,7 +116,8 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event
if (!op->dialog) {
/*call terminated very early*/
- op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503);
+ sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO error",NULL);
+ op->base.root->callbacks.call_failure(op);
call_set_released(op);
} else {
/*dialog will terminated shortly, nothing to do*/
@@ -178,7 +168,12 @@ static void cancelling_invite(SalOp* op ){
sal_op_send_request(op,cancel);
op->state=SalOpStateTerminating;
}
-
+static int vfu_retry (void *user_data, unsigned int events) {
+ SalOp *op=(SalOp *)user_data;
+ sal_call_send_vfu_request(op);
+ sal_op_unref(op);
+ return BELLE_SIP_STOP;
+}
static void call_process_response(void *op_base, const belle_sip_response_event_t *event){
SalOp* op = (SalOp*)op_base;
belle_sip_request_t* ack;
@@ -187,6 +182,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
belle_sip_request_t* req;
belle_sip_response_t* response=belle_sip_response_event_get_response(event);
int code = belle_sip_response_get_status_code(response);
+ belle_sip_header_content_type_t *header_content_type=NULL;
if (!client_transaction) {
@@ -257,7 +253,16 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
op->state=SalOpStateActive;
} else if (code >= 300 && strcmp("INVITE",belle_sip_request_get_method(req))==0){
call_set_error(op,response);
- } else {
+ } else if (code == 491
+ && strcmp("INFO",belle_sip_request_get_method(req)) == 0
+ && (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t))
+ && strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0
+ && strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) {
+ unsigned int retry_in =1000*((float)rand()/RAND_MAX);
+ belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry");
+ ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in);
+ belle_sip_object_unref(s);
+ }else {
/*ignoring*/
}
break;
@@ -290,7 +295,8 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t
if (!op->dialog) {
/*call terminated very early*/
- op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408);
+ sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL);
+ op->base.root->callbacks.call_failure(op);
call_set_released(op);
} else {
/*dialog will terminated shortly, nothing to do*/
@@ -631,13 +637,18 @@ int sal_call(SalOp *op, const char *from, const char *to){
return sal_op_send_request(op,invite);
}
+static belle_sip_listener_callbacks_t call_op_callbacks={0};
+
void sal_op_call_fill_cbs(SalOp*op) {
- op->callbacks.process_io_error=call_process_io_error;
- op->callbacks.process_response_event=call_process_response;
- op->callbacks.process_timeout=call_process_timeout;
- op->callbacks.process_transaction_terminated=call_process_transaction_terminated;
- op->callbacks.process_request_event=process_request_event;
- op->callbacks.process_dialog_terminated=process_dialog_terminated;
+ if (call_op_callbacks.process_response_event==NULL){
+ call_op_callbacks.process_io_error=call_process_io_error;
+ call_op_callbacks.process_response_event=call_process_response;
+ call_op_callbacks.process_timeout=call_process_timeout;
+ call_op_callbacks.process_transaction_terminated=call_process_transaction_terminated;
+ call_op_callbacks.process_request_event=process_request_event;
+ call_op_callbacks.process_dialog_terminated=process_dialog_terminated;
+ }
+ op->callbacks=&call_op_callbacks;
op->type=SalOpCall;
}
diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c
index 1972c97f6..4409c73a3 100644
--- a/coreapi/bellesip_sal/sal_op_events.c
+++ b/coreapi/bellesip_sal/sal_op_events.c
@@ -37,8 +37,6 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher
,unsigned int status_code
,const char* reason_phrase) {
SalOp* op = (SalOp*)user_pointer;
- SalError error=SalErrorUnknown;
- SalReason sr=SalReasonUnknown;
belle_sip_transaction_t *tr=BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher));
/*belle_sip_response_t* response=belle_sip_transaction_get_response(tr);*/
SalSubscribeStatus sss=SalSubscribeTerminated;
@@ -50,8 +48,8 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher
set_or_update_dialog(op,belle_sip_transaction_get_dialog(tr));
}
if (status_code>=200){
- sal_compute_sal_errors_from_code(status_code,&error,&sr);
- op->base.root->callbacks.subscribe_response(op,sss,error,sr);
+ sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL);
+ op->base.root->callbacks.subscribe_response(op,sss);
}else if (status_code==0){
op->base.root->callbacks.on_expire(op);
}
@@ -172,13 +170,18 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
}
}
+static belle_sip_listener_callbacks_t op_subscribe_callbacks={ 0 };
+
void sal_op_subscribe_fill_cbs(SalOp*op) {
- op->callbacks.process_io_error=subscribe_process_io_error;
- op->callbacks.process_response_event=subscribe_response_event;
- op->callbacks.process_timeout=subscribe_process_timeout;
- op->callbacks.process_transaction_terminated=subscribe_process_transaction_terminated;
- op->callbacks.process_request_event=subscribe_process_request_event;
- op->callbacks.process_dialog_terminated=subscribe_process_dialog_terminated;
+ if (op_subscribe_callbacks.process_io_error==NULL){
+ op_subscribe_callbacks.process_io_error=subscribe_process_io_error;
+ op_subscribe_callbacks.process_response_event=subscribe_response_event;
+ op_subscribe_callbacks.process_timeout=subscribe_process_timeout;
+ op_subscribe_callbacks.process_transaction_terminated=subscribe_process_transaction_terminated;
+ op_subscribe_callbacks.process_request_event=subscribe_process_request_event;
+ op_subscribe_callbacks.process_dialog_terminated=subscribe_process_dialog_terminated;
+ }
+ op->callbacks=&op_subscribe_callbacks;
op->type=SalOpSubscribe;
}
diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c
index b3124300c..a6020791e 100644
--- a/coreapi/bellesip_sal/sal_op_impl.c
+++ b/coreapi/bellesip_sal/sal_op_impl.c
@@ -62,6 +62,7 @@ void sal_op_release_impl(SalOp *op){
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans);
if (op->event) belle_sip_object_unref(op->event);
+ sal_error_info_reset(&op->error_info);
__sal_op_free(op);
return ;
}
@@ -89,18 +90,23 @@ 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);
+ }
belle_sip_header_contact_set_automatic(contact_header,op->base.root->auto_contacts);
if (op->base.root->uuid){
if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){
@@ -298,7 +304,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req
if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION)
&& !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) {
/*hmm just in case we already have authentication param in cache*/
- belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL);
+ 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*/);
@@ -334,6 +340,12 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) {
SalReason sal_reason_to_sip_code(SalReason r){
int ret=500;
switch(r){
+ case SalReasonNone:
+ ret=200;
+ break;
+ case SalReasonIOError:
+ ret=503;
+ break;
case SalReasonUnknown:
ret=400;
break;
@@ -401,110 +413,123 @@ SalReason sal_reason_to_sip_code(SalReason r){
return ret;
}
-void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) {
- *sal_err=SalErrorFailure;
+SalReason _sal_reason_from_sip_code(int code) {
+ if (code>=100 && code<300) return SalReasonNone;
+
switch(code) {
+ case 0:
+ return SalReasonIOError;
case 301:
- *sal_reason=SalReasonMovedPermanently;
- break;
+ return SalReasonMovedPermanently;
case 302:
- *sal_reason=SalReasonRedirect;
- break;
+ return SalReasonRedirect;
case 401:
case 407:
- *sal_reason=SalReasonUnauthorized;
- break;
+ return SalReasonUnauthorized;
case 403:
- *sal_reason=SalReasonForbidden;
- break;
+ return SalReasonForbidden;
case 404:
- *sal_reason=SalReasonNotFound;
- break;
+ return SalReasonNotFound;
case 408:
- *sal_reason=SalReasonRequestTimeout;
- break;
+ return SalReasonRequestTimeout;
case 410:
- *sal_reason=SalReasonGone;
- break;
+ return SalReasonGone;
case 415:
- *sal_reason=SalReasonUnsupportedContent;
- break;
+ return SalReasonUnsupportedContent;
case 422:
ms_error ("422 not implemented yet");;
break;
case 480:
- *sal_reason=SalReasonTemporarilyUnavailable;
- break;
+ return SalReasonTemporarilyUnavailable;
case 481:
- *sal_reason=SalReasonNoMatch;
- break;
+ return SalReasonNoMatch;
case 484:
- *sal_reason=SalReasonAddressIncomplete;
- break;
+ return SalReasonAddressIncomplete;
case 486:
- *sal_reason=SalReasonBusy;
- break;
+ return SalReasonBusy;
case 487:
- break;
+ return SalReasonNone;
case 488:
- *sal_reason=SalReasonNotAcceptable;
- break;
+ return SalReasonNotAcceptable;
case 491:
- *sal_reason=SalReasonRequestPending;
- break;
+ return SalReasonRequestPending;
case 501:
- *sal_reason=SalReasonNotImplemented;
- break;
+ return SalReasonNotImplemented;
case 502:
- *sal_reason=SalReasonBadGateway;
- break;
+ return SalReasonBadGateway;
case 504:
- *sal_reason=SalReasonServerTimeout;
- break;
+ return SalReasonServerTimeout;
case 600:
- *sal_reason=SalReasonDoNotDisturb;
- break;
+ return SalReasonDoNotDisturb;
case 603:
- *sal_reason=SalReasonDeclined;
- break;
+ return SalReasonDeclined;
case 503:
- *sal_reason=SalReasonServiceUnavailable;
- break;
+ return SalReasonServiceUnavailable;
default:
- if (code>=300){
- *sal_err=SalErrorFailure;
- *sal_reason=SalReasonUnknown;
- }else if (code>=100){
- *sal_err=SalErrorNone;
- *sal_reason=SalReasonUnknown;
- }else if (code==0){
- *sal_err=SalErrorNoResponse;
- }
- /* no break */
+ return SalReasonUnknown;
+ }
+ return SalReasonUnknown;
+}
+
+const SalErrorInfo *sal_error_info_none(void){
+ static SalErrorInfo none={
+ SalReasonNone,
+ "Ok",
+ 200,
+ NULL,
+ NULL
+ };
+ return &none;
+}
+
+void sal_error_info_reset(SalErrorInfo *ei){
+ if (ei->status_string){
+ ms_free(ei->status_string);
+ ei->status_string=NULL;
+ }
+ if (ei->warnings){
+ ms_free(ei->warnings);
+ ei->warnings=NULL;
+
+ }
+ if (ei->full_string){
+ ms_free(ei->full_string);
+ ei->full_string=NULL;
+ }
+ ei->protocol_code=0;
+ ei->reason=SalReasonNone;
+}
+
+void sal_error_info_set(SalErrorInfo *ei, SalReason reason, int code, const char *status_string, const char *warning){
+ sal_error_info_reset(ei);
+ if (reason==SalReasonUnknown) ei->reason=_sal_reason_from_sip_code(code);
+ else ei->reason=reason;
+ ei->protocol_code=code;
+ ei->status_string=status_string ? ms_strdup(status_string) : NULL;
+ ei->warnings=warning ? ms_strdup(warning) : NULL;
+ if (ei->status_string){
+ if (ei->warnings)
+ ei->full_string=ms_strdup_printf("%s %s",ei->status_string,ei->warnings);
+ else ei->full_string=ms_strdup(ei->status_string);
}
}
-/*return TRUE if error code*/
-bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) {
- int code = belle_sip_response_get_status_code(response);
- belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
- *sal_err=SalErrorUnknown;
- *sal_reason = SalReasonUnknown;
- if (reason_header){
- snprintf(reason
- ,reason_size
- ,"%s %s"
- ,belle_sip_response_get_reason_phrase(response)
- ,belle_sip_header_get_unparsed_value(reason_header));
- } else {
- strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size);
- }
- if (code>=400) {
- sal_compute_sal_errors_from_code(code,sal_err,sal_reason);
- return TRUE;
- } else {
- return FALSE;
- }
+void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response){
+ int code = belle_sip_response_get_status_code(response);
+ const char *reason_phrase=belle_sip_response_get_reason_phrase(response);
+ /*Remark: the reason header is to be used mainly in SIP requests, thus the use and prototype of this function should be changed.*/
+ belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
+ 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);
+}
+
+const SalErrorInfo *sal_op_get_error_info(const SalOp *op){
+ return &op->error_info;
}
void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) {
diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c
index bf7f7b82a..c346347d0 100644
--- a/coreapi/bellesip_sal/sal_op_message.c
+++ b/coreapi/bellesip_sal/sal_op_message.c
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void process_error( SalOp* op) {
if (op->dir == SalOpDirOutgoing) {
- op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed, SalReasonUnknown);
+ op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed);
} else {
ms_warning("unexpected io error for incoming message on op [%p]",op);
}
@@ -30,33 +30,20 @@ static void process_error( SalOp* op) {
static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
SalOp* op = (SalOp*)user_ctx;
-// belle_sip_object_t* source = belle_sip_io_error_event_get_source(event);
-// if (BELLE_SIP_IS_INSTANCE_OF(source,belle_sip_transaction_t)) {
-// /*reset op to make sure transaction terminated does not need op*/
-// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(source),NULL);
-// }
+ sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO Error",NULL);
process_error(op);
}
static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
SalOp* op=(SalOp*)user_ctx;
-// belle_sip_client_transaction_t *client_transaction=belle_sip_timeout_event_get_client_transaction(event);
-// belle_sip_server_transaction_t *server_transaction=belle_sip_timeout_event_get_server_transaction(event);
-// /*reset op to make sure transaction terminated does not need op*/
-// if (client_transaction) {
-// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);
-// } else {
-// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),NULL);
-// }
+ sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL);
process_error(op);
}
static void process_response_event(void *op_base, const belle_sip_response_event_t *event){
SalOp* op = (SalOp*)op_base;
- /*belle_sip_client_transaction_t *client_transaction=belle_sip_response_event_get_client_transaction(event);*/
int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
SalTextDeliveryStatus status;
- SalReason reason=SalReasonUnknown;
- SalError err=SalErrorNone;
+ sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event));
if (code>=100 && code <200)
status=SalTextDeliveryInProgress;
@@ -64,13 +51,10 @@ static void process_response_event(void *op_base, const belle_sip_response_event
status=SalTextDeliveryDone;
else
status=SalTextDeliveryFailed;
- if (status != SalTextDeliveryInProgress) {
- /*reset op to make sure transaction terminated does not need op
- belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*/
- }
- sal_compute_sal_errors_from_code(code,&err,&reason);
- op->base.root->callbacks.text_delivery_update(op,status, reason);
+
+ op->base.root->callbacks.text_delivery_update(op,status);
}
+
static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) {
return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0
&& strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0;
@@ -108,6 +92,11 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
|| (external_body=is_external_body(content_type)))) {
SalMessage salmsg;
char message_id[256]={0};
+
+ if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
+ op->pending_server_trans=server_transaction;
+ belle_sip_object_ref(op->pending_server_trans);
+
address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
@@ -136,6 +125,8 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
saliscomposing.from=from;
saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
op->base.root->callbacks.is_composing_received(op,&saliscomposing);
+ resp = belle_sip_response_create_from_request(req,200);
+ belle_sip_server_transaction_send_response(server_transaction,resp);
belle_sip_object_unref(address);
belle_sip_free(from);
} else {
@@ -146,14 +137,11 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
belle_sip_server_transaction_send_response(server_transaction,resp);
return;
}
- resp = belle_sip_response_create_from_request(req,200);
- belle_sip_server_transaction_send_response(server_transaction,resp);
}
static void process_request_event(void *op_base, const belle_sip_request_event_t *event) {
SalOp* op = (SalOp*)op_base;
sal_process_incoming_message(op,event);
- sal_op_release(op);
}
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){
@@ -187,14 +175,30 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
}
+int sal_message_reply(SalOp *op, SalReason reason){
+ if (op->pending_server_trans){
+ int code=sal_reason_to_sip_code(reason);
+ belle_sip_response_t *resp = belle_sip_response_create_from_request(
+ belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_server_trans),code);
+ belle_sip_server_transaction_send_response(op->pending_server_trans,resp);
+ return 0;
+ }else ms_error("sal_message_reply(): no server transaction");
+ return -1;
+}
+
int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) {
return sal_message_send(op,from,to,"text/plain",msg);
}
+static belle_sip_listener_callbacks_t op_message_callbacks={0};
+
void sal_op_message_fill_cbs(SalOp*op) {
- op->callbacks.process_io_error=process_io_error;
- op->callbacks.process_response_event=process_response_event;
- op->callbacks.process_timeout=process_timeout;
- op->callbacks.process_request_event=process_request_event;
+ if (op_message_callbacks.process_io_error==NULL){
+ op_message_callbacks.process_io_error=process_io_error;
+ op_message_callbacks.process_response_event=process_response_event;
+ op_message_callbacks.process_timeout=process_timeout;
+ op_message_callbacks.process_request_event=process_request_event;
+ }
+ op->callbacks=&op_message_callbacks;
op->type=SalOpMessage;
}
diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c
index 9f7d6f871..ca526fd5d 100644
--- a/coreapi/bellesip_sal/sal_op_presence.c
+++ b/coreapi/bellesip_sal/sal_op_presence.c
@@ -94,13 +94,12 @@ static void presence_response_event(void *op_base, const belle_sip_response_even
belle_sip_response_t* response=belle_sip_response_event_get_response(event);
belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
int code = belle_sip_response_get_status_code(response);
- char reason[256]={0};
- SalError error=SalErrorUnknown;
- SalReason sr=SalReasonUnknown;
belle_sip_header_expires_t* expires;
+
+ sal_op_set_error_info_from_response(op,response);
- if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) {
- ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr));
+ if (code>=300) {
+ ms_message("subscription to [%s] rejected",sal_op_get_to(op));
op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/
return;
}
@@ -267,13 +266,18 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
}
}
+static belle_sip_listener_callbacks_t op_presence_callbacks={0};
+
void sal_op_presence_fill_cbs(SalOp*op) {
- op->callbacks.process_io_error=presence_process_io_error;
- op->callbacks.process_response_event=presence_response_event;
- op->callbacks.process_timeout=presence_process_timeout;
- op->callbacks.process_transaction_terminated=presence_process_transaction_terminated;
- op->callbacks.process_request_event=presence_process_request_event;
- op->callbacks.process_dialog_terminated=presence_process_dialog_terminated;
+ if (op_presence_callbacks.process_request_event==NULL){
+ op_presence_callbacks.process_io_error=presence_process_io_error;
+ op_presence_callbacks.process_response_event=presence_response_event;
+ op_presence_callbacks.process_timeout=presence_process_timeout;
+ op_presence_callbacks.process_transaction_terminated=presence_process_transaction_terminated;
+ op_presence_callbacks.process_request_event=presence_process_request_event;
+ op_presence_callbacks.process_dialog_terminated=presence_process_dialog_terminated;
+ }
+ op->callbacks=&op_presence_callbacks;
op->type=SalOpPresence;
}
diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c
index a55042919..81a7ce724 100644
--- a/coreapi/bellesip_sal/sal_op_publish.c
+++ b/coreapi/bellesip_sal/sal_op_publish.c
@@ -35,24 +35,26 @@ static void publish_refresher_listener (belle_sip_refresher_t* refresher
}else if (status_code==0){
op->base.root->callbacks.on_expire(op);
}else if (status_code>=200){
- SalError err;
- SalReason reason;
- sal_compute_sal_errors_from_code(status_code,&err,&reason);
- op->base.root->callbacks.on_publish_response(op,err,reason);
+ sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL);
+ op->base.root->callbacks.on_publish_response(op);
}
}
static void publish_response_event(void *userctx, const belle_sip_response_event_t *event){
SalOp *op=(SalOp*)userctx;
- int code=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
- SalError err;
- SalReason reason;
- sal_compute_sal_errors_from_code(code,&err,&reason);
- op->base.root->callbacks.on_publish_response(op,err,reason);
+ sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event));
+ if (op->error_info.protocol_code>=200){
+ op->base.root->callbacks.on_publish_response(op);
+ }
}
-void sal_op_publish_fill_cbs(SalOp*op) {
- op->callbacks.process_response_event=publish_response_event;
+static belle_sip_listener_callbacks_t op_publish_callbacks={0};
+
+void sal_op_publish_fill_cbs(SalOp *op) {
+ if (op_publish_callbacks.process_response_event==NULL){
+ op_publish_callbacks.process_response_event=publish_response_event;
+ }
+ op->callbacks=&op_publish_callbacks;
op->type=SalOpPublish;
}
diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c
index 2f12d4533..17a3861b4 100644
--- a/coreapi/bellesip_sal/sal_op_registration.c
+++ b/coreapi/bellesip_sal/sal_op_registration.c
@@ -24,8 +24,6 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher
,unsigned int status_code
,const char* reason_phrase) {
SalOp* op = (SalOp*)user_pointer;
- SalError sal_err;
- SalReason sal_reason;
belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));
ms_message("Register refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op));
@@ -57,9 +55,8 @@ 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_compute_sal_errors_from_code(status_code,&sal_err,&sal_reason);
- op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase);
+ 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*/
sal_add_pending_auth(op->base.root,op);
diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c
index 080a43dcc..b2f106cef 100644
--- a/coreapi/bellesip_sal/sal_sdp.c
+++ b/coreapi/bellesip_sal/sal_sdp.c
@@ -68,26 +68,26 @@ static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const S
if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer));
}
-static belle_sdp_attribute_t * create_rtcp_xr_attribute(const SalRtcpXrDescription *desc) {
+static belle_sdp_attribute_t * create_rtcp_xr_attribute(const OrtpRtcpXrConfiguration *config) {
belle_sdp_rtcp_xr_attribute_t *attribute = belle_sdp_rtcp_xr_attribute_new();
- if (desc->rcvr_rtt_mode != SalRtcpXrRcvrRttNone) {
- if (desc->rcvr_rtt_mode == SalRtcpXrRcvrRttAll) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "all");
- else if (desc->rcvr_rtt_mode == SalRtcpXrRcvrRttSender) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "sender");
- belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_max_size(attribute, desc->rcvr_rtt_max_size);
+ if (config->rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
+ if (config->rcvr_rtt_mode == OrtpRtcpXrRcvrRttAll) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "all");
+ else if (config->rcvr_rtt_mode == OrtpRtcpXrRcvrRttSender) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "sender");
+ belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_max_size(attribute, config->rcvr_rtt_max_size);
}
- belle_sdp_rtcp_xr_attribute_set_stat_summary(attribute, (desc->stat_summary_enabled == TRUE));
- if (desc->stat_summary_enabled == TRUE) {
- if (desc->stat_summary_flags & SalRtcpXrStatSummaryLoss) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "loss");
- if (desc->stat_summary_flags & SalRtcpXrStatSummaryDup) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "dup");
- if (desc->stat_summary_flags & SalRtcpXrStatSummaryJitt) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "jitt");
- if (desc->stat_summary_flags & SalRtcpXrStatSummaryTTL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "TTL");
- if (desc->stat_summary_flags & SalRtcpXrStatSummaryHL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "HL");
+ belle_sdp_rtcp_xr_attribute_set_stat_summary(attribute, (config->stat_summary_enabled == TRUE));
+ if (config->stat_summary_enabled == TRUE) {
+ if (config->stat_summary_flags & OrtpRtcpXrStatSummaryLoss) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "loss");
+ if (config->stat_summary_flags & OrtpRtcpXrStatSummaryDup) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "dup");
+ if (config->stat_summary_flags & OrtpRtcpXrStatSummaryJitt) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "jitt");
+ if (config->stat_summary_flags & OrtpRtcpXrStatSummaryTTL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "TTL");
+ if (config->stat_summary_flags & OrtpRtcpXrStatSummaryHL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "HL");
}
- belle_sdp_rtcp_xr_attribute_set_voip_metrics(attribute, (desc->voip_metrics_enabled == TRUE));
+ belle_sdp_rtcp_xr_attribute_set_voip_metrics(attribute, (config->voip_metrics_enabled == TRUE));
return BELLE_SDP_ATTRIBUTE(attribute);
}
-static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMediaDescription *md, const SalStreamDescription *stream ) {
+static void stream_description_to_sdp ( belle_sdp_session_description_t *session_desc, const SalMediaDescription *md, const SalStreamDescription *stream ) {
belle_sdp_mime_parameter_t* mime_param;
belle_sdp_media_description_t* media_desc;
int j;
@@ -215,10 +215,27 @@ static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMedia
}
if (stream->rtcp_xr.enabled == TRUE) {
- belle_sdp_media_description_add_attribute(media_desc, create_rtcp_xr_attribute(&stream->rtcp_xr));
+ char sastr[1024] = {0};
+ char mastr[1024] = {0};
+ size_t saoff = 0;
+ size_t maoff = 0;
+ const belle_sdp_attribute_t *session_attribute = belle_sdp_session_description_get_attribute(session_desc, "rtcp-xr");
+ belle_sdp_attribute_t *media_attribute;
+ if (session_attribute != NULL) {
+ belle_sip_object_marshal((belle_sip_object_t*)session_attribute, sastr, sizeof(sastr), &saoff);
+ }
+ media_attribute = create_rtcp_xr_attribute(&stream->rtcp_xr);
+ if (media_attribute != NULL) {
+ belle_sip_object_marshal((belle_sip_object_t*)media_attribute, mastr, sizeof(mastr), &maoff);
+ }
+ if (strcmp(sastr, mastr) != 0) {
+ belle_sdp_media_description_add_attribute(media_desc, media_attribute);
+ } else {
+ belle_sip_object_unref((belle_sip_object_t*)media_attribute);
+ }
}
- return media_desc;
+ belle_sdp_session_description_add_media_description(session_desc, media_desc);
}
belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescription *desc ) {
@@ -272,7 +289,7 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
}
for ( i=0; in_total_streams; i++ ) {
- belle_sdp_session_description_add_media_description ( session_desc,stream_description_to_sdp(desc,&desc->streams[i]));
+ stream_description_to_sdp(session_desc, desc, &desc->streams[i]);
}
return session_desc;
}
@@ -304,8 +321,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S
static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
belle_sip_list_t *attribute_it;
- const belle_sdp_attribute_t *attribute;
- const belle_sdp_raw_attribute_t *raw_attribute;
+ belle_sdp_attribute_t *attribute;
char tmp[256], tmp2[256];
int valid_count = 0;
int nb;
@@ -315,10 +331,9 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med
; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL;
attribute_it=attribute_it->next ) {
attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data );
- raw_attribute=BELLE_SDP_RAW_ATTRIBUTE(attribute);
- if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_raw_attribute_get_value ( raw_attribute ) !=NULL ) {
- nb = sscanf ( belle_sdp_raw_attribute_get_value ( raw_attribute ), "%d %256s inline:%256s",
+ if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) {
+ nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s",
&stream->crypto[valid_count].tag,
tmp,
tmp2 );
@@ -345,7 +360,7 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med
valid_count++;
}
} else {
- ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_raw_attribute_get_value ( raw_attribute ),nb );
+ ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb );
}
}
}
@@ -354,17 +369,15 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med
static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
belle_sip_list_t *attribute_it;
- const belle_sdp_attribute_t *attribute;
- const belle_sdp_raw_attribute_t *raw_attribute;
+ belle_sdp_attribute_t *attribute;
const char *att_name;
const char *value;
int nb_ice_candidates = 0;
for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) {
attribute=BELLE_SDP_ATTRIBUTE(attribute_it->data);
- raw_attribute=BELLE_SDP_RAW_ATTRIBUTE(attribute);
att_name = belle_sdp_attribute_get_name(attribute);
- value = belle_sdp_raw_attribute_get_value(raw_attribute);
+ value = belle_sdp_attribute_get_value(attribute);
if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) {
SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates];
@@ -400,63 +413,63 @@ static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_
}
}
-static void sal_init_rtcp_xr_description(SalRtcpXrDescription *desc) {
- desc->enabled = FALSE;
- desc->rcvr_rtt_mode = SalRtcpXrRcvrRttNone;
- desc->rcvr_rtt_max_size = -1;
- desc->stat_summary_flags = 0;
- desc->voip_metrics_enabled = FALSE;
+static void sal_init_rtcp_xr_description(OrtpRtcpXrConfiguration *config) {
+ config->enabled = FALSE;
+ config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone;
+ config->rcvr_rtt_max_size = -1;
+ config->stat_summary_flags = 0;
+ config->voip_metrics_enabled = FALSE;
}
-static void sdp_parse_rtcp_xr_parameters(const belle_sdp_attribute_t *attribute, SalRtcpXrDescription *desc) {
- sal_init_rtcp_xr_description(desc);
-
+static void sdp_parse_rtcp_xr_parameters(const belle_sdp_attribute_t *attribute, OrtpRtcpXrConfiguration *config) {
if (attribute != NULL) {
- const belle_sdp_rtcp_xr_attribute_t *xr_attr = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute);
- const char *rcvr_rtt_mode = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(xr_attr);
+ const belle_sdp_rtcp_xr_attribute_t *xr_attr;
+ const char *rcvr_rtt_mode;
+ sal_init_rtcp_xr_description(config);
+ xr_attr = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute);
+ rcvr_rtt_mode = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(xr_attr);
if (rcvr_rtt_mode != NULL) {
if (strcasecmp(rcvr_rtt_mode, "all") == 0) {
- desc->rcvr_rtt_mode = SalRtcpXrRcvrRttAll;
+ config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll;
} else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) {
- desc->rcvr_rtt_mode = SalRtcpXrRcvrRttSender;
+ config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttSender;
}
- desc->rcvr_rtt_max_size = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_max_size(xr_attr);
+ config->rcvr_rtt_max_size = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_max_size(xr_attr);
}
- desc->stat_summary_enabled = (belle_sdp_rtcp_xr_attribute_has_stat_summary(xr_attr) != 0);
- if (desc->stat_summary_enabled) {
+ config->stat_summary_enabled = (belle_sdp_rtcp_xr_attribute_has_stat_summary(xr_attr) != 0);
+ if (config->stat_summary_enabled) {
belle_sip_list_t *stat_summary_flag_it;
for (stat_summary_flag_it = belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(xr_attr); stat_summary_flag_it != NULL; stat_summary_flag_it = stat_summary_flag_it->next ) {
const char *flag = (const char *)stat_summary_flag_it->data;
if (flag != NULL) {
- if (strcasecmp(flag, "loss") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryLoss;
- else if (strcasecmp(flag, "dup") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryDup;
- else if (strcasecmp(flag, "jitt") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryJitt;
- else if (strcasecmp(flag, "TTL") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryTTL;
- else if (strcasecmp(flag, "HL") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryHL;
+ if (strcasecmp(flag, "loss") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryLoss;
+ else if (strcasecmp(flag, "dup") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryDup;
+ else if (strcasecmp(flag, "jitt") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryJitt;
+ else if (strcasecmp(flag, "TTL") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryTTL;
+ else if (strcasecmp(flag, "HL") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryHL;
}
}
}
- desc->voip_metrics_enabled = (belle_sdp_rtcp_xr_attribute_has_voip_metrics(xr_attr) != 0);
- desc->enabled = TRUE;
+ config->voip_metrics_enabled = (belle_sdp_rtcp_xr_attribute_has_voip_metrics(xr_attr) != 0);
+ config->enabled = TRUE;
}
}
-static void sdp_parse_session_rtcp_xr_parameters(belle_sdp_session_description_t *session_desc, SalRtcpXrDescription *desc) {
+static void sdp_parse_session_rtcp_xr_parameters(belle_sdp_session_description_t *session_desc, OrtpRtcpXrConfiguration *config) {
const belle_sdp_attribute_t *attribute = belle_sdp_session_description_get_attribute(session_desc, "rtcp-xr");
- sdp_parse_rtcp_xr_parameters(attribute, desc);
+ sdp_parse_rtcp_xr_parameters(attribute, config);
}
-static void sdp_parse_media_rtcp_xr_parameters(belle_sdp_media_description_t *media_desc, SalRtcpXrDescription *desc) {
+static void sdp_parse_media_rtcp_xr_parameters(belle_sdp_media_description_t *media_desc, OrtpRtcpXrConfiguration *config) {
const belle_sdp_attribute_t *attribute = belle_sdp_media_description_get_attribute(media_desc, "rtcp-xr");
- sdp_parse_rtcp_xr_parameters(attribute, desc);
+ sdp_parse_rtcp_xr_parameters(attribute, config);
}
static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, belle_sdp_media_description_t *media_desc) {
SalStreamDescription *stream;
belle_sdp_connection_t* cnx;
belle_sdp_media_t* media;
- const belle_sdp_attribute_t* attribute;
- const belle_sdp_raw_attribute_t* raw_attribute;
+ belle_sdp_attribute_t* attribute;
const char* value;
const char *mtype,*proto;
@@ -518,8 +531,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
stream->rtcp_port = stream->rtp_port + 1;
snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr);
attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp");
- raw_attribute=BELLE_SDP_RAW_ATTRIBUTE(attribute);
- if (attribute && (value=belle_sdp_raw_attribute_get_value(raw_attribute))!=NULL){
+ if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
char tmp[256];
int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp);
if (nb == 1) {
@@ -540,6 +552,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
sdp_parse_media_ice_parameters(media_desc, stream);
/* Get RTCP-XR attributes if any */
+ stream->rtcp_xr = md->rtcp_xr; // Use session parameters if no stream parameters are defined
sdp_parse_media_rtcp_xr_parameters(media_desc, &stream->rtcp_xr);
md->n_total_streams++;
diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c
index f39700f01..efd17aab6 100644
--- a/coreapi/callbacks.c
+++ b/coreapi/callbacks.c
@@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include
#endif
-static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details);
+static void register_failure(SalOp *op);
static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) {
if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED;
@@ -58,14 +58,14 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c
rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr;
rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr;
ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
- rtp_session_set_remote_addr_full(call->audiostream->ms.session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
+ rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
}
#ifdef VIDEO_ENABLED
if (call->videostream && new_videodesc) {
rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr;
rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr;
ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
- rtp_session_set_remote_addr_full(call->videostream->ms.session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
+ rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
}
#else
(void)new_videodesc;
@@ -97,7 +97,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
sal_media_description_ref(new_md);
call->expect_media_in_ack=FALSE;
call->resultdesc=new_md;
- if ((call->audiostream && call->audiostream->ms.ticker) || (call->videostream && call->videostream->ms.ticker)){
+ if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){
/* we already started media: check if we really need to restart it*/
if (oldmd){
int md_changed = media_parameters_changed(call, oldmd, new_md);
@@ -143,8 +143,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){
send_ringbacktone=TRUE;
}
- if (call->state==LinphoneCallIncomingEarlyMedia ||
- (call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){
+ if ((call->state==LinphoneCallIncomingEarlyMedia || call->state==LinphoneCallOutgoingEarlyMedia) && !call->params.real_early_media){
all_muted=TRUE;
}
linphone_call_start_media_streams(call,all_muted,send_ringbacktone);
@@ -206,7 +205,8 @@ static void call_received(SalOp *h){
const char *from,*to;
char *alt_contact;
LinphoneAddress *from_addr, *to_addr;
- bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE);
+ /*this mode is deprcated because probably useless*/
+ bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",FALSE);
/* first check if we can answer successfully to this invite */
if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) {
@@ -549,7 +549,7 @@ static void call_terminated(SalOp *op, const char *from){
break;
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
- call->reason=LinphoneReasonNotAnswered;
+ sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,0,"Incoming call cancelled",NULL);
break;
default:
break;
@@ -592,14 +592,15 @@ static int resume_call_after_failed_transfer(LinphoneCall *call){
return BELLE_SIP_STOP;
}
-static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){
+static void call_failure(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
+ const SalErrorInfo *ei=sal_op_get_error_info(op);
char *msg486=_("User is busy.");
char *msg480=_("User is temporarily unavailable.");
/*char *retrymsg=_("%s. Retry after %i minute(s).");*/
char *msg600=_("User does not want to be disturbed.");
char *msg603=_("Call declined.");
- const char *msg=details;
+ const char *msg=ei->full_string;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
LinphoneCall *referer=call->referer;
@@ -609,102 +610,94 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
}
if (lc->vtable.show) lc->vtable.show(lc);
-
- if (error==SalErrorNoResponse){
- msg=_("No response.");
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc,msg);
- }else if (error==SalErrorProtocol){
- msg=details ? details : _("Protocol error.");
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc, msg);
- }else if (error==SalErrorFailure){
- switch(sr){
- case SalReasonDeclined:
- msg=msg603;
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc,msg603);
- break;
- case SalReasonBusy:
- msg=msg486;
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc,msg486);
- break;
- case SalReasonRedirect:
- {
- ms_error("case SalReasonRedirect");
- linphone_call_stop_media_streams(call);
- if ( call->state==LinphoneCallOutgoingInit
+ switch(ei->reason){
+ case SalReasonNone:
+ break;
+ case SalReasonRequestTimeout:
+ msg=_("Request timeout.");
+ if (lc->vtable.display_status)
+ lc->vtable.display_status(lc,msg);
+ break;
+ case SalReasonDeclined:
+ msg=msg603;
+ if (lc->vtable.display_status)
+ lc->vtable.display_status(lc,msg603);
+ break;
+ case SalReasonBusy:
+ msg=msg486;
+ if (lc->vtable.display_status)
+ lc->vtable.display_status(lc,msg486);
+ break;
+ case SalReasonRedirect:
+ {
+ linphone_call_stop_media_streams(call);
+ if ( call->state==LinphoneCallOutgoingInit
+ || call->state==LinphoneCallOutgoingProgress
+ || call->state==LinphoneCallOutgoingRinging /*push case*/
+ || call->state==LinphoneCallOutgoingEarlyMedia){
+ LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op);
+ if( redirection_to ){
+ char* url = linphone_address_as_string(redirection_to);
+ ms_warning("Redirecting call [%p] to %s",call, url);
+ ms_free(url);
+ linphone_call_create_op(call);
+ linphone_core_start_invite(lc, call, redirection_to);
+ return;
+ }
+ }
+ msg=_("Redirected");
+ if (lc->vtable.display_status)
+ lc->vtable.display_status(lc,msg);
+ }
+ break;
+ case SalReasonTemporarilyUnavailable:
+ msg=msg480;
+ if (lc->vtable.display_status)
+ lc->vtable.display_status(lc,msg480);
+ break;
+ case SalReasonNotFound:
+ if (lc->vtable.display_status)
+ lc->vtable.display_status(lc,msg);
+ break;
+ case SalReasonDoNotDisturb:
+ msg=msg600;
+ if (lc->vtable.display_status)
+ lc->vtable.display_status(lc,msg600);
+ break;
+ case SalReasonUnsupportedContent: /*params.media_encryption == LinphoneMediaEncryptionSRTP &&
+ !linphone_core_is_media_encryption_mandatory(lc)) {
+ int i;
+ ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call);
+ if (call->state==LinphoneCallOutgoingInit
|| call->state==LinphoneCallOutgoingProgress
|| call->state==LinphoneCallOutgoingRinging /*push case*/
|| call->state==LinphoneCallOutgoingEarlyMedia){
- LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op);
- if( redirection_to ){
- char* url = linphone_address_as_string(redirection_to);
- ms_error("Redirecting call [%p] to %s",call, url);
- ms_free(url);
- linphone_call_create_op(call);
- linphone_core_start_invite(lc, call, redirection_to);
- return;
+ ms_message("Retrying call [%p] with AVP",call);
+ /* clear SRTP local params */
+ call->params.media_encryption = LinphoneMediaEncryptionNone;
+ for(i=0; ilocaldesc->n_active_streams; i++) {
+ call->localdesc->streams[i].proto = SalProtoRtpAvp;
+ memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
}
+ linphone_core_restart_invite(lc, call);
+ return;
}
- msg=_("Redirected");
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc,msg);
}
- break;
- case SalReasonTemporarilyUnavailable:
- msg=msg480;
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc,msg480);
- break;
- case SalReasonNotFound:
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc,msg);
- break;
- case SalReasonDoNotDisturb:
- msg=msg600;
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc,msg600);
- break;
- case SalReasonUnsupportedContent: /*params.media_encryption == LinphoneMediaEncryptionSRTP &&
- !linphone_core_is_media_encryption_mandatory(lc)) {
- int i;
- ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call);
- linphone_call_stop_media_streams(call);
- if ( call->state==LinphoneCallOutgoingInit
- || call->state==LinphoneCallOutgoingProgress
- || call->state==LinphoneCallOutgoingRinging /*push case*/
- || call->state==LinphoneCallOutgoingEarlyMedia){
- ms_message("Retrying call [%p] with AVP",call);
- /* clear SRTP local params */
- call->params.media_encryption = LinphoneMediaEncryptionNone;
- for(i=0; ilocaldesc->n_active_streams; i++) {
- call->localdesc->streams[i].proto = SalProtoRtpAvp;
- memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
- }
- linphone_core_restart_invite(lc, call);
- return;
- }
-
- }
- msg=_("Incompatible media parameters.");
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc,msg);
- break;
- case SalReasonRequestPending:
- /*restore previous state, the application will decide to resubmit the action if relevant*/
- call->reason=linphone_reason_from_sal(sr);
- linphone_call_set_state(call,call->prevstate,msg);
- return;
- break;
- default:
- if (lc->vtable.display_status)
- lc->vtable.display_status(lc,_("Call failed."));
- }
+ msg=_("Incompatible media parameters.");
+ if (lc->vtable.display_status)
+ lc->vtable.display_status(lc,msg);
+ break;
+ case SalReasonRequestPending:
+ /*restore previous state, the application will decide to resubmit the action if relevant*/
+ linphone_call_set_state(call,call->prevstate,msg);
+ return;
+ break;
+ default:
+ if (lc->vtable.display_status)
+ lc->vtable.display_status(lc,_("Call failed."));
}
/*some call error are not fatal*/
@@ -713,8 +706,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
case LinphoneCallPausing:
case LinphoneCallResuming:
ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate));
- call->reason=linphone_reason_from_sal(sr);
- linphone_call_set_state(call, call->prevstate,details);
+ linphone_call_set_state(call, call->prevstate,ei->full_string);
return;
default:
break; /*nothing to do*/
@@ -727,13 +719,14 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
linphone_call_delete_upnp_session(call);
#endif //BUILD_UPNP
- call->reason=linphone_reason_from_sal(sr);
- if (sr==SalReasonDeclined){
- linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
- }else{
- linphone_call_set_state(call,LinphoneCallError,details);
+ if (call->state!=LinphoneCallEnd && call->state!=LinphoneCallError){
+ if (ei->reason==SalReasonDeclined){
+ linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
+ }else{
+ linphone_call_set_state(call,LinphoneCallError,ei->full_string);
+ }
+ if (ei->reason!=SalReasonNone) linphone_core_play_call_error_tone(lc,linphone_reason_from_sal(ei->reason));
}
- linphone_core_play_call_error_tone(lc,call->reason);
if (referer){
/*notify referer of the failure*/
@@ -772,7 +765,6 @@ static void register_success(SalOp *op, bool_t registered){
ms_message("Registration success for removed proxy config, ignored");
return;
}
- linphone_proxy_config_set_error(cfg,LinphoneReasonNone);
linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared ,
registered ? "Registration successful" : "Unregistration done");
if (lc->vtable.display_status){
@@ -784,9 +776,11 @@ static void register_success(SalOp *op, bool_t registered){
}
-static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
+static void register_failure(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
+ const SalErrorInfo *ei=sal_op_get_error_info(op);
+ const char *details=ei->full_string;
if (cfg==NULL){
ms_warning("Registration failed for unknown proxy config.");
@@ -800,15 +794,12 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const
details=_("no response timeout");
if (lc->vtable.display_status) {
- char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details );
+ char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op), details);
lc->vtable.display_status(lc,msg);
ms_free(msg);
}
- linphone_proxy_config_set_error(cfg,linphone_reason_from_sal(reason));
-
- if (error== SalErrorFailure
- && reason == SalReasonServiceUnavailable
+ if ((ei->reason == SalReasonServiceUnavailable || ei->reason == SalReasonIOError)
&& linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) {
linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying"));
} else {
@@ -886,9 +877,12 @@ static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){
static void text_received(SalOp *op, const SalMessage *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
- if (is_duplicate_msg(lc,msg->message_id)==FALSE){
+ LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
+ if (lc->chat_deny_code==LinphoneReasonNone && is_duplicate_msg(lc,msg->message_id)==FALSE){
linphone_core_message_received(lc,op,msg);
}
+ sal_message_reply(op,linphone_reason_to_sal(lc->chat_deny_code));
+ if (!call) sal_op_release(op);
}
static void is_composing_received(SalOp *op, const SalIsComposing *is_composing) {
@@ -1030,22 +1024,15 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus sta
return LinphoneChatMessageStateIdle;
}
-static int op_equals(LinphoneCall *a, SalOp *b) {
- return a->op !=b; /*return 0 if equals*/
-}
-
-static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status, SalReason reason){
+static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op);
- const MSList* calls;
if (chat_msg == NULL) {
// Do not handle delivery status for isComposing messages.
return;
}
- calls = linphone_core_get_calls(chat_msg->chat_room->lc);
chat_msg->state=chatStatusSal2Linphone(status);
- chat_msg->reason=linphone_reason_from_sal(reason);
linphone_chat_message_store_state(chat_msg);
if (chat_msg && chat_msg->cb) {
ms_message("Notifying text delivery with status %i",chat_msg->state);
@@ -1055,11 +1042,6 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status, SalRea
}
if (status != SalTextDeliveryInProgress) { /*don't release op if progress*/
linphone_chat_message_destroy(chat_msg);
-
- if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) {
- /*op was only create for messaging purpose, destroying*/
- sal_op_release(op);
- }
}
}
@@ -1068,7 +1050,7 @@ static void info_received(SalOp *op, const SalBody *body){
linphone_core_notify_info_message(lc,op,body);
}
-static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason){
+static void subscribe_response(SalOp *op, SalSubscribeStatus status){
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
if (lev==NULL) return;
@@ -1078,7 +1060,6 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError er
}else if (status==SalSubscribePending){
linphone_event_set_state(lev,LinphoneSubscriptionPending);
}else{
- linphone_event_set_reason(lev, linphone_reason_from_sal(reason));
linphone_event_set_state(lev,LinphoneSubscriptionError);
}
}
@@ -1120,18 +1101,18 @@ static void subscribe_closed(SalOp *op){
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
}
-static void on_publish_response(SalOp* op, SalError err, SalReason reason){
+static void on_publish_response(SalOp* op){
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
+ const SalErrorInfo *ei=sal_op_get_error_info(op);
if (lev==NULL) return;
- if (err==SalErrorNone){
+ if (ei->reason==SalReasonNone){
if (!lev->terminating)
linphone_event_set_publish_state(lev,LinphonePublishOk);
else
linphone_event_set_publish_state(lev,LinphonePublishCleared);
}else{
- linphone_event_set_reason(lev,linphone_reason_from_sal(reason));
linphone_event_set_publish_state(lev,LinphonePublishError);
}
}
diff --git a/coreapi/chat.c b/coreapi/chat.c
index bb944e1cc..ef01b8b11 100644
--- a/coreapi/chat.c
+++ b/coreapi/chat.c
@@ -37,6 +37,31 @@
* @{
*/
+/**
+ * Inconditionnaly disable incoming chat messages.
+ * @param lc the core
+ * @param deny_reason the deny reason (#LinphoneReasonNone has no effect).
+**/
+void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason){
+ lc->chat_deny_code=deny_reason;
+}
+
+/**
+ * Enable reception of incoming chat messages.
+ * By default it is enabled but it can be disabled with linphone_core_disable_chat().
+ * @param lc the core
+**/
+void linphone_core_enable_chat(LinphoneCore *lc){
+ lc->chat_deny_code=LinphoneReasonNone;
+}
+
+/**
+ * Returns whether chat is enabled.
+**/
+bool_t linphone_core_chat_enabled(const LinphoneCore *lc){
+ return lc->chat_deny_code!=LinphoneReasonNone;
+}
+
/**
* Returns an array of chat rooms
* @param lc #LinphoneCore object
@@ -160,7 +185,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
identity=linphone_proxy_config_get_identity(proxy);
}else identity=linphone_core_get_primary_contact(cr->lc);
/*sending out of calls*/
- op = sal_op_new(cr->lc->sal);
+ msg->op = op = sal_op_new(cr->lc->sal);
linphone_configure_op(cr->lc,op,cr->peer_url,msg->custom_headers,lp_config_get_int(cr->lc->config,"sip","chat_msg_with_contact",0));
sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/
}
@@ -779,6 +804,7 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg)
* Destroys a LinphoneChatMessage.
**/
void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
+ if (msg->op) sal_op_release(msg->op);
if (msg->message) ms_free(msg->message);
if (msg->external_body_url) ms_free(msg->external_body_url);
if (msg->from) linphone_address_destroy(msg->from);
@@ -787,9 +813,17 @@ void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
ms_free(msg);
}
+/**
+ * Get full details about delivery error of a chat message.
+ * @param msg a LinphoneChatMessage
+ * @return a LinphoneErrorInfo describing the details.
+**/
+const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg){
+ return linphone_error_info_from_sal_op(msg->op);
+}
LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg) {
- return msg->reason;
+ return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg));
}
/**
diff --git a/coreapi/event.c b/coreapi/event.c
index 6a7930943..731412153 100644
--- a/coreapi/event.c
+++ b/coreapi/event.c
@@ -107,6 +107,9 @@ void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState s
if (lc->vtable.publish_state_changed){
lc->vtable.publish_state_changed(lev->lc,lev,state);
}
+ if (state==LinphonePublishCleared){
+ linphone_event_unref(lev);
+ }
}
}
@@ -114,12 +117,12 @@ LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){
return lev->publish_state;
}
-void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason){
- lev->reason=reason;
+const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev){
+ return linphone_error_info_from_sal_op(lev->op);
}
LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){
- return lev->reason;
+ return linphone_error_info_get_reason(linphone_event_get_error_info(lev));
}
LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
@@ -291,7 +294,8 @@ void linphone_event_terminate(LinphoneEvent *lev){
if (lev->publish_state!=LinphonePublishNone){
if (lev->publish_state==LinphonePublishOk){
sal_publish(lev->op,NULL,NULL,NULL,0,NULL);
- }
+ }else sal_op_stop_refreshing(lev->op);
+ linphone_event_set_publish_state(lev,LinphonePublishCleared);
return;
}
diff --git a/coreapi/event.h b/coreapi/event.h
index e01ab9414..5985d1c96 100644
--- a/coreapi/event.h
+++ b/coreapi/event.h
@@ -207,6 +207,11 @@ LINPHONE_PUBLIC int linphone_event_update_publish(LinphoneEvent *lev, const Linp
**/
LINPHONE_PUBLIC LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev);
+/**
+ * Get full details about an error occured.
+**/
+const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev);
+
/**
* Get subscription state. If the event object was not created by a subscription mechanism, #LinphoneSubscriptionNone is returned.
**/
diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c
index 0e69bf546..41a92140f 100644
--- a/coreapi/linphonecall.c
+++ b/coreapi/linphonecall.c
@@ -82,6 +82,14 @@ const char* linphone_call_get_authentication_token(LinphoneCall *call){
return call->auth_token;
}
+/**
+ * Returns whether ZRTP authentication token is verified.
+ * If not, it must be verified by users as described in ZRTP procedure.
+ * Once done, the application must inform of the results with linphone_call_set_authentication_token_verified().
+ * @param call the LinphoneCall
+ * @return TRUE if authentication token is verifed, false otherwise.
+ * @ingroup call_control
+**/
bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
return call->auth_token_verified;
}
@@ -172,17 +180,24 @@ static void linphone_call_audiostream_auth_token_ready(void *data, const char* a
ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
}
+/**
+ * Set the result of ZRTP short code verification by user.
+ * If remote party also does the same, it will update the ZRTP cache so that user's verification will not be required for the two users.
+ * @param call the LinphoneCall
+ * @param verified whether the ZRTP SAS is verified.
+ * @ingroup call_control
+**/
void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
if (call->audiostream==NULL){
ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
}
- if (call->audiostream->ms.zrtp_context==NULL){
+ if (call->audiostream->ms.sessions.zrtp_context==NULL){
ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
}
if (!call->auth_token_verified && verified){
- ortp_zrtp_sas_verified(call->audiostream->ms.zrtp_context);
+ ortp_zrtp_sas_verified(call->audiostream->ms.sessions.zrtp_context);
}else if (call->auth_token_verified && !verified){
- ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context);
+ ortp_zrtp_sas_reset_verified(call->audiostream->ms.sessions.zrtp_context);
}
call->auth_token_verified=verified;
propagate_encryption_changed(call);
@@ -260,22 +275,26 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){
static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) {
LinphoneCore *lc = call->core;
+ int i;
md->rtcp_xr.enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_enabled", 0);
if (md->rtcp_xr.enabled == TRUE) {
const char *rcvr_rtt_mode = lp_config_get_string(lc->config, "rtp", "rtcp_xr_rcvr_rtt_mode", "none");
- if (strcasecmp(rcvr_rtt_mode, "all") == 0) md->rtcp_xr.rcvr_rtt_mode = SalRtcpXrRcvrRttAll;
- else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) md->rtcp_xr.rcvr_rtt_mode = SalRtcpXrRcvrRttSender;
- else md->rtcp_xr.rcvr_rtt_mode = SalRtcpXrRcvrRttNone;
- if (md->rtcp_xr.rcvr_rtt_mode != SalRtcpXrRcvrRttNone) {
+ if (strcasecmp(rcvr_rtt_mode, "all") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll;
+ else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttSender;
+ else md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone;
+ if (md->rtcp_xr.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(lc->config, "rtp", "rtcp_xr_rcvr_rtt_max_size", 0);
}
md->rtcp_xr.stat_summary_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_stat_summary_enabled", 0);
if (md->rtcp_xr.stat_summary_enabled == TRUE) {
- md->rtcp_xr.stat_summary_flags = SalRtcpXrStatSummaryLoss | SalRtcpXrStatSummaryDup | SalRtcpXrStatSummaryJitt | SalRtcpXrStatSummaryTTL;
+ md->rtcp_xr.stat_summary_flags = OrtpRtcpXrStatSummaryLoss | OrtpRtcpXrStatSummaryDup | OrtpRtcpXrStatSummaryJitt | OrtpRtcpXrStatSummaryTTL;
}
md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_enabled", 0);
}
+ for (i = 0; i < md->n_active_streams; i++) {
+ memcpy(&md->streams[i].rtcp_xr, &md->rtcp_xr, sizeof(md->streams[i].rtcp_xr));
+ }
}
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
@@ -314,8 +333,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr));
strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr));
strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1);
- md->streams[0].rtp_port=call->audio_port;
- md->streams[0].rtcp_port=call->audio_port+1;
+ md->streams[0].rtp_port=call->media_ports[0].rtp_port;
+ md->streams[0].rtcp_port=call->media_ports[0].rtcp_port;
md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
SalProtoRtpSavp : SalProtoRtpAvp;
md->streams[0].type=SalAudio;
@@ -331,8 +350,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
if (call->params.has_video){
md->n_active_streams++;
strncpy(md->streams[0].name,"Video",sizeof(md->streams[0].name)-1);
- md->streams[1].rtp_port=call->video_port;
- md->streams[1].rtcp_port=call->video_port+1;
+ md->streams[1].rtp_port=call->media_ports[1].rtp_port;
+ md->streams[1].rtcp_port=call->media_ports[1].rtcp_port;
md->streams[1].proto=md->streams[0].proto;
md->streams[1].type=SalVideo;
l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
@@ -374,34 +393,19 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
}
}
-static int find_port_offset(LinphoneCore *lc, SalStreamType type){
+static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){
int offset;
MSList *elem;
int tried_port;
int existing_port;
bool_t already_used=FALSE;
+
for(offset=0;offset<100;offset+=2){
- switch (type) {
- default:
- case SalAudio:
- tried_port=linphone_core_get_audio_port (lc)+offset;
- break;
- case SalVideo:
- tried_port=linphone_core_get_video_port (lc)+offset;
- break;
- }
+ tried_port=base_port+offset;
already_used=FALSE;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
- switch (type) {
- default:
- case SalAudio:
- existing_port = call->audio_port;
- break;
- case SalVideo:
- existing_port = call->video_port;
- break;
- }
+ existing_port=call->media_ports[stream_index].rtp_port;
if (existing_port==tried_port) {
already_used=TRUE;
break;
@@ -416,37 +420,19 @@ static int find_port_offset(LinphoneCore *lc, SalStreamType type){
return offset;
}
-static int select_random_port(LinphoneCore *lc, SalStreamType type) {
+static int select_random_port(LinphoneCore *lc, int stream_index, int min_port, int max_port) {
MSList *elem;
int nb_tries;
int tried_port = 0;
int existing_port = 0;
- int min_port = 0, max_port = 0;
bool_t already_used = FALSE;
- switch (type) {
- default:
- case SalAudio:
- linphone_core_get_audio_port_range(lc, &min_port, &max_port);
- break;
- case SalVideo:
- linphone_core_get_video_port_range(lc, &min_port, &max_port);
- break;
- }
tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
if (tried_port < min_port) tried_port = min_port + 2;
for (nb_tries = 0; nb_tries < 100; nb_tries++) {
for (elem = lc->calls; elem != NULL; elem = elem->next) {
LinphoneCall *call = (LinphoneCall *)elem->data;
- switch (type) {
- default:
- case SalAudio:
- existing_port = call->audio_port;
- break;
- case SalVideo:
- existing_port = call->video_port;
- break;
- }
+ existing_port=call->media_ports[stream_index].rtp_port;
if (existing_port == tried_port) {
already_used = TRUE;
break;
@@ -461,8 +447,31 @@ static int select_random_port(LinphoneCore *lc, SalStreamType type) {
return tried_port;
}
-static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
+static void port_config_set_random(LinphoneCall *call, int stream_index){
+ call->media_ports[stream_index].rtp_port=-1;
+ call->media_ports[stream_index].rtcp_port=-1;
+}
+
+static void port_config_set(LinphoneCall *call, int stream_index, int min_port, int max_port){
int port_offset;
+ if (min_port>0 && max_port>0){
+ if (min_port == max_port) {
+ /* Used fixed RTP audio port. */
+ port_offset=find_port_offset(call->core, stream_index, min_port);
+ if (port_offset==-1) {
+ port_config_set_random(call, stream_index);
+ return;
+ }
+ call->media_ports[stream_index].rtp_port=min_port+port_offset;
+ } else {
+ /* Select random RTP audio port in the specified range. */
+ call->media_ports[stream_index].rtp_port = select_random_port(call->core, stream_index, min_port, max_port);
+ }
+ call->media_ports[stream_index].rtcp_port=call->media_ports[stream_index].rtp_port+1;
+ }else port_config_set_random(call,stream_index);
+}
+
+static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
int min_port, max_port;
call->magic=linphone_call_magic;
@@ -475,25 +484,11 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
call->camera_enabled=TRUE;
linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
- if (min_port == max_port) {
- /* Used fixed RTP audio port. */
- port_offset=find_port_offset (call->core, SalAudio);
- if (port_offset==-1) return;
- call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
- } else {
- /* Select random RTP audio port in the specified range. */
- call->audio_port = select_random_port(call->core, SalAudio);
- }
+ port_config_set(call,0,min_port,max_port);
+
linphone_core_get_video_port_range(call->core, &min_port, &max_port);
- if (min_port == max_port) {
- /* Used fixed RTP video port. */
- port_offset=find_port_offset (call->core, SalVideo);
- if (port_offset==-1) return;
- call->video_port=linphone_core_get_video_port(call->core)+port_offset;
- } else {
- /* Select random RTP video port in the specified range. */
- call->video_port = select_random_port(call->core, SalVideo);
- }
+ 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);
}
@@ -644,20 +639,22 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
// In this case WE chose the media parameters according to policy.
call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
}
-
+ /*create the ice session now if ICE is required*/
+ if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseIce){
+ call->ice_session = ice_session_new();
+ ice_session_set_role(call->ice_session, IR_Controlled);
+ }
+ /*reserve the sockets immediately*/
+ linphone_call_init_media_streams(call);
switch (linphone_core_get_firewall_policy(call->core)) {
case LinphonePolicyUseIce:
- call->ice_session = ice_session_new();
- ice_session_set_role(call->ice_session, IR_Controlled);
+ /*start ICE gathering*/
linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
- if (call->ice_session != NULL) {
- linphone_call_init_media_streams(call);
- 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_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);
}
break;
case LinphonePolicyUseStun:
@@ -669,7 +666,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
if(!lc->rtp_conf.disable_upnp) {
call->upnp_session = linphone_upnp_session_new(call);
if (call->upnp_session != NULL) {
- linphone_call_init_media_streams(call);
if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
@@ -695,6 +691,11 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
static void linphone_call_set_terminated(LinphoneCall *call){
LinphoneCore *lc=call->core;
+ linphone_call_stop_media_streams(call);
+ ms_media_stream_sessions_uninit(&call->sessions[0]);
+ ms_media_stream_sessions_uninit(&call->sessions[1]);
+ linphone_call_delete_upnp_session(call);
+ linphone_call_delete_ice_session(call);
linphone_core_update_allocated_audio_bandwidth(lc);
call->owns_call_log=FALSE;
@@ -789,11 +790,11 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
call->state=cstate;
}
if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
- switch(call->reason){
- case LinphoneReasonDeclined:
+ switch(call->non_op_error.reason){
+ case SalReasonDeclined:
call->log->status=LinphoneCallDeclined;
break;
- case LinphoneReasonNotAnswered:
+ case SalReasonRequestTimeout:
call->log->status=LinphoneCallMissed;
break;
default:
@@ -810,6 +811,11 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
lc->vtable.call_state_changed(lc,call,cstate,message);
if (cstate==LinphoneCallReleased){
if (call->op!=NULL) {
+ /*transfer the last error so that it can be obtained even in Released state*/
+ if (call->non_op_error.reason==SalReasonNone){
+ const SalErrorInfo *ei=sal_op_get_error_info(call->op);
+ sal_error_info_set(&call->non_op_error,ei->reason,ei->protocol_code,ei->status_string,ei->warnings);
+ }
/* so that we cannot have anymore upcalls for SAL
concerning this call*/
sal_op_release(call->op);
@@ -832,11 +838,6 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
static void linphone_call_destroy(LinphoneCall *obj)
{
ms_message("Call [%p] freed.",obj);
- linphone_call_stop_media_streams(obj);
-#ifdef BUILD_UPNP
- linphone_call_delete_upnp_session(obj);
-#endif //BUILD_UPNP
- linphone_call_delete_ice_session(obj);
if (obj->op!=NULL) {
sal_op_release(obj->op);
obj->op=NULL;
@@ -873,6 +874,7 @@ static void linphone_call_destroy(LinphoneCall *obj)
}
linphone_call_params_uninit(&obj->params);
linphone_call_params_uninit(&obj->current_params);
+ sal_error_info_reset(&obj->non_op_error);
ms_free(obj);
}
@@ -994,7 +996,16 @@ LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
* Returns the reason for a call termination (either error or normal termination)
**/
LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
- return call->reason;
+ return linphone_error_info_get_reason(linphone_call_get_error_info(call));
+}
+
+/**
+ * Returns full details about call errors or termination reasons.
+**/
+const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call){
+ if (call->non_op_error.reason!=SalReasonNone){
+ return (const LinphoneErrorInfo*)&call->non_op_error;
+ }else return linphone_error_info_from_sal_op(call->op);
}
/**
@@ -1410,17 +1421,31 @@ void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, Lin
call->nextVideoFrameDecoded._func = cb;
call->nextVideoFrameDecoded._user_data = user_data;
#ifdef VIDEO_ENABLED
- ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
+ if (call->videostream && call->videostream->ms.decoder)
+ ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
#endif
}
+static void port_config_set_random_choosed(LinphoneCall *call, int stream_index, RtpSession *session){
+ call->media_ports[stream_index].rtp_port=rtp_session_get_local_port(session);
+ call->media_ports[stream_index].rtcp_port=rtp_session_get_local_rtcp_port(session);
+}
+
void linphone_call_init_audio_stream(LinphoneCall *call){
LinphoneCore *lc=call->core;
AudioStream *audiostream;
int dscp;
if (call->audiostream != NULL) return;
- call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,call->af==AF_INET6);
+ if (call->sessions[0].rtp_session==NULL){
+ call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6);
+ }else{
+ call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]);
+ }
+ audiostream=call->audiostream;
+ if (call->media_ports[0].rtp_port==-1){
+ port_config_set_random_choosed(call,0,audiostream->ms.sessions.rtp_session);
+ }
dscp=linphone_core_get_audio_dscp(lc);
if (dscp!=-1)
audio_stream_set_dscp(audiostream,dscp);
@@ -1452,68 +1477,73 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
if (lc->rtptf){
- RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
- RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
- rtp_session_set_transports(audiostream->ms.session,artp,artcp);
+ RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[0].rtp_port);
+ 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.session, TRUE);
- rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
+ 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.session);
+ 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.session,call->audiostream_app_evq);
+ rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq);
}
void linphone_call_init_video_stream(LinphoneCall *call){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
- if (!call->params.has_video) {
- linphone_call_stop_video_stream(call);
- return;
- }
- if (call->videostream != NULL) return;
- if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
+ if (call->videostream == NULL){
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);
-
- call->videostream=video_stream_new(call->video_port,call->video_port+1,call->af==AF_INET6);
+
+ 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{
+ call->videostream=video_stream_new_with_sessions(&call->sessions[1]);
+ }
+ if (call->media_ports[1].rtp_port==-1){
+ port_config_set_random_choosed(call,1,call->videostream->ms.sessions.rtp_session);
+ }
if (dscp!=-1)
video_stream_set_dscp(call->videostream,dscp);
video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
- if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
+ if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.sessions.rtp_session,video_recv_buf_size);
if (display_filter != NULL)
video_stream_set_display_filter_name(call->videostream,display_filter);
video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
if (lc->rtptf){
- RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
- RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
- rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
+ RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[1].rtp_port);
+ RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[1].rtcp_port);
+ rtp_session_set_transports(call->videostream->ms.sessions.rtp_session,vrtp,vrtcp);
}
- if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
- rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
- rtp_session_set_symmetric_rtp(call->videostream->ms.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.session);
- ms_message ("creating new ice video check list [%p] for session [%p]",call->videostream->ms.ice_check_list,call->videostream->ms.session);
- }
- call->videostream_app_evq = ortp_ev_queue_new();
- rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
+ call->videostream_app_evq = ortp_ev_queue_new();
+ rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq);
#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
@@ -1717,6 +1747,49 @@ static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned
return -1;
}
+static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *call, SalStreamType type) {
+ RtpSession *session;
+ const OrtpRtcpXrConfiguration *localconfig;
+ const OrtpRtcpXrConfiguration *remoteconfig;
+ OrtpRtcpXrConfiguration currentconfig;
+ const SalStreamDescription *localstream;
+ const SalStreamDescription *remotestream;
+
+ localstream = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, type);
+ if (!localstream) localstream = sal_media_description_find_stream(call->localdesc, SalProtoRtpAvp, type);
+ if (!localstream) return;
+ localconfig = &localstream->rtcp_xr;
+ remotestream = sal_media_description_find_stream(sal_call_get_remote_media_description(call->op), SalProtoRtpSavp, type);
+ if (!remotestream) remotestream = sal_media_description_find_stream(sal_call_get_remote_media_description(call->op), SalProtoRtpAvp, type);
+ if (!remotestream) return;
+ remoteconfig = &remotestream->rtcp_xr;
+
+ if (localstream->dir == SalStreamInactive) return;
+ else if (localstream->dir == SalStreamRecvOnly) {
+ /* Use local config for unilateral parameters and remote config for collaborative parameters. */
+ memcpy(¤tconfig, localconfig, sizeof(currentconfig));
+ currentconfig.rcvr_rtt_mode = remoteconfig->rcvr_rtt_mode;
+ currentconfig.rcvr_rtt_max_size = remoteconfig->rcvr_rtt_max_size;
+ } else {
+ memcpy(¤tconfig, remoteconfig, sizeof(currentconfig));
+ }
+ if (type == SalAudio) {
+ session = call->audiostream->ms.sessions.rtp_session;
+ } else {
+ session = call->videostream->ms.sessions.rtp_session;
+ }
+ rtp_session_configure_rtcp_xr(session, ¤tconfig);
+ if (currentconfig.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
+ rtp_session_set_rtcp_xr_rcvr_rtt_interval(session, lp_config_get_int(lc->config, "rtp", "rtcp_xr_rcvr_rtt_interval_duration", 5000));
+ }
+ if (currentconfig.stat_summary_enabled == TRUE) {
+ rtp_session_set_rtcp_xr_stat_summary_interval(session, lp_config_get_int(lc->config, "rtp", "rtcp_xr_stat_summary_interval_duration", 5000));
+ }
+ if (currentconfig.voip_metrics_enabled == TRUE) {
+ rtp_session_set_rtcp_xr_voip_metrics_interval(session, lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_interval_duration", 5000));
+ }
+}
+
static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
LinphoneCore *lc=call->core;
int used_pt=-1;
@@ -1811,6 +1884,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
call->audiostream_encrypted=FALSE;
}
}else call->audiostream_encrypted=FALSE;
+ configure_rtp_session_for_rtcp_xr(lc, call, SalAudio);
audio_stream_start_full(
call->audiostream,
call->audio_profile,
@@ -1932,7 +2006,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
}else{
call->videostream_encrypted=FALSE;
}
-
+ configure_rtp_session_for_rtcp_xr(lc, call, SalVideo);
+
call->log->video_enabled = TRUE;
video_stream_set_direction (call->videostream, dir);
ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
@@ -2087,14 +2162,16 @@ void linphone_call_delete_ice_session(LinphoneCall *call){
}
}
-#ifdef BUILD_UPNP
+
void linphone_call_delete_upnp_session(LinphoneCall *call){
+#ifdef BUILD_UPNP
if(call->upnp_session!=NULL) {
linphone_upnp_session_destroy(call->upnp_session);
call->upnp_session=NULL;
}
-}
#endif //BUILD_UPNP
+}
+
static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
float quality=media_stream_get_average_quality_rating(st);
@@ -2107,7 +2184,8 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
void linphone_call_stop_audio_stream(LinphoneCall *call) {
if (call->audiostream!=NULL) {
- rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
+ 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);
ortp_ev_queue_destroy(call->audiostream_app_evq);
call->audiostream_app_evq=NULL;
@@ -2134,7 +2212,8 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) {
void linphone_call_stop_video_stream(LinphoneCall *call) {
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL){
- rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
+ 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);
ortp_ev_queue_destroy(call->videostream_app_evq);
call->videostream_app_evq=NULL;
@@ -2605,12 +2684,12 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
if ((call->state==LinphoneCallStreamsRunning || call->state==LinphoneCallOutgoingEarlyMedia || call->state==LinphoneCallIncomingEarlyMedia) && one_second_elapsed){
float audio_load=0, video_load=0;
if (call->audiostream!=NULL){
- if (call->audiostream->ms.ticker)
- audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
+ if (call->audiostream->ms.sessions.ticker)
+ audio_load=ms_ticker_get_average_load(call->audiostream->ms.sessions.ticker);
}
if (call->videostream!=NULL){
- if (call->videostream->ms.ticker)
- video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
+ if (call->videostream->ms.sessions.ticker)
+ video_load=ms_ticker_get_average_load(call->videostream->ms.sessions.ticker);
}
report_bandwidth(call,(MediaStream*)call->audiostream,(MediaStream*)call->videostream);
ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
@@ -2637,20 +2716,22 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
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.session);
+ 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.session), sizeof(jitter_stats_t));
+ 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]);
@@ -2680,20 +2761,22 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
} 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.session);
+ 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.session), sizeof(jitter_stats_t));
+ 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]);
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index c4fffd030..6c609d037 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -536,8 +536,25 @@ static void sound_config_read(LinphoneCore *lc)
/*alsadev let the user use custom alsa device within linphone*/
devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
if (devid){
- MSSndCard *card=ms_alsa_card_new_custom(devid,devid);
- ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card);
+ MSSndCard* card;
+ const char* delim=",";
+ size_t l=strlen(devid);
+ char* d=malloc(l+1);
+ char* i;
+ memcpy(d,devid,l+1);
+ for (l=0,i=strpbrk(d+l,delim);i;i=strpbrk(d+l,delim)){
+ char s=*i;
+ *i='\0';
+ card=ms_alsa_card_new_custom(d+l,d+l);
+ ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card);
+ *i=s;
+ l=i-d+1;
+ }
+ if(d[l]!='\0') {
+ card=ms_alsa_card_new_custom(d+l,d+l);
+ ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card);
+ }
+ free(d);
}
tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
@@ -615,11 +632,13 @@ static void sound_config_read(LinphoneCore *lc)
static void certificates_config_read(LinphoneCore *lc)
{
+ const char *rootca;
#ifdef __linux
- sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs"));
+ rootca=lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs");
#else
- sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE));
+ rootca=lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE);
#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));
}
@@ -1350,7 +1369,7 @@ 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=1");
+ linphone_core_assign_payload_type(lc,&payload_type_opus,-1,"useinbandfec=1; usedtx=0; cbr=1");
linphone_core_assign_payload_type(lc,&payload_type_isac,-1,NULL);
linphone_core_handle_static_payloads(lc);
@@ -1369,6 +1388,8 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
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);
@@ -1521,7 +1542,7 @@ static void update_primary_contact(LinphoneCore *lc){
lc->sip_conf.loopback_only=TRUE;
}else lc->sip_conf.loopback_only=FALSE;
linphone_address_set_domain(url,tmp);
- linphone_address_set_port(url,linphone_core_get_sip_port (lc));
+ linphone_address_set_port(url,linphone_core_get_sip_port(lc));
guessed=linphone_address_as_string(url);
lc->sip_conf.guessed_contact=guessed;
linphone_address_destroy(url);
@@ -1734,6 +1755,8 @@ void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc,bool_t rtp_no_
/**
* Sets the UDP port used for audio streaming.
+ * A value if -1 will request the system to allocate the local port randomly.
+ * This is recommended in order to avoid firewall warnings.
*
* @ingroup network_parameters
**/
@@ -1754,6 +1777,8 @@ void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_
/**
* Sets the UDP port used for video streaming.
+ * A value if -1 will request the system to allocate the local port randomly.
+ * This is recommended in order to avoid firewall warnings.
*
* @ingroup network_parameters
**/
@@ -1833,8 +1858,9 @@ void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833)
**/
int linphone_core_get_sip_port(LinphoneCore *lc)
{
- LCSipTransports *tr=&lc->sip_conf.transports;
- return tr->udp_port>0 ? tr->udp_port : (tr->tcp_port > 0 ? tr->tcp_port : tr->tls_port);
+ LCSipTransports tr;
+ linphone_core_get_sip_transports_used(lc,&tr);
+ return tr.udp_port>0 ? tr.udp_port : (tr.tcp_port > 0 ? tr.tcp_port : tr.tls_port);
}
#if !USE_BELLE_SIP
@@ -1918,25 +1944,23 @@ static int apply_transports(LinphoneCore *lc){
anyaddr="0.0.0.0";
sal_unlisten_ports(sal);
- if (tr->udp_port>0){
+ 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){
+ if (tr->tcp_port!=0){
if (sal_listen_port (sal,anyaddr,tr->tcp_port,SalTransportTCP,FALSE)!=0){
transport_error(lc,"tcp",tr->tcp_port);
}
}
- if (tr->tls_port>0){
+ 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);
-
return 0;
}
@@ -1951,37 +1975,24 @@ bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTra
* Sets the ports to be used for each of transport (UDP or TCP)
*
* A zero value port for a given transport means the transport
- * is not used.
+ * is not used. A value of LC_SIP_TRANSPORT_RANDOM (-1) means the port is to be choosen randomly by the system.
*
* @ingroup network_parameters
**/
int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports * tr_config /*config to be saved*/){
LCSipTransports tr=*tr_config;
- int random_port=(0xDFFF&random())+1024;
if (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1) {
/*legacy random mode*/
if (tr.udp_port>0){
- tr.udp_port=random_port;
- tr.tls_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/
- }else if (tr.tcp_port>0){
- tr.tcp_port=random_port;
- tr.tls_port=tr.udp_port=0; /*make sure only one transport is active at a time*/
- }else if (tr.tls_port>0){
- tr.tls_port=random_port;
- tr.udp_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/
- } else {
- tr.udp_port=random_port;
+ tr.udp_port=LC_SIP_TRANSPORT_RANDOM;
+ }
+ if (tr.tcp_port>0){
+ tr.tcp_port=LC_SIP_TRANSPORT_RANDOM;
+ }
+ if (tr.tls_port>0){
+ tr.tls_port=LC_SIP_TRANSPORT_RANDOM;
}
- }
- if (tr.udp_port == LC_SIP_TRANSPORT_RANDOM) {
- tr.udp_port=random_port;
- }
- if (tr.tcp_port == LC_SIP_TRANSPORT_RANDOM) {
- tr.tcp_port=random_port;
- }
- if (tr.tls_port == LC_SIP_TRANSPORT_RANDOM) {
- tr.tls_port=random_port+1;
}
if (tr.udp_port==0 && tr.tcp_port==0 && tr.tls_port==0){
@@ -2003,9 +2014,9 @@ int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports * t
}
/**
- * Retrieves the ports used for each transport (udp, tcp).
+ * Retrieves the port configuration used for each transport (udp, tcp, tls).
* A zero value port for a given transport means the transport
- * is not used.
+ * is not used. A value of LC_SIP_TRANSPORT_RANDOM (-1) means the port is to be choosen randomly by the system.
* @ingroup network_parameters
**/
int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *tr){
@@ -2013,6 +2024,18 @@ int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *tr){
return 0;
}
+/**
+ * Retrieves the real port number assigned for each sip transport (udp, tcp, tls).
+ * A zero value means that the transport is not activated.
+ * If LC_SIP_TRANSPORT_RANDOM was passed to linphone_core_set_sip_transports(), the random port choosed by the system is returned.
+ * @ingroup network_parameters
+ * @param tr a LCSipTransports structure.
+**/
+void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCSipTransports *tr){
+ tr->udp_port=sal_get_listening_port(lc->sal,SalTransportUDP);
+ tr->tcp_port=sal_get_listening_port(lc->sal,SalTransportTCP);
+ tr->tls_port=sal_get_listening_port(lc->sal,SalTransportTLS);
+}
/**
* Sets the UDP port to be used by SIP.
*
@@ -2281,7 +2304,7 @@ void linphone_core_iterate(LinphoneCore *lc){
ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout);
decline_reason=lc->current_call ? LinphoneReasonBusy : LinphoneReasonDeclined;
call->log->status=LinphoneCallMissed;
- call->reason=LinphoneReasonNotAnswered;
+ sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,408,"Not answered",NULL);
linphone_core_decline_call(lc,call,decline_reason);
}
}
@@ -2526,7 +2549,6 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L
for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
const char *domain=linphone_proxy_config_get_domain(cfg);
-/* ms_warning("Checking %s / %s %s", domain, linphone_address_get_domain(uri), linphone_proxy_config_get_route(cfg)); */
if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){
if (linphone_proxy_config_register_enabled(cfg)) {
found_cfg=cfg;
@@ -2540,7 +2562,7 @@ end:
if (!found_cfg && found_noreg_cfg) found_cfg = found_noreg_cfg;
if (found_cfg && found_cfg!=default_cfg){
ms_debug("Overriding default proxy setting for this call/message/subscribe operation.");
- }
+ }else if (!found_cfg) found_cfg=default_cfg; /*when no matching proxy config is found, use the default proxy config*/
return found_cfg;
}
@@ -2586,6 +2608,10 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c
int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call){
linphone_call_create_op(call);
+ linphone_call_stop_media_streams(call);
+ ms_media_stream_sessions_uninit(&call->sessions[0]);
+ ms_media_stream_sessions_uninit(&call->sessions[1]);
+ linphone_call_init_media_streams(call);
return linphone_core_start_invite(lc,call, NULL);
}
@@ -2597,7 +2623,6 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const Linph
linphone_call_set_contact_op(call);
linphone_core_stop_dtmf_stream(lc);
- linphone_call_init_media_streams(call);
linphone_call_make_local_media_description(lc,call);
if (lc->ringstream==NULL) {
@@ -2784,7 +2809,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
lc->vtable.display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls"));
return NULL;
}
- linphone_core_get_default_proxy(lc,&proxy);
real_url=linphone_address_as_string(addr);
proxy=linphone_core_lookup_known_proxy(lc,addr);
@@ -2809,9 +2833,9 @@ 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");
+ 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_init_media_streams(call);
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) {
@@ -2824,7 +2848,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
}
else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
#ifdef BUILD_UPNP
- linphone_call_init_media_streams(call);
call->log->start_date_time=time(NULL);
if (linphone_core_update_upnp(lc,call)<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
@@ -3038,7 +3061,6 @@ int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall*
// if parameters are passed, update the media description
if ( params ) {
- md = sal_call_get_remote_media_description ( call->op );
_linphone_call_params_copy ( &call->params,params );
linphone_call_make_local_media_description ( lc,call );
sal_call_set_local_media_description ( call->op,call->localdesc );
@@ -3264,6 +3286,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const
}
return _linphone_core_accept_call_update(lc, call, params);
}
+
int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
SalMediaDescription *remote_desc;
bool_t keep_sdp_version;
@@ -3294,13 +3317,13 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons
call->params.has_video = FALSE;
}
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->ice_session != NULL) && !ice_session_candidates_gathered(call->ice_session)) {
if ((call->params.has_video) && (call->params.has_video != old_has_video)) {
- 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. */
@@ -3316,7 +3339,6 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons
linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op));
#ifdef VIDEO_ENABLED
if ((call->params.has_video) && (call->params.has_video != old_has_video)) {
- linphone_call_init_video_stream(call);
video_stream_prepare_video(call->videostream);
if (linphone_core_update_upnp(lc, call)<0) {
/* uPnP update failed, proceed with the call anyway. */
@@ -3419,9 +3441,6 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
sal_op_set_sent_custom_header(call->op,params->custom_headers);
}
- if (call->audiostream==NULL)
- linphone_call_init_media_streams(call);
-
/*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);
@@ -3431,7 +3450,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate);
}
- if (!was_ringing && call->audiostream->ms.ticker==NULL){
+ if (!was_ringing && call->audiostream->ms.state==MSStreamInitialized){
audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
}
@@ -3471,8 +3490,8 @@ int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *e
static void terminate_call(LinphoneCore *lc, LinphoneCall *call){
if (call->state==LinphoneCallIncomingReceived){
- if (call->reason!=LinphoneReasonNotAnswered)
- call->reason=LinphoneReasonDeclined;
+ if (call->non_op_error.reason!=SalReasonRequestTimeout)
+ call->non_op_error.reason=SalReasonDeclined;
}
/*stop ringing*/
linphone_core_stop_ringing(lc);
@@ -3491,7 +3510,7 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){
int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri){
if (call->state==LinphoneCallIncomingReceived){
sal_call_decline(call->op,SalReasonRedirect,redirect_uri);
- call->reason=LinphoneReasonDeclined;
+ sal_error_info_set(&call->non_op_error,SalReasonRedirect,603,"Call redirected",NULL);
terminate_call(lc,call);
}else{
ms_error("Bad state for call redirection.");
@@ -4349,6 +4368,10 @@ const char *linphone_core_get_ring(const LinphoneCore *lc){
**/
void linphone_core_set_root_ca(LinphoneCore *lc,const char *path){
sal_set_root_ca(lc->sal, path);
+ if (lc->http_verify_policy){
+ belle_tls_verify_policy_set_root_ca(lc->http_verify_policy,path);
+ }
+ lp_config_set_string(lc->config,"sip","root_ca",path);
}
/**
@@ -4359,7 +4382,7 @@ void linphone_core_set_root_ca(LinphoneCore *lc,const char *path){
* @ingroup initializing
**/
const char *linphone_core_get_root_ca(LinphoneCore *lc){
- return sal_get_root_ca(lc->sal);
+ return lp_config_get_string(lc->config,"sip","root_ca",NULL);
}
/**
@@ -4369,6 +4392,10 @@ const char *linphone_core_get_root_ca(LinphoneCore *lc){
**/
void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){
sal_verify_server_certificates(lc->sal,yesno);
+ if (lc->http_verify_policy){
+ belle_tls_verify_policy_set_exceptions(lc->http_verify_policy, yesno ? 0 : BELLE_TLS_VERIFY_ANY_REASON);
+ }
+ lp_config_set_int(lc->config,"sip","verify_server_certs",yesno);
}
/**
@@ -4377,6 +4404,10 @@ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){
**/
void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){
sal_verify_server_cn(lc->sal,yesno);
+ if (lc->http_verify_policy){
+ belle_tls_verify_policy_set_exceptions(lc->http_verify_policy, yesno ? 0 : BELLE_TLS_VERIFY_CN_MISMATCH);
+ }
+ lp_config_set_int(lc->config,"sip","verify_server_cn",yesno);
}
static void notify_end_of_ring(void *ud, MSFilter *f, unsigned int event, void *arg){
@@ -5338,7 +5369,7 @@ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){
}
if (file!=NULL) {
lc->play_file=ms_strdup(file);
- if (call && call->audiostream && call->audiostream->ms.ticker)
+ if (call && call->audiostream && call->audiostream->ms.state==MSStreamStarted)
audio_stream_play(call->audiostream,file);
}
}
@@ -5613,9 +5644,6 @@ void net_config_uninit(LinphoneCore *lc)
{
net_config_t *config=&lc->net_conf;
- if (lc->http_provider) {
- belle_sip_object_unref(lc->http_provider);
- }
if (config->stun_server!=NULL){
ms_free(config->stun_server);
}
@@ -5690,6 +5718,14 @@ void sip_config_uninit(LinphoneCore *lc)
sal_reset_transports(lc->sal);
sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/
+ if (lc->http_provider) {
+ belle_sip_object_unref(lc->http_provider);
+ lc->http_provider=NULL;
+ }
+ if (lc->http_verify_policy){
+ belle_sip_object_unref(lc->http_verify_policy);
+ lc->http_verify_policy=NULL;
+ }
sal_iterate(lc->sal); /*make sure event are purged*/
sal_uninit(lc->sal);
lc->sal=NULL;
@@ -6153,6 +6189,8 @@ const char *linphone_reason_to_string(LinphoneReason err){
return "Bad gateway";
case LinphoneReasonServerTimeout:
return "Server timeout";
+ case LinphoneReasonUnknown:
+ return "Unknown error";
}
return "unknown error";
}
diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h
index 9d3ecb455..f4f34b8c6 100644
--- a/coreapi/linphonecore.h
+++ b/coreapi/linphonecore.h
@@ -159,6 +159,7 @@ typedef struct _LinphoneCall LinphoneCall;
* Enum describing various failure reasons or contextual information for some events.
* @see linphone_call_get_reason()
* @see linphone_proxy_config_get_error()
+ * @see linphone_error_info_get_reason()
* @ingroup misc
**/
enum _LinphoneReason{
@@ -181,7 +182,8 @@ enum _LinphoneReason{
LinphoneReasonAddressIncomplete, /**GetStringUTFChars(jfactoryConfig, NULL):NULL;
LinphoneCoreData* ldata = new LinphoneCoreData(env,thiz,jlistener,juserdata);
+ ms_init(); // Initialize mediastreamer2 before loading the plugins
+
#ifdef HAVE_ILBC
libmsilbc_init(); // requires an fpu
#endif
#ifdef HAVE_X264
libmsx264_init();
#endif
+#ifdef HAVE_OPENH264
+ libmsopenh264_init();
+#endif
#ifdef HAVE_AMR
libmsamr_init();
#endif
@@ -776,6 +785,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env
,jlong lc) {
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc);
linphone_core_destroy((LinphoneCore*)lc);
+ ms_exit();
delete lcData;
}
@@ -798,6 +808,10 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCallImpl_sendInfoMessage(J
return linphone_call_send_info_message((LinphoneCall*)callptr,(LinphoneInfoMessage*)infoptr);
}
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_stopRinging(JNIEnv* env, jobject thiz, jlong lc) {
+ linphone_core_stop_ringing((LinphoneCore*)lc);
+}
+
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setChatDatabasePath(JNIEnv* env, jobject thiz, jlong lc, jstring jpath) {
const char* path = env->GetStringUTFChars(jpath, NULL);
linphone_core_set_chat_database_path((LinphoneCore*)lc, path);
@@ -805,8 +819,8 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setChatDatabasePath(JNIE
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv* env, jobject thiz, jlong lc, jstring jdisplayname, jstring jusername) {
- const char* displayname = env->GetStringUTFChars(jdisplayname, NULL);
- const char* username = env->GetStringUTFChars(jusername, NULL);
+ const char* displayname = jdisplayname ? env->GetStringUTFChars(jdisplayname, NULL) : NULL;
+ const char* username = jusername ? env->GetStringUTFChars(jusername, NULL) : NULL;
LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc);
if (parsed != NULL) {
@@ -816,8 +830,8 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv
linphone_core_set_primary_contact((LinphoneCore*)lc, contact);
}
- env->ReleaseStringUTFChars(jdisplayname, displayname);
- env->ReleaseStringUTFChars(jusername, username);
+ if (jdisplayname) env->ReleaseStringUTFChars(jdisplayname, displayname);
+ if (jusername) env->ReleaseStringUTFChars(jusername, username);
}
extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getPrimaryContactUsername(JNIEnv* env, jobject thiz, jlong lc) {
@@ -1455,6 +1469,34 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createProxyConfig(JNIEn
return (jlong) proxy;
}
+/*
+ * Class: org_linphone_core_LinphoneCoreImpl
+ * Method: disableChat
+ * Signature: (JI)V
+ */
+extern "C" JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_disableChat(JNIEnv *env, jobject jobj, jlong ptr, jint reason){
+ linphone_core_disable_chat((LinphoneCore*)ptr,(LinphoneReason)reason);
+}
+
+/*
+ * Class: org_linphone_core_LinphoneCoreImpl
+ * Method: enableChat
+ * Signature: (J)V
+ */
+extern "C" JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableChat(JNIEnv *env, jobject jobj, jlong ptr){
+ linphone_core_enable_chat((LinphoneCore*)ptr);
+}
+
+/*
+ * Class: org_linphone_core_LinphoneCoreImpl
+ * Method: chatEnabled
+ * Signature: (J)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_chatEnabled(JNIEnv *env, jobject jobj, jlong ptr){
+ return (jboolean) linphone_core_chat_enabled((LinphoneCore*)ptr);
+}
+
+
//ProxyConfig
extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) {
@@ -1622,6 +1664,10 @@ extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getError(JNIEnv*
return linphone_proxy_config_get_error((LinphoneProxyConfig *) ptr);
}
+extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_getErrorInfo(JNIEnv* env,jobject thiz,jlong ptr) {
+ return (jlong)linphone_proxy_config_get_error_info((LinphoneProxyConfig *) ptr);
+}
+
//Auth Info
extern "C" jlong Java_org_linphone_core_LinphoneAuthInfoImpl_newLinphoneAuthInfo(JNIEnv* env
@@ -2074,6 +2120,18 @@ extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getRemoteAddress( JNIEn
return (jlong)linphone_call_get_remote_address((LinphoneCall*)ptr);
}
+extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getErrorInfo( JNIEnv* env
+ ,jobject thiz
+ ,jlong ptr) {
+ return (jlong)linphone_call_get_error_info((LinphoneCall*)ptr);
+}
+
+extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getReason( JNIEnv* env
+ ,jobject thiz
+ ,jlong ptr) {
+ return (jint)linphone_call_get_reason((LinphoneCall*)ptr);
+}
+
extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getRemoteUserAgent(JNIEnv *env, jobject thiz, jlong ptr) {
LinphoneCall *call = (LinphoneCall *)ptr;
const char *value=linphone_call_get_remote_user_agent(call);
@@ -2400,6 +2458,12 @@ extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getReason(JNIEnv*
return linphone_chat_message_get_reason((LinphoneChatMessage*)ptr);
}
+extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getErrorInfo(JNIEnv* env
+ ,jobject thiz
+ ,jlong ptr) {
+ return (jlong)linphone_chat_message_get_error_info((LinphoneChatMessage*)ptr);
+}
+
extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getCustomHeader(JNIEnv* env
,jobject thiz
,jlong ptr, jstring jheader_name) {
@@ -3684,6 +3748,11 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getReason(JNIEnv
return linphone_event_get_reason(ev);
}
+JNIEXPORT jlong JNICALL Java_org_linphone_core_LinphoneEventImpl_getErrorInfo(JNIEnv *env, jobject jobj, jlong evptr){
+ LinphoneEvent *ev=(LinphoneEvent*)evptr;
+ return (jlong)linphone_event_get_error_info(ev);
+}
+
/*
* Class: org_linphone_core_LinphoneEventImpl
* Method: getSubscriptionDir
@@ -4616,4 +4685,49 @@ JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_isSdp200AckEn
return (jboolean)linphone_core_sdp_200_ack_enabled((const LinphoneCore*)lc);
}
+/* Header for class org_linphone_core_ErrorInfoImpl */
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_linphone_core_ErrorInfoImpl
+ * Method: getReason
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_linphone_core_ErrorInfoImpl_getReason(JNIEnv *env, jobject jobj, jlong ei){
+ return linphone_error_info_get_reason((const LinphoneErrorInfo*)ei);
+}
+
+/*
+ * Class: org_linphone_core_ErrorInfoImpl
+ * Method: getProtocolCode
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_linphone_core_ErrorInfoImpl_getProtocolCode(JNIEnv *env, jobject jobj, jlong ei){
+ return linphone_error_info_get_protocol_code((const LinphoneErrorInfo*)ei);
+}
+
+/*
+ * Class: org_linphone_core_ErrorInfoImpl
+ * Method: getPhrase
+ * Signature: (J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getPhrase(JNIEnv *env, jobject jobj, jlong ei){
+ const char *tmp=linphone_error_info_get_phrase((const LinphoneErrorInfo*)ei);
+ return tmp ? env->NewStringUTF(tmp) : NULL;
+}
+
+/*
+ * Class: org_linphone_core_ErrorInfoImpl
+ * Method: getDetails
+ * Signature: (J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getDetails(JNIEnv *env, jobject jobj, jlong ei){
+ const char *tmp=linphone_error_info_get_details((const LinphoneErrorInfo*)ei);
+ return tmp ? env->NewStringUTF(tmp) : NULL;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c
index feaff8cd1..8df196df2 100644
--- a/coreapi/lpconfig.c
+++ b/coreapi/lpconfig.c
@@ -324,8 +324,9 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename){
}
void lp_item_set_value(LpItem *item, const char *value){
- ortp_free(item->value);
+ char *prev_value=item->value;
item->value=ortp_strdup(value);
+ ortp_free(prev_value);
}
diff --git a/coreapi/misc.c b/coreapi/misc.c
index b2dd6774e..37198490e 100644
--- a/coreapi/misc.c
+++ b/coreapi/misc.c
@@ -375,6 +375,10 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
ms_warning("stun support is not implemented for ipv6");
return -1;
}
+ if (call->media_ports[0].rtp_port==-1){
+ ms_warning("Stun-only support not available for system random port");
+ return -1;
+ }
if (server!=NULL){
const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc);
ortp_socket_t sock1=-1, sock2=-1;
@@ -394,10 +398,10 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
lc->vtable.display_status(lc,_("Stun lookup in progress..."));
/*create the two audio and video RTP sockets, and send STUN message to our stun server */
- sock1=create_socket(call->audio_port);
+ sock1=create_socket(call->media_ports[0].rtp_port);
if (sock1==-1) return -1;
if (video_enabled){
- sock2=create_socket(call->video_port);
+ sock2=create_socket(call->media_ports[1].rtp_port);
if (sock2==-1) return -1;
}
got_audio=FALSE;
@@ -581,14 +585,14 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
return -1;
}
if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) {
- ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
- ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
+ ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtp_port, 1, NULL);
+ ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtcp_port, 2, NULL);
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
}
- if (call->params.has_video && (video_check_list != NULL)
+ if (linphone_core_video_enabled(lc) && (video_check_list != NULL)
&& (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) {
- ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
- ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
+ ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtp_port, 1, NULL);
+ ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtcp_port, 2, NULL);
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
}
@@ -883,7 +887,12 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
}
}
for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) {
- ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
+ IceCheckList *removed=ice_session_check_list(call->ice_session, i - 1);
+ ice_session_remove_check_list(call->ice_session, removed);
+ if (call->audiostream && call->audiostream->ms.ice_check_list==removed)
+ call->audiostream->ms.ice_check_list=NULL;
+ if (call->videostream && call->videostream->ms.ice_check_list==removed)
+ call->videostream->ms.ice_check_list=NULL;
}
ice_session_check_mismatch(call->ice_session);
} else {
@@ -1100,9 +1109,9 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
SalReason linphone_reason_to_sal(LinphoneReason reason){
switch(reason){
case LinphoneReasonNone:
- return SalReasonUnknown;
+ return SalReasonNone;
case LinphoneReasonNoResponse:
- return SalReasonUnknown;
+ return SalReasonRequestTimeout;
case LinphoneReasonForbidden:
return SalReasonForbidden;
case LinphoneReasonDeclined:
@@ -1139,6 +1148,8 @@ SalReason linphone_reason_to_sal(LinphoneReason reason){
return SalReasonServerTimeout;
case LinphoneReasonNotAnswered:
return SalReasonRequestTimeout;
+ case LinphoneReasonUnknown:
+ return SalReasonUnknown;
}
return SalReasonUnknown;
}
@@ -1146,9 +1157,15 @@ SalReason linphone_reason_to_sal(LinphoneReason reason){
LinphoneReason linphone_reason_from_sal(SalReason r){
LinphoneReason ret=LinphoneReasonNone;
switch(r){
- case SalReasonUnknown:
+ case SalReasonNone:
ret=LinphoneReasonNone;
break;
+ case SalReasonIOError:
+ ret=LinphoneReasonIOError;
+ break;
+ case SalReasonUnknown:
+ ret=LinphoneReasonUnknown;
+ break;
case SalReasonBusy:
ret=LinphoneReasonBusy;
break;
@@ -1213,6 +1230,52 @@ LinphoneReason linphone_reason_from_sal(SalReason r){
return ret;
}
+/**
+ * Get reason code from the error info.
+ * @param ei the error info.
+ * @return a #LinphoneReason
+ * @ingroup misc
+**/
+LinphoneReason linphone_error_info_get_reason(const LinphoneErrorInfo *ei){
+ const SalErrorInfo *sei=(const SalErrorInfo*)ei;
+ return linphone_reason_from_sal(sei->reason);
+}
+
+/**
+ * Get textual phrase from the error info.
+ * This is the text that is provided by the peer in the protocol (SIP).
+ * @param ei the error info.
+ * @return the error phrase
+ * @ingroup misc
+**/
+const char *linphone_error_info_get_phrase(const LinphoneErrorInfo *ei){
+ const SalErrorInfo *sei=(const SalErrorInfo*)ei;
+ return sei->status_string;
+}
+
+/**
+ * Provides additional information regarding the failure.
+ * With SIP protocol, the "Reason" and "Warning" headers are returned.
+ * @param ei the error info.
+ * @return more details about the failure.
+ * @ingroup misc
+**/
+const char *linphone_error_info_get_details(const LinphoneErrorInfo *ei){
+ const SalErrorInfo *sei=(const SalErrorInfo*)ei;
+ return sei->warnings;
+}
+
+/**
+ * Get the status code from the low level protocol (ex a SIP status code).
+ * @param ei the error info.
+ * @return the status code.
+ * @ingroup misc
+**/
+int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei){
+ const SalErrorInfo *sei=(const SalErrorInfo*)ei;
+ return sei->protocol_code;
+}
+
/**
* Set the name of the mediastreamer2 filter to be used for rendering video.
* This is for advanced users of the library, mainly to workaround hardware/driver bugs.
@@ -1308,7 +1371,7 @@ int linphone_core_migrate_to_multi_transport(LinphoneCore *lc){
newtp.udp_port=port;
newtp.tcp_port=port;
newtp.tls_port=LC_SIP_TRANSPORT_RANDOM;
- lp_config_set_string(lc->config, "sip","sip_random_port",NULL); //remove
+ lp_config_set_string(lc->config, "sip","sip_random_port",NULL); /*remove*/
linphone_core_set_sip_transports(lc,&newtp);
}
lp_config_set_int(lc->config,"sip","multi_transport_migration_done",1);
diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c
index 67a9a5a60..caece9835 100644
--- a/coreapi/offeranswer.c
+++ b/coreapi/offeranswer.c
@@ -273,16 +273,17 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
const SalMediaDescription *remote_answer,
SalMediaDescription *result){
int i,j;
-
const SalStreamDescription *ls,*rs;
+
for(i=0,j=0;in_total_streams;++i){
ms_message("Processing for stream %i",i);
ls=&local_offer->streams[i];
rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type);
if (rs) {
initiate_outgoing(ls,rs,&result->streams[j]);
+ memcpy(&result->streams[i].rtcp_xr, &ls->rtcp_xr, sizeof(result->streams[i].rtcp_xr));
if ((ls->rtcp_xr.enabled == TRUE) && (rs->rtcp_xr.enabled == FALSE)) {
- memset(&result->streams[j].rtcp_xr, 0, sizeof(result->streams[j].rtcp_xr));
+ result->streams[i].rtcp_xr.enabled = FALSE;
}
++j;
}
@@ -292,8 +293,9 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
result->n_total_streams=local_offer->n_total_streams;
result->bandwidth=remote_answer->bandwidth;
strcpy(result->addr,remote_answer->addr);
+ memcpy(&result->rtcp_xr, &local_offer->rtcp_xr, sizeof(result->rtcp_xr));
if ((local_offer->rtcp_xr.enabled == TRUE) && (remote_answer->rtcp_xr.enabled == FALSE)) {
- memset(&result->rtcp_xr, 0, sizeof(result->rtcp_xr));
+ result->rtcp_xr.enabled = FALSE;
}
return 0;
@@ -352,10 +354,11 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
// Handle media RTCP XR attribute
memset(&result->streams[i].rtcp_xr, 0, sizeof(result->streams[i].rtcp_xr));
if (rs->rtcp_xr.enabled == TRUE) {
- if (ls->rtcp_xr.enabled == TRUE) {
- memcpy(&result->streams[i].rtcp_xr, &ls->rtcp_xr, sizeof(result->streams[i].rtcp_xr));
- } else if (local_capabilities->rtcp_xr.enabled == TRUE) {
- memcpy(&result->streams[i].rtcp_xr, &local_capabilities->rtcp_xr, sizeof(result->streams[i].rtcp_xr));
+ const OrtpRtcpXrConfiguration *rtcp_xr_conf = NULL;
+ if (ls->rtcp_xr.enabled == TRUE) rtcp_xr_conf = &ls->rtcp_xr;
+ else if (local_capabilities->rtcp_xr.enabled == TRUE) rtcp_xr_conf = &local_capabilities->rtcp_xr;
+ if ((rtcp_xr_conf != NULL) && (ls->dir == SalStreamSendRecv)) {
+ memcpy(&result->streams[i].rtcp_xr, rtcp_xr_conf, sizeof(result->streams[i].rtcp_xr));
} else {
result->streams[i].rtcp_xr.enabled = TRUE;
}
@@ -385,11 +388,13 @@ 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
memset(&result->rtcp_xr, 0, sizeof(result->rtcp_xr));
if (remote_offer->rtcp_xr.enabled == TRUE) {
- if (local_capabilities->rtcp_xr.enabled == TRUE) {
+ if ((local_capabilities->rtcp_xr.enabled == TRUE) && (local_capabilities->dir == SalStreamSendRecv)) {
memcpy(&result->rtcp_xr, &local_capabilities->rtcp_xr, sizeof(result->rtcp_xr));
} else {
result->rtcp_xr.enabled = TRUE;
diff --git a/coreapi/private.h b/coreapi/private.h
index 9e8d0af0f..9fa89dd3a 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -146,7 +146,7 @@ struct _LinphoneChatMessage {
LinphoneChatMessageState state;
bool_t is_read;
unsigned int storage_id;
- LinphoneReason reason;
+ SalOp *op;
};
typedef struct StunCandidate{
@@ -155,10 +155,16 @@ typedef struct StunCandidate{
}StunCandidate;
+typedef struct _PortConfig{
+ int rtp_port;
+ int rtcp_port;
+}PortConfig;
+
struct _LinphoneCall
{
int magic; /*used to distinguish from proxy config*/
struct _LinphoneCore *core;
+ SalErrorInfo non_op_error;
int af; /*the address family to prefer for RTP path, guessed from signaling path*/
LinphoneCallDir dir;
SalMediaDescription *biggestdesc; /*media description with all already proposed streams, used to remember the mapping of streams*/
@@ -174,12 +180,11 @@ struct _LinphoneCall
LinphoneCallState state;
LinphoneCallState prevstate;
LinphoneCallState transfer_state; /*idle if no transfer*/
- LinphoneReason reason;
LinphoneProxyConfig *dest_proxy;
int refcnt;
void * user_pointer;
- int audio_port;
- int video_port;
+ PortConfig media_ports[2];
+ MSMediaStreamSessions sessions[2]; /*the rtp, srtp, zrtp contexts for each stream*/
StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
@@ -204,7 +209,7 @@ struct _LinphoneCall
unsigned int remote_session_ver;
LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/
LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */
- int localdesc_changed;
+ int localdesc_changed;/*not a boolean, contains a mask representing changes*/
bool_t refer_pending;
bool_t expect_media_in_ack;
@@ -373,7 +378,6 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call)
void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call);
bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md);
extern SalCallbacks linphone_sal_callbacks;
-void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg, LinphoneReason error);
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc);
LinphoneCall * is_a_linphone_call(void *user_pointer);
@@ -413,7 +417,6 @@ struct _LinphoneProxyConfig
bool_t pad[3];
void* user_data;
time_t deletion_date;
- LinphoneReason error;
LinphonePrivacyMask privacy;
};
@@ -682,7 +685,9 @@ struct _LinphoneCore
UpnpContext *upnp;
#endif //BUILD_UPNP
belle_http_provider_t *http_provider;
+ belle_tls_verify_policy_t *http_verify_policy;
MSList *tones;
+ LinphoneReason chat_deny_code;
};
@@ -693,7 +698,6 @@ struct _LinphoneEvent{
SalCustomHeader *send_custom_headers;
LinphoneSubscriptionState subscription_state;
LinphonePublishState publish_state;
- LinphoneReason reason;
void *userdata;
int refcnt;
char *name;
@@ -806,7 +810,6 @@ LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir,
LinphoneEvent *linphone_event_new_with_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);
-void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason);
LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss);
const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref);
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc);
@@ -847,6 +850,10 @@ 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);
+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
*/
diff --git a/coreapi/proxy.c b/coreapi/proxy.c
index 5e0b8ff18..74c8a7730 100644
--- a/coreapi/proxy.c
+++ b/coreapi/proxy.c
@@ -1368,11 +1368,11 @@ LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyCon
}
LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) {
- return cfg->error;
+ return linphone_error_info_get_reason(linphone_proxy_config_get_error_info(cfg));
}
-void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason error) {
- cfg->error = error;
+const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProxyConfig *cfg){
+ return linphone_error_info_from_sal_op(cfg->op);
}
const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) {
diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c
index 7deb4d5e6..96ee2a6dd 100644
--- a/coreapi/remote_provisioning.c
+++ b/coreapi/remote_provisioning.c
@@ -52,11 +52,32 @@ static void linphone_remote_provisioning_apply(LinphoneCore *lc, const char *xml
}
}
+static int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* file_path){
+ int status = -1;
+ FILE* f = fopen(file_path, "r");
+
+ if( f ){
+ fseek(f, 0, SEEK_END);
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ char* provisioning = ms_malloc(fsize + 1);
+ fread(provisioning, fsize, 1, f);
+ fclose(f);
+ linphone_remote_provisioning_apply(lc, provisioning);
+ status = 0;
+ } else {
+ ms_error("Couldn't open file %s for provisioning", file_path);
+ }
+
+ return status;
+}
+
static void belle_request_process_response_event(void *ctx, const belle_http_response_event_t *event) {
LinphoneCore *lc = (LinphoneCore *)ctx;
belle_sip_message_t *body = BELLE_SIP_MESSAGE(event->response);
const char *message = belle_sip_message_get_body(body);
-
+
if (belle_http_response_get_status_code(event->response) == 200) {
linphone_remote_provisioning_apply(lc, message);
} else {
@@ -80,23 +101,31 @@ static void belle_request_process_auth_requested(void *ctx, belle_sip_auth_event
}
int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri) {
- belle_generic_uri_t *uri=belle_generic_uri_parse(remote_provisioning_uri);
- belle_http_request_listener_callbacks_t belle_request_listener = {
- belle_request_process_response_event,
- belle_request_process_io_error,
- belle_request_process_timeout,
- belle_request_process_auth_requested
- };
- belle_http_request_listener_t *listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc);
- belle_http_request_t *request;
-
- if (uri==NULL) {
- belle_sip_error("Invalid provisioning URI [%s]",remote_provisioning_uri);
- return -1;
+ const char* file_path = strstr(remote_provisioning_uri, "file://");
+
+ if( file_path == remote_provisioning_uri ){
+ // We allow for 'local remote-provisioning' in case the file is to be opened from the hard drive
+ file_path += strlen("file://");
+ return linphone_remote_provisioning_load_file(lc, file_path);
+ } else {
+ belle_generic_uri_t *uri=belle_generic_uri_parse(remote_provisioning_uri);
+ belle_http_request_listener_callbacks_t belle_request_listener = {
+ belle_request_process_response_event,
+ belle_request_process_io_error,
+ belle_request_process_timeout,
+ belle_request_process_auth_requested
+ };
+ belle_http_request_listener_t *listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc);
+ belle_http_request_t *request;
+
+ if (uri==NULL) {
+ belle_sip_error("Invalid provisioning URI [%s]",remote_provisioning_uri);
+ return -1;
+ }
+ request=belle_http_request_create("GET",uri, NULL);
+ belle_http_provider_send_request(lc->http_provider, request, listener);
+ return 0;
}
- request=belle_http_request_create("GET",uri, NULL);
- belle_http_provider_send_request(lc->http_provider, request, listener);
- return 0;
}
void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char *uri) {
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index c612ff07d..0daee4a7d 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -14,7 +14,8 @@ UI_FILES= about.ui \
call_statistics.ui \
ldap.ui \
config-uri.ui \
- provisioning-fetch.ui
+ provisioning-fetch.ui \
+ audio_assistant.ui
PIXMAPS= \
stock_people.png
@@ -52,6 +53,7 @@ linphone_SOURCES= \
singleinstance.c \
conference.c \
config-fetching.c \
+ audio_assistant.c \
linphone.h
if BUILD_WIZARD
linphone_SOURCES+= \
diff --git a/gtk/audio_assistant.c b/gtk/audio_assistant.c
new file mode 100644
index 000000000..431fa9995
--- /dev/null
+++ b/gtk/audio_assistant.c
@@ -0,0 +1,469 @@
+/*
+linphone, gtk-glade interface.
+Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org)
+
+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.
+*/
+
+#include
+
+#include "linphone.h"
+#include "linphonecore_utils.h"
+#include "mediastreamer2/mediastream.h"
+#include "mediastreamer2/msvolume.h"
+
+static GtkWidget *audio_assistant=NULL;
+static void prepare(GtkAssistant *w);
+
+GtkWidget *get_widget_from_assistant(const char *name){
+ return (GtkWidget *)g_object_get_data(G_OBJECT(audio_assistant),name);
+}
+
+static void set_widget_to_assistant(const char *name,GtkWidget *w){
+ g_object_set_data(G_OBJECT(audio_assistant),name,w);
+}
+
+static void update_record_button(gboolean is_visible){
+ GtkWidget *rec_button = get_widget_from_assistant("rec_button");
+ gtk_widget_set_sensitive(rec_button,is_visible);
+}
+
+#if 0
+static void activate_record_button(gboolean is_active){
+ GtkWidget *rec_button = get_widget_from_assistant("rec_button");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rec_button),is_active);
+}
+#endif
+
+static void update_play_button(gboolean is_visible){
+ GtkWidget *play_button = get_widget_from_assistant("play_button");
+ gtk_widget_set_sensitive(play_button,is_visible);
+}
+
+static void activate_play_button(gboolean is_active){
+ GtkWidget *play_button = get_widget_from_assistant("play_button");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),is_active);
+}
+
+static gchar *get_record_file(){
+ char filename[256]={0};
+ char date[64]={0};
+ time_t curtime=time(NULL);
+ struct tm loctime;
+
+ #ifdef WIN32
+ loctime=*localtime(&curtime);
+ #else
+ localtime_r(&curtime,&loctime);
+ #endif
+ snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i%2i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min, loctime.tm_sec);
+
+ snprintf(filename,sizeof(filename)-1,"record-%s.wav",date);
+ return g_build_path(G_DIR_SEPARATOR_S,g_get_tmp_dir(),filename,NULL);;
+}
+
+static float audio_stream_get_record_volume(AudioStream *st){
+ if (st && st->volsend){
+ float vol=0;
+ ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
+ return vol;
+ }
+ return LINPHONE_VOLUME_DB_LOWEST;
+}
+
+static float audio_stream_get_max_volume(AudioStream *st){
+ if (st && st->volsend){
+ float vol=0;
+ ms_filter_call_method(st->volsend,MS_VOLUME_GET_MAX,&vol);
+ return vol;
+ }
+ return LINPHONE_VOLUME_DB_LOWEST;
+}
+
+static gboolean update_audio_label(volume_ctx_t *ctx){
+ float volume_db=ctx->get_volume(ctx->data);
+ gchar *result;
+ if (volume_db < -20) result = _("No voice detected");
+ else if (volume_db <= -10) result = _("Too low");
+ else if (volume_db < -6) result = _("Good");
+ else result = _("Too loud");
+ g_message("volume_max_db=%f, text=%s",volume_db,result);
+ gtk_label_set_text(GTK_LABEL(ctx->widget),result);
+ return TRUE;
+}
+
+static void on_audio_label_destroy(guint task_id){
+ g_source_remove(task_id);
+}
+
+void linphone_gtk_init_audio_label(GtkWidget *w, get_volume_t get_volume, void *data){
+ guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id_t"));
+ if (task_id==0){
+ volume_ctx_t *ctx=g_new(volume_ctx_t,1);
+ ctx->widget=w;
+ ctx->get_volume=get_volume;
+ ctx->data=data;
+ ctx->last_value=0;
+ g_object_set_data_full(G_OBJECT(w),"ctx_t",ctx,g_free);
+ task_id=g_timeout_add(200,(GSourceFunc)update_audio_label,ctx);
+ g_object_set_data_full(G_OBJECT(w),"task_id_t",GINT_TO_POINTER(task_id),(GDestroyNotify)on_audio_label_destroy);
+ }
+}
+
+void linphone_gtk_uninit_audio_label(GtkWidget *w){
+ guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id_t"));
+ if (task_id!=0){
+ g_object_set_data(G_OBJECT(w),"ctx_t",NULL);
+ g_object_set_data(G_OBJECT(w),"task_id_t",NULL);
+ }
+}
+
+static void playback_device_changed(GtkWidget *w){
+ gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
+ linphone_core_set_playback_device(linphone_gtk_get_core(),sel);
+ g_free(sel);
+}
+
+static void capture_device_changed(GtkWidget *capture_device){
+ gchar *sel;
+ GtkWidget *mic_audiolevel;
+ GtkWidget *label_audiolevel;
+ GtkWidget *assistant=gtk_widget_get_toplevel(capture_device);
+ AudioStream *audio_stream;
+
+ mic_audiolevel = get_widget_from_assistant("mic_audiolevel");
+ label_audiolevel = get_widget_from_assistant("label_audiolevel");
+ audio_stream = (AudioStream *) g_object_get_data(G_OBJECT(assistant),"stream");
+ sel = gtk_combo_box_get_active_text(GTK_COMBO_BOX(capture_device));
+ linphone_core_set_capture_device(linphone_gtk_get_core(),sel);
+ linphone_gtk_uninit_audio_meter(mic_audiolevel);
+ linphone_gtk_uninit_audio_label(label_audiolevel);
+ audio_stream_stop(audio_stream);
+ g_free(sel);
+ /*now restart the audio stream*/
+ prepare(GTK_ASSISTANT(assistant));
+}
+
+static void dialog_click(GtkWidget *dialog, guint response_id, GtkWidget *page){
+ switch(response_id){
+ case GTK_RESPONSE_YES:
+ gtk_assistant_set_page_complete(GTK_ASSISTANT(audio_assistant),page,TRUE);
+ break;
+ default:
+ break;
+ }
+ gtk_widget_destroy(dialog);
+}
+
+static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay, void *data){
+ ms_message("echo calibration finished %s.",status==LinphoneEcCalibratorDone ? "successfully" : "with faillure");
+ if (status==LinphoneEcCalibratorDone) ms_message("Measured delay is %i",delay);
+
+ GtkWidget * dialog;
+ GtkWidget *speaker_page = get_widget_from_assistant("speaker_page");
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW(audio_assistant),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ "%s","Did you hear three beeps ?");
+
+ g_signal_connect(G_OBJECT (dialog), "response",
+ G_CALLBACK (dialog_click),speaker_page);
+ gtk_widget_show(dialog);
+}
+
+void linphone_gtk_start_sound(GtkWidget *w){
+ LinphoneCore *lc = linphone_gtk_get_core();
+ linphone_core_start_echo_calibration(lc,calibration_finished,NULL,NULL,NULL);
+}
+
+static gboolean linphone_gtk_stop_record(gpointer data){
+ AudioStream *stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"record_stream");
+ if(stream != NULL){
+ audio_stream_stop(stream);
+ g_object_set_data(G_OBJECT(audio_assistant),"record_stream",NULL);
+ }
+ update_record_button(FALSE);
+ update_play_button(TRUE);
+ return FALSE;
+}
+
+
+void linphone_gtk_start_record_sound(GtkWidget *w, gpointer data){
+ LinphoneCore *lc = linphone_gtk_get_core();
+ AudioStream *stream = NULL;
+ MSSndCardManager *manager = ms_snd_card_manager_get();
+ gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
+
+ if(active){
+ gchar *path = get_record_file();
+ stream=audio_stream_new(8888, 8889, FALSE);
+ if(stream != NULL){
+ audio_stream_start_full(stream,&av_profile,"127.0.0.1",8888,"127.0.0.1",8889,0,0,NULL,
+ path,NULL,ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE);
+ g_object_set_data(G_OBJECT(audio_assistant),"record_stream",stream);
+ }
+ gint timeout_id = gtk_timeout_add(6000,(GtkFunction)linphone_gtk_stop_record,NULL);
+ g_object_set_data(G_OBJECT(audio_assistant),"timeout_id",GINT_TO_POINTER(timeout_id));
+ g_object_set_data(G_OBJECT(audio_assistant),"path",path);
+ } else {
+ stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"record_stream");
+ gint timeout_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(audio_assistant),"timeout_id"));
+ gtk_timeout_remove(timeout_id);
+ if(stream != NULL){
+ audio_stream_stop(stream);
+ g_object_set_data(G_OBJECT(audio_assistant),"record_stream",NULL);
+ }
+ update_record_button(FALSE);
+ update_play_button(TRUE);
+ }
+}
+
+static void endoffile_cb(void *ud, MSFilter *f, unsigned int ev,void * arg){
+ switch (ev) {
+ case MS_PLAYER_EOF: {
+ ms_message("EndOfFile received");
+ activate_play_button(FALSE);
+ break;
+ }
+ break;
+ }
+}
+
+void linphone_gtk_start_play_record_sound(GtkWidget *w,gpointer data){
+ LinphoneCore *lc = linphone_gtk_get_core();
+ gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
+ AudioStream *stream = NULL;
+ MSSndCardManager *manager = ms_snd_card_manager_get();
+
+ if(active){
+ gchar *path = g_object_get_data(G_OBJECT(audio_assistant),"path");
+ stream=audio_stream_new(8888, 8889, FALSE);
+ if(path != NULL){
+ audio_stream_start_full(stream,&av_profile,"127.0.0.1",8888,"127.0.0.1",8889,0,0,path,
+ NULL,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),NULL,FALSE);
+ ms_filter_add_notify_callback(stream->soundread,endoffile_cb,stream,FALSE);
+ g_object_set_data(G_OBJECT(audio_assistant),"play_stream",stream);
+ }
+ } else {
+ stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"play_stream");
+ if(stream != NULL){
+ audio_stream_stop(stream);
+ g_object_set_data(G_OBJECT(audio_assistant),"play_stream",NULL);
+ }
+ }
+}
+
+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"));
+ gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2);
+ gtk_widget_show_all(vbox);
+ return vbox;
+}
+
+static GtkWidget *create_mic_page(){
+ GtkWidget *vbox=gtk_table_new(3,2,FALSE);
+ LinphoneCore *lc=linphone_gtk_get_core();
+
+ GtkWidget *labelMicChoice=gtk_label_new(_("Capture device"));
+ GtkWidget *labelMicLevel=gtk_label_new(_("Recorded volume"));
+ GtkWidget *mic_audiolevel=gtk_progress_bar_new();
+ GtkWidget *capture_device=gtk_combo_box_new();
+ GtkWidget *box = gtk_vbox_new(FALSE,0);
+ GtkWidget *label_audiolevel=gtk_label_new(_("No voice"));
+
+ gtk_box_pack_start(GTK_BOX(box),mic_audiolevel,TRUE,TRUE,1);
+ gtk_box_pack_start(GTK_BOX(box),label_audiolevel,FALSE,FALSE,1);
+
+ gtk_table_attach_defaults(GTK_TABLE(vbox), labelMicChoice, 0, 1, 0, 1);
+ 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_set_row_spacings(GTK_TABLE(vbox),10);
+
+ set_widget_to_assistant("mic_audiolevel",mic_audiolevel);
+ set_widget_to_assistant("label_audiolevel",label_audiolevel);
+
+ const char **sound_devices=linphone_core_get_sound_devices(lc);
+ linphone_gtk_fill_combo_box(capture_device, sound_devices,
+ linphone_core_get_capture_device(lc), CAP_CAPTURE);
+ gtk_widget_show_all(vbox);
+
+ g_signal_connect(G_OBJECT(capture_device),"changed",(GCallback)capture_device_changed,capture_device);
+
+ return vbox;
+}
+
+static GtkWidget *create_speaker_page(){
+ GtkWidget *vbox=gtk_table_new(2,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();
+
+ 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_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_set_row_spacings(GTK_TABLE(vbox),10);
+
+ const char **sound_devices=linphone_core_get_sound_devices(lc);
+ linphone_gtk_fill_combo_box(playback_device, sound_devices,
+ linphone_core_get_playback_device(lc),CAP_PLAYBACK);
+ gtk_widget_show_all(vbox);
+
+ 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);
+
+ return vbox;
+}
+
+static GtkWidget *create_play_record_page(){
+ GtkWidget *vbox=gtk_table_new(2,2,FALSE);
+ GtkWidget *labelRecord=gtk_label_new(_("Press the record button and say some words"));
+ GtkWidget *labelPlay=gtk_label_new(_("Listen to your record voice"));
+ GtkWidget *rec_button=gtk_toggle_button_new_with_label("Record");
+ GtkWidget *play_button=gtk_toggle_button_new_with_label("Play");
+ GtkWidget *image;
+
+ image=gtk_image_new_from_stock(GTK_STOCK_MEDIA_RECORD,GTK_ICON_SIZE_MENU);
+ gtk_button_set_image(GTK_BUTTON(rec_button),image);
+
+ image=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY,GTK_ICON_SIZE_MENU);
+ gtk_button_set_image(GTK_BUTTON(play_button),image);
+ gtk_widget_set_sensitive(play_button,FALSE);
+
+ gtk_table_attach_defaults(GTK_TABLE(vbox), labelRecord, 0, 1, 0, 1);
+ gtk_table_attach(GTK_TABLE(vbox), rec_button, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0,0);
+ gtk_table_attach_defaults(GTK_TABLE(vbox), labelPlay, 0, 1, 1, 2);
+ gtk_table_attach(GTK_TABLE(vbox), play_button, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0,0);
+
+ gtk_widget_show_all(vbox);
+
+ set_widget_to_assistant("rec_button",rec_button);
+ set_widget_to_assistant("play_button",play_button);
+ g_signal_connect(G_OBJECT(rec_button),"toggled",(GCallback)linphone_gtk_start_record_sound,vbox);
+ g_signal_connect(G_OBJECT(play_button),"toggled",(GCallback)linphone_gtk_start_play_record_sound,vbox);
+
+ return vbox;
+}
+
+static GtkWidget *create_end_page(){
+ GtkWidget *vbox=gtk_vbox_new(FALSE,2);
+ GtkWidget *label=gtk_label_new(_("Let's start Linphone now"));
+ gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2);
+ gtk_widget_show_all(vbox);
+ return vbox;
+}
+
+static void prepare(GtkAssistant *w){
+ AudioStream *audio_stream = NULL;
+ LinphoneCore *lc=linphone_gtk_get_core();
+ int page = gtk_assistant_get_current_page(w);
+ GtkWidget *mic_audiolevel = get_widget_from_assistant("mic_audiolevel");
+ GtkWidget *label_audiolevel = get_widget_from_assistant("label_audiolevel");
+
+ //Speaker page
+ if(page == 1){
+ MSSndCardManager *manager = ms_snd_card_manager_get();
+ audio_stream = audio_stream_start_with_sndcards(&av_profile,9898,"127.0.0.1",19898,0,0,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE);
+ if (mic_audiolevel != NULL && audio_stream != NULL){
+ g_object_set_data(G_OBJECT(audio_assistant),"stream",audio_stream);
+ linphone_gtk_init_audio_meter(mic_audiolevel,(get_volume_t)audio_stream_get_record_volume,audio_stream);
+ linphone_gtk_init_audio_label(label_audiolevel,(get_volume_t)audio_stream_get_max_volume,audio_stream);
+ }
+ } else if(page == 2 || page == 0){
+ if(mic_audiolevel != NULL && label_audiolevel != NULL){
+ audio_stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"stream");
+ if(audio_stream != NULL){
+ linphone_gtk_uninit_audio_meter(mic_audiolevel);
+ linphone_gtk_uninit_audio_label(label_audiolevel);
+ audio_stream_stop(audio_stream);
+ g_object_set_data(G_OBJECT(audio_assistant),"stream",NULL);
+ }
+ }
+ }
+}
+
+void linphone_gtk_close_audio_assistant(GtkWidget *w){
+ gchar *path = g_object_get_data(G_OBJECT(audio_assistant),"path");
+ if(path != NULL){
+ g_unlink(path);
+ }
+ gtk_widget_destroy(w);
+ if(linphone_gtk_get_audio_assistant_option()){
+ gtk_main_quit();
+ }
+ audio_assistant = NULL;
+}
+
+void linphone_gtk_audio_assistant_apply(GtkWidget *w){
+ linphone_gtk_close_audio_assistant(w);
+}
+
+void linphone_gtk_show_audio_assistant(void){
+ GtkWidget *w;
+ if(audio_assistant!=NULL)
+ return;
+ w=audio_assistant=linphone_gtk_create_window("audio_assistant");
+
+ gtk_window_set_resizable (GTK_WINDOW(w), FALSE);
+ gtk_window_set_title(GTK_WINDOW(w),_("Audio Assistant"));
+
+ GtkWidget *welcome=create_intro();
+ GtkWidget *mic_page=create_mic_page();
+ GtkWidget *speaker_page=create_speaker_page();
+ GtkWidget *play_record_page=create_play_record_page();
+ GtkWidget *end_page=create_end_page();
+
+ gtk_assistant_append_page(GTK_ASSISTANT(w),welcome);
+ gtk_assistant_set_page_type(GTK_ASSISTANT(w),welcome,GTK_ASSISTANT_PAGE_INTRO);
+ gtk_assistant_set_page_title(GTK_ASSISTANT(w),welcome,_("Audio assistant"));
+ gtk_assistant_set_page_complete(GTK_ASSISTANT(w),welcome,TRUE);
+
+ gtk_assistant_append_page(GTK_ASSISTANT(w),mic_page);
+ gtk_assistant_set_page_type(GTK_ASSISTANT(w),mic_page,GTK_ASSISTANT_PAGE_CONTENT);
+ gtk_assistant_set_page_title(GTK_ASSISTANT(w),mic_page,_("Mic Gain calibration"));
+ gtk_assistant_set_page_complete(GTK_ASSISTANT(w),mic_page,TRUE);
+
+ gtk_assistant_append_page(GTK_ASSISTANT(w),speaker_page);
+ gtk_assistant_set_page_type(GTK_ASSISTANT(w),speaker_page,GTK_ASSISTANT_PAGE_CONTENT);
+ gtk_assistant_set_page_complete(GTK_ASSISTANT(w),speaker_page,FALSE);
+ gtk_assistant_set_page_title(GTK_ASSISTANT(w),speaker_page,_("Speaker volume calibration"));
+
+ gtk_assistant_append_page(GTK_ASSISTANT(w),play_record_page);
+ gtk_assistant_set_page_type(GTK_ASSISTANT(w),play_record_page,GTK_ASSISTANT_PAGE_CONTENT);
+ gtk_assistant_set_page_complete(GTK_ASSISTANT(w),play_record_page,TRUE);
+ gtk_assistant_set_page_title(GTK_ASSISTANT(w),play_record_page,_("Record and Play"));
+
+ gtk_assistant_append_page(GTK_ASSISTANT(w),end_page);
+ gtk_assistant_set_page_type(GTK_ASSISTANT(w),end_page,GTK_ASSISTANT_PAGE_SUMMARY);
+ gtk_assistant_set_page_complete(GTK_ASSISTANT(w),end_page,TRUE);
+ gtk_assistant_set_page_title(GTK_ASSISTANT(w),end_page,_("Terminating"));
+
+ g_signal_connect(G_OBJECT(w),"close",(GCallback)linphone_gtk_close_audio_assistant,w);
+ g_signal_connect(G_OBJECT(w),"cancel",(GCallback)linphone_gtk_close_audio_assistant,w);
+ g_signal_connect(G_OBJECT(w),"prepare",(GCallback)prepare,NULL);
+
+ gtk_widget_show(w);
+}
diff --git a/gtk/audio_assistant.ui b/gtk/audio_assistant.ui
new file mode 100644
index 000000000..b8390f5d8
--- /dev/null
+++ b/gtk/audio_assistant.ui
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/gtk/incall_view.c b/gtk/incall_view.c
index 8f96cfb27..8ab6309f6 100644
--- a/gtk/incall_view.c
+++ b/gtk/incall_view.c
@@ -567,19 +567,12 @@ static gboolean linphone_gtk_in_call_view_refresh(LinphoneCall *call){
return TRUE;
}
-typedef struct _volume_ctx{
- GtkWidget *widget;
- get_volume_t get_volume;
- void *data;
- float last_value;
-}volume_ctx_t;
-
-#define UNSIGNIFICANT_VOLUME (-26)
+#define UNSIGNIFICANT_VOLUME (-23)
#define SMOOTH 0.15
static gboolean update_audio_meter(volume_ctx_t *ctx){
float volume_db=ctx->get_volume(ctx->data);
- float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME+3.0);
+ float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME-3.0);
if (frac<0) frac=0;
if (frac>1.0) frac=1.0;
if (fraclast_value){
diff --git a/gtk/linphone.h b/gtk/linphone.h
index e1df87ab3..2a256cab5 100644
--- a/gtk/linphone.h
+++ b/gtk/linphone.h
@@ -53,6 +53,27 @@ enum {
COMPLETION_LDAP
};
+typedef float (*get_volume_t)(void *data);
+
+typedef struct _volume_ctx{
+ GtkWidget *widget;
+ get_volume_t get_volume;
+ void *data;
+ float last_value;
+}volume_ctx_t;
+
+typedef enum {
+ CAP_IGNORE,
+ CAP_PLAYBACK,
+ CAP_CAPTURE
+}DeviceCap;
+
+enum {
+ START_LINPHONE,
+ START_AUDIO_ASSISTANT,
+ START_LINPHONE_WITH_CALL
+};
+
GdkPixbuf * create_pixbuf(const gchar *filename);
GdkPixbufAnimation *create_pixbuf_animation(const gchar *filename);
void add_pixmap_directory(const gchar *directory);
@@ -96,7 +117,6 @@ LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void);
void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap);
int linphone_gtk_is_ldap_supported(void);
-
void linphone_gtk_open_browser(const char *url);
void linphone_gtk_check_for_new_version(void);
const char *linphone_gtk_get_lang(const char *config_file);
@@ -150,8 +170,8 @@ void linphone_gtk_unset_from_conference(LinphoneCall *call);
void linphone_gtk_terminate_conference_participant(LinphoneCall *call);
void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call);
void linphone_gtk_update_video_button(LinphoneCall *call);
-typedef float (*get_volume_t)(void *data);
void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data);
+void linphone_gtk_uninit_audio_meter(GtkWidget *w);
void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login);
void linphone_gtk_exit_login_frame(void);
@@ -159,14 +179,18 @@ void linphone_gtk_set_ui_config(const char *key, const char *value);
void linphone_gtk_log_uninit();
-bool_t linphone_gtk_init_instance(const char *app_name, const char *addr_to_call);
+bool_t linphone_gtk_init_instance(const char *app_name, int option, const char *addr_to_call);
void linphone_gtk_uninit_instance(void);
void linphone_gtk_monitor_usb(void);
void linphone_gtk_unmonitor_usb(void);
+void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap);
gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference);
void linphone_gtk_schedule_restart(void);
+void linphone_gtk_show_audio_assistant(void);
+gboolean linphone_gtk_get_audio_assistant_option(void);
+
void linphone_gtk_set_configuration_uri(void);
GtkWidget * linphone_gtk_show_config_fetching(void);
void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state);
diff --git a/gtk/main.c b/gtk/main.c
index f40acb8b6..2fd3fd897 100644
--- a/gtk/main.c
+++ b/gtk/main.c
@@ -86,8 +86,10 @@ static gboolean verbose=0;
static gboolean quit_done=FALSE;
static gboolean auto_answer = 0;
static gchar * addr_to_call = NULL;
+static int start_option = START_LINPHONE;
static gboolean no_video=FALSE;
static gboolean iconified=FALSE;
+static gboolean run_audio_assistant=FALSE;
static gchar *workingdir=NULL;
static char *progpath=NULL;
gchar *linphone_logfile=NULL;
@@ -153,6 +155,13 @@ static GOptionEntry linphone_options[]={
.arg_data = (gpointer) &custom_config_file,
.description = N_("Configuration file")
},
+ {
+ .long_name = "run-audio-assistant",
+ .short_name = '\0',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = (gpointer) &run_audio_assistant,
+ .description = N_("Run the audio assistant")
+ },
{0}
};
@@ -262,6 +271,10 @@ void linphone_gtk_schedule_restart(void){
restart=TRUE;
}
+gboolean linphone_gtk_get_audio_assistant_option(void){
+ return run_audio_assistant;
+}
+
static void linphone_gtk_init_liblinphone(const char *config_file,
const char *factory_config_file, const char *db_file) {
LinphoneCoreVTable vtable={0};
@@ -2136,6 +2149,11 @@ static void linphone_gtk_init_ui(void){
}
#endif
+ if(run_audio_assistant){
+ linphone_gtk_show_audio_assistant();
+ start_option=START_AUDIO_ASSISTANT;
+ iconified = TRUE;
+ }
#ifndef HAVE_GTK_OSX
linphone_gtk_init_status_icon();
#endif
@@ -2168,7 +2186,6 @@ int main(int argc, char *argv[]){
config_file=linphone_gtk_get_config_file(NULL);
-
#ifdef WIN32
/*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
if ((lang=getenv("LANG"))!=NULL){
@@ -2226,6 +2243,9 @@ int main(int argc, char *argv[]){
}
config_file=linphone_gtk_get_config_file(custom_config_file);
+ if(run_audio_assistant) start_option=START_AUDIO_ASSISTANT;
+ if(addr_to_call != NULL) start_option=START_LINPHONE_WITH_CALL;
+
settings=gtk_settings_get_default();
g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
@@ -2275,7 +2295,7 @@ int main(int argc, char *argv[]){
#endif
core_start:
- if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
+ if (linphone_gtk_init_instance(app_name, start_option, addr_to_call) == FALSE){
g_warning("Another running instance of linphone has been detected. It has been woken-up.");
g_warning("This instance is going to exit now.");
gdk_threads_leave();
diff --git a/gtk/main.ui b/gtk/main.ui
index 8be5b3555..44750d572 100644
--- a/gtk/main.ui
+++ b/gtk/main.ui
@@ -786,6 +786,12 @@
False
gtk-add
+
+
+
+
+
+
+
+
@@ -1733,9 +1803,6 @@
5
-
-
-
+
+
+
@@ -1881,59 +1951,6 @@
-
-
-
-