From 48f34568c9fab1cbc11e3c6030fca07d175d488d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 29 Mar 2012 15:09:52 +0200 Subject: [PATCH] implement notifications when doing transfers --- configure.ac | 2 +- coreapi/callbacks.c | 40 +++++++++++++- coreapi/linphonecall.c | 5 ++ coreapi/linphonecore.c | 10 +++- coreapi/linphonecore.h | 9 ++- coreapi/presence.c | 2 +- coreapi/private.h | 5 +- coreapi/sal.h | 17 ++++-- coreapi/sal_eXosip2.c | 121 +++++++++++++++++++++++++++++------------ gtk/incall_view.c | 22 ++++++++ gtk/linphone.h | 1 + gtk/main.c | 6 ++ mediastreamer2 | 2 +- 13 files changed, 191 insertions(+), 51 deletions(-) diff --git a/configure.ac b/configure.ac index 7a523eec..2bead21d 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ if test "$LINPHONE_EXTRA_VERSION" != "" ;then LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION} fi -LIBLINPHONE_SO_CURRENT=4 dnl increment this number when you add/change/remove an interface +LIBLINPHONE_SO_CURRENT=5 dnl increment this number when you add/change/remove an interface LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 5ffd43e4..8d41da10 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -323,6 +323,7 @@ static void call_accepted(SalOp *op){ call->state==LinphoneCallOutgoingRinging || call->state==LinphoneCallOutgoingEarlyMedia){ linphone_call_set_state(call,LinphoneCallConnected,"Connected"); + if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call); } if (md && !sal_media_description_empty(md)){ if (sal_media_description_has_dir(md,SalStreamSendOnly) || @@ -591,6 +592,10 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } else { linphone_call_set_state(call,LinphoneCallError,msg); } + if (call->referer && linphone_call_get_state(call->referer)==LinphoneCallPaused && call->referer->was_automatically_paused){ + /*resume to the call that send us the refer automatically*/ + linphone_core_resume_call(lc,call->referer); + } } static void call_released(SalOp *op){ @@ -744,12 +749,11 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ if (call->state!=LinphoneCallPaused){ ms_message("Automatically pausing current call to accept transfer."); linphone_core_pause_call(lc,call); + call->was_automatically_paused=TRUE; } linphone_core_start_refered_call(lc,call); - sal_call_accept_refer(op); }else if (lc->vtable.refer_received){ lc->vtable.refer_received(lc,referto); - sal_call_accept_refer(op); } } @@ -766,7 +770,7 @@ static void notify(SalOp *op, const char *from, const char *msg){ lc->vtable.notify_recv(lc,call,from,msg); } -static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){ +static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); linphone_notify_recv(lc,op,ss,status); } @@ -795,6 +799,35 @@ static void ping_reply(SalOp *op){ } } +static void notify_refer(SalOp *op, SalReferStatus status){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); + LinphoneCallState cstate; + if (call==NULL) { + ms_warning("Receiving notify_refer for unknown call."); + return ; + } + switch(status){ + case SalReferTrying: + cstate=LinphoneCallOutgoingProgress; + break; + case SalReferSuccess: + cstate=LinphoneCallConnected; + break; + case SalReferFailed: + cstate=LinphoneCallError; + break; + default: + cstate=LinphoneCallError; + } + if (lc->vtable.transfer_state_changed) + lc->vtable.transfer_state_changed(lc,call,cstate); + if (cstate==LinphoneCallConnected){ + /*automatically terminate the call as the transfer is complete.*/ + linphone_core_terminate_call(lc,call); + } +} + SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, @@ -814,6 +847,7 @@ SalCallbacks linphone_sal_callbacks={ text_received, notify, notify_presence, + notify_refer, subscribe_received, subscribe_closed, ping_reply diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 61a528d2..433d0ce2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -332,6 +332,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr discover_mtu(lc,linphone_address_get_domain (to)); if (params->referer){ sal_call_set_referer(call->op,params->referer->op); + call->referer=linphone_call_ref(params->referer); } return call; } @@ -401,6 +402,10 @@ static void linphone_call_set_terminated(LinphoneCall *call){ linphone_core_stop_dtmf(lc); call->ringing_beep=FALSE; } + if (call->referer){ + linphone_call_unref(call->referer); + call->referer=NULL; + } } void linphone_call_fix_call_parameters(LinphoneCall *call){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bee7ad5f..904f6a6c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1943,12 +1943,20 @@ const char * linphone_core_get_route(LinphoneCore *lc){ void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){ if (call->refer_pending){ LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc); + LinphoneCall *newcall; cp->has_video &= !!lc->video_policy.automatically_initiate; cp->referer=call; ms_message("Starting new call to refered address %s",call->refer_to); call->refer_pending=FALSE; - linphone_core_invite_with_params(lc,call->refer_to,cp); + newcall=linphone_core_invite_with_params(lc,call->refer_to,cp); linphone_call_params_destroy(cp); + if (newcall) linphone_core_notify_refer_state(lc,call,newcall); + } +} + +void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall){ + if (referer->op!=NULL){ + sal_call_notify_refer_state(referer->op,newcall ? newcall->op : NULL); } } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b7ceb87d..4581d24f 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -616,7 +616,9 @@ typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to); typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf); /** Callback prototype */ typedef void (*CallFirstVideoFrameCb)(struct _LinphoneCore *lc, LinphoneCall *call); - +/** Callback prototype for in progress transfers. The new_call_state is the state of the call resulting of the transfer, at the other party. */ +typedef void (*LinphoneTransferStateChanged)(struct _LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state); + /** * This structure holds all callbacks that the application should implement. * None is mandatory. @@ -632,6 +634,9 @@ typedef struct _LinphoneVTable{ TextMessageReceived text_received; /**< A text message has been received */ DtmfReceived dtmf_received; /**< A dtmf has been received received */ ReferReceived refer_received; /**< An out of call refer was received */ + CallEncryptionChangedCb call_encryption_changed; /**did,"SIP/2.0 100 Trying\r\n"); + } + else if (newcall->cid!=-1){ + if (newcall->did==-1){ + /* not yet established*/ + if (!newcall->terminated){ + /* in progress*/ + send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n"); + } + }else{ + if (!newcall->terminated){ + send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n"); + } + } + } + return 0; +} + int sal_ping(SalOp *op, const char *from, const char *to){ osip_message_t *options=NULL; @@ -748,26 +787,6 @@ int sal_ping(SalOp *op, const char *from, const char *to){ return -1; } -int sal_call_accept_refer(SalOp *op){ - osip_message_t *msg=NULL; - int err=0; - eXosip_lock(); - err = eXosip_call_build_notify(op->did,EXOSIP_SUBCRSTATE_ACTIVE,&msg); - if(msg != NULL) - { - osip_message_set_header(msg,(const char *)"event","refer"); - osip_message_set_content_type(msg,"message/sipfrag"); - osip_message_set_body(msg,"SIP/2.0 100 Trying",sizeof("SIP/2.0 100 Trying")); - eXosip_call_send_request(op->did,msg); - } - else - { - ms_error("could not get a notify built\n"); - } - eXosip_unlock(); - return err; -} - int sal_call_refer(SalOp *h, const char *refer_to){ osip_message_t *msg=NULL; int err=0; @@ -1517,6 +1536,51 @@ static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){ } } +void process_notify(Sal *sal, eXosip_event_t *ev){ + osip_header_t *h=NULL; + char *from=NULL; + SalOp *op=find_op(sal,ev); + osip_message_t *ans=NULL; + + ms_message("Receiving NOTIFY request !"); + osip_from_to_str(ev->request->from,&from); + osip_message_header_get_byname(ev->request,"Event",0,&h); + if(h){ + osip_body_t *body=NULL; + //osip_content_type_t *ct=NULL; + osip_message_get_body(ev->request,0,&body); + //ct=osip_message_get_content_type(ev->request); + if (h->hvalue && strcasecmp(h->hvalue,"refer")==0){ + /*special handling of refer events*/ + if (body && body->body){ + osip_message_t *msg; + osip_message_init(&msg); + if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){ + int code=osip_message_get_status_code(msg); + if (code==100){ + sal->callbacks.notify_refer(op,SalReferTrying); + }else if (code==200){ + sal->callbacks.notify_refer(op,SalReferSuccess); + }else if (code>=400){ + sal->callbacks.notify_refer(op,SalReferFailed); + } + } + osip_message_free(msg); + } + }else{ + /*generic handling*/ + sal->callbacks.notify(op,from,h->hvalue); + } + } + /*answer that we received the notify*/ + eXosip_lock(); + eXosip_call_build_answer(ev->tid,200,&ans); + if (ans) + eXosip_call_send_answer(ev->tid,200,ans); + eXosip_unlock(); + osip_free(from); +} + static void call_message_new(Sal *sal, eXosip_event_t *ev){ osip_message_t *ans=NULL; if (ev->request){ @@ -1559,22 +1623,7 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){ ms_message("Receiving REFER request !"); process_refer(sal,op,ev); }else if(MSG_IS_NOTIFY(ev->request)){ - osip_header_t *h=NULL; - char *from=NULL; - SalOp *op=find_op(sal,ev); - - ms_message("Receiving NOTIFY request !"); - osip_from_to_str(ev->request->from,&from); - osip_message_header_get_byname(ev->request,"Event",0,&h); - if(h) - sal->callbacks.notify(op,from,h->hvalue); - /*answer that we received the notify*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - osip_free(from); + process_notify(sal,ev); }else if (MSG_IS_OPTIONS(ev->request)){ eXosip_lock(); eXosip_call_build_answer(ev->tid,200,&ans); diff --git a/gtk/incall_view.c b/gtk/incall_view.c index d693ac14..d19dba8c 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -579,6 +579,28 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m linphone_gtk_terminate_conference_participant(call); } +void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + if (callview){ + GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); + const char *transfer_status="unknown"; + switch(cstate){ + case LinphoneCallOutgoingProgress: + transfer_status=_("Transfer in progress"); + break; + case LinphoneCallConnected: + transfer_status=_("Transfer done."); + break; + case LinphoneCallError: + transfer_status=_("Transfer failed."); + break; + default: + break; + } + gtk_label_set_text(GTK_LABEL(duration),transfer_status); + } +} + void linphone_gtk_draw_mute_button(GtkButton *button, gboolean active){ g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active)); if (active){ diff --git a/gtk/linphone.h b/gtk/linphone.h index 7074bc87..d4cafe28 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -107,6 +107,7 @@ void linphone_gtk_in_call_view_update_duration(LinphoneCall *call); void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg); void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call); void linphone_gtk_in_call_view_set_paused(LinphoneCall *call); +void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate); void linphone_gtk_mute_clicked(GtkButton *button); void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive); void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon); diff --git a/gtk/main.c b/gtk/main.c index 60c4556d..81919526 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -63,6 +63,7 @@ static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const ch static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl); static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg); static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token); +static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate); static gboolean linphone_gtk_auto_answer(LinphoneCall *call); static void linphone_gtk_status_icon_set_blinking(gboolean val); @@ -225,6 +226,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.refer_received=linphone_gtk_refer_received; vtable.buddy_info_updated=linphone_gtk_buddy_info_updated; vtable.call_encryption_changed=linphone_gtk_call_encryption_changed; + vtable.transfer_state_changed=linphone_gtk_transfer_state_changed; linphone_core_set_user_agent("Linphone", LINPHONE_VERSION); the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); @@ -1133,6 +1135,10 @@ static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall linphone_gtk_in_call_view_show_encryption(call); } +static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){ + linphone_gtk_in_call_view_set_transfer_status(call,cstate); +} + static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){ GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities")); GtkTreeModel *model=gtk_combo_box_get_model(box); diff --git a/mediastreamer2 b/mediastreamer2 index 9d722a14..1b517a0b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9d722a1456c8574b385fac0eadf4ad6a4067637b +Subproject commit 1b517a0bc1d6559267143130d137d0252a05f752 -- 2.39.2