]> sjero.net Git - linphone/commitdiff
implemented attended transfer (untested yet)
authorSimon Morlat <simon.morlat@linphone.org>
Wed, 20 Oct 2010 15:48:14 +0000 (17:48 +0200)
committerSimon Morlat <simon.morlat@linphone.org>
Wed, 20 Oct 2010 15:48:14 +0000 (17:48 +0200)
console/commands.c
coreapi/callbacks.c
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/linphonecore.h
coreapi/private.h
coreapi/sal.h
coreapi/sal_eXosip2.c
coreapi/sal_eXosip2.h
mediastreamer2
oRTP

index d22d4b8187784e59b91ff0033c8b97fb8954eba6..a7aa22f76a30295826bdba259f8963850ab4a701 100644 (file)
@@ -170,6 +170,12 @@ static LPC_COMMAND commands[] = {
        { "resume", lpc_cmd_resume, "resume a call",
                "'resume' : resume the unique call\n"
                "'resume <call id>' : hold off the call with given id\n"},
+       { "transfer", lpc_cmd_transfer,
+               "Transfer a call to a specified destination.",
+               "'transfer <sip-uri>' : transfers the current active call to the destination sip-uri\n"
+               "'transfer <call id> <sip-uri>': transfers the call with 'id' to the destination sip-uri\n"
+               "'transfer <call id1> --to-call <call id2>': transfers the call with 'id1' to the destination of call 'id2' (attended transfer)\n"
+       },
        { "mute", lpc_cmd_mute_mic, 
          "Mute microphone and suspend voice transmission."},
 #ifdef VIDEO_ENABLED
@@ -209,11 +215,6 @@ static LPC_COMMAND commands[] = {
                "'ipv6 enable' : enable the use of the ipv6 network.\n"
                "'ipv6 disable' : do not use ipv6 network."
        },
-       { "transfer", lpc_cmd_transfer,
-               "Transfer a call to a specified destination.",
-               "'transfer <sip-uri>' : transfers the current active call to the destination sip-uri"
-               "'transfer <call id> <sip-uri>': transfers the call with 'id' to the destination sip-uri"
-       },
        { "nat", lpc_cmd_nat, "Set nat address",
                "'nat'        : show nat settings.\n"
                "'nat <addr>' : set nat address.\n"
@@ -637,10 +638,12 @@ lpc_cmd_transfer(LinphoneCore *lc, char *args)
 {
        if (args){
                LinphoneCall *call;
+               LinphoneCall *call2;
                const char *refer_to=NULL;
                char arg1[256]={0};
                char arg2[266]={0};
-               int n=sscanf(args,"%s %s",arg1,arg2);
+               long id2=0;
+               int n=sscanf(args,"%s %s %li",arg1,arg2,&id2);
                if (n==1 || isalpha(*arg1)){
                        call=linphone_core_get_current_call(lc);
                        if (call==NULL && ms_list_size(linphone_core_get_calls(lc))==1){
@@ -651,13 +654,24 @@ lpc_cmd_transfer(LinphoneCore *lc, char *args)
                                linphonec_out("No active call, please specify a call id among the ones listed by 'calls' command.\n");
                                return 0;
                        }
-               }else{
+                       linphone_core_transfer_call(lc, call, refer_to);
+               }else if (n==2){
                        long id=atoi(arg1);
                        refer_to=args+strlen(arg1)+1;
                        call=linphonec_get_call(id);
                        if (call==NULL) return 0;
-               }
-               linphone_core_transfer_call(lc, call, refer_to);
+                       linphone_core_transfer_call(lc, call, refer_to);
+               }else if (n==3){
+                       long id=atoi(arg1);
+                       call=linphonec_get_call(id);
+                       call2=linphonec_get_call(id2);
+                       if (call==NULL || call2==NULL) return 0;
+                       if (strcmp(arg2,"--to-call")!=0){
+                               return 0;
+                       }
+                       linphonec_out("Performing attended transfer of call %i to call %i",id,id2);
+                       linphone_core_transfer_call_to_another (lc,call,call2);
+               }else return 0;
        }else{
                linphonec_out("Transfer command requires at least one argument\n");
                return 0;
index add616d85fbbbd739f0b9faf128ee5db30cf6418..9f7cd26582d02187740d5d2efcca2c0b3322ceed 100644 (file)
@@ -557,10 +557,10 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){
                        ms_free(msg);
                }
                if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc);
-               sal_refer_accept(op);
+               sal_call_accept_refer(op);
        }else if (lc->vtable.refer_received){
                lc->vtable.refer_received(lc,referto);
-               sal_refer_accept(op);
+               sal_call_accept_refer(op);
        }
 }
 
index 8139bbdb2961a96d34dccc1e178441a422b92e19..1cdc41ffe039855b3721dc2abd4883c4a6dfe934 100644 (file)
@@ -161,6 +161,9 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
        if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun)
                linphone_core_run_stun_tests(call->core,call);
        discover_mtu(lc,linphone_address_get_domain (to));
+       if (params->referer){
+               sal_call_set_referer (call->op,params->referer->op);
+       }
        return call;
 }
 
index b9e7fe518e9216cac538e6226d863c1b1b95a2d6..9abea19a0a7b75a86ce91a5c6869669c1f348d73 100644 (file)
@@ -1844,9 +1844,12 @@ void linphone_core_start_pending_refered_calls(LinphoneCore *lc){
        for(elem=lc->calls;elem!=NULL;elem=elem->next){
                LinphoneCall *call=(LinphoneCall*)elem->data;
                if (call->refer_pending){
+                       LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc);
+                       cp->referer=call;
                        ms_message("Starting new call to refered address %s",call->refer_to);
                        call->refer_pending=FALSE;
-                       linphone_core_invite(lc,call->refer_to);
+                       linphone_core_invite_with_params(lc,call->refer_to,cp);
+                       linphone_call_params_destroy(cp);
                        break;
                }
        }
@@ -2143,12 +2146,28 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char
        }
        //lc->call=NULL; //Do not do that you will lose the call afterward . . .
        real_url=linphone_address_as_string (real_parsed_url);
-       sal_refer(call->op,real_url);
+       sal_call_refer(call->op,real_url);
        ms_free(real_url);
        linphone_address_destroy(real_parsed_url);
        return 0;
 }
 
+/**
+ * Transfer a call to destination of another running call. This is used for "attended transfer" scenarios.
+ * @param lc linphone core object
+ * @param call a running call you want to transfer
+ * @param dest a running call whose remote person will receive the transfer
+ *
+ * The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately.
+ * The destination call is a call previously established to introduce the transfered person.
+ * This method will send a transfer request to the transfered person. The phone of the transfered is then
+ * expected to automatically call to the destination of the transfer. The receiver of the transfer will then automatically
+ * close the call with us (the 'dest' call).
+**/
+int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){
+       return sal_call_refer_with_replaces (call->op,dest->op);
+}
+
 bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){
        LinphoneCall *call = linphone_core_get_current_call(lc);
        if(call != NULL)
@@ -2198,6 +2217,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call)
 {
        LinphoneProxyConfig *cfg=NULL;
        const char *contact=NULL;
+       SalOp *replaced;
        
        if (call==NULL){
                //if just one call is present answer the only one ...
@@ -2207,16 +2227,27 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call)
                        call = (LinphoneCall*)linphone_core_get_calls(lc)->data;
        }
 
-       if (lc->current_call!=NULL && lc->current_call!=call){
-               ms_warning("Cannot accept this call, there is already one running.");
-               return -1;
-       }
-       
        if (call->state==LinphoneCallConnected){
                /*call already accepted*/
                return -1;
        }
+       
+       /* check if this call is supposed to replace an already running one*/
+       replaced=sal_call_get_replaces(call->op);
+       if (replaced){
+               LinphoneCall *rc=(LinphoneCall*)sal_op_get_user_pointer (replaced);
+               if (rc){
+                       ms_message("Call %p replaces call %p. This last one is going to be terminated automatically.",
+                                  call,rc);
+                       linphone_core_terminate_call (lc,rc);
+               }
+       }
 
+       if (lc->current_call!=NULL && lc->current_call!=call){
+               ms_warning("Cannot accept this call, there is already one running.");
+               return -1;
+       }
+       
        /*can accept a new call only if others are on hold */
        {
                MSList *elem;
index 1a75f5bad66d02301bc6c99fa6cef74cb611f1d1..313907ad9fc2d2825192cf207b67fa4b4102968f 100644 (file)
@@ -591,6 +591,8 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
 
 int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to);
 
+int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest);
+
 bool_t linphone_core_inc_invite_pending(LinphoneCore*lc);
 
 bool_t linphone_core_in_call(const LinphoneCore *lc);
index 9bee983b6342bfaea2b62f3c5e478c3d2acce27a..b41c772dd490c8fb7e1140ddd56b63578b5079cc 100644 (file)
@@ -57,6 +57,7 @@
 
 
 struct _LinphoneCallParams{
+       LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */
        bool_t has_video;
        bool_t pad[3];
 };
index 0fcd6e5a875c90e469f769914fb84b2bc4ca1f9e..b0b3c7574254318649d2fa5ab3b9d0cfaf9a026b 100644 (file)
@@ -282,8 +282,11 @@ int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optio
 int sal_call_hold(SalOp *h, bool_t holdon);
 int sal_call_update(SalOp *h);
 SalMediaDescription * sal_call_get_final_media_description(SalOp *h);
-int sal_refer(SalOp *h, const char *refer_to);
-int sal_refer_accept(SalOp *h);
+int sal_call_refer(SalOp *h, const char *refer_to);
+int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h);
+int sal_call_accept_refer(SalOp *h);
+/*informs this call is consecutive to an incoming refer */
+int sal_call_set_referer(SalOp *h, SalOp *refered_call);
 /* returns the SalOp of a call that should be replaced by h, if any */
 SalOp *sal_call_get_replaces(SalOp *h);
 int sal_call_send_dtmf(SalOp *h, char dtmf);
index c61ec96abffa4514cbf449db2144fad85c562fc5..dfa4744cb820d57f5e031ce3e0b174f919c0378b 100644 (file)
@@ -162,6 +162,7 @@ SalOp * sal_op_new(Sal *sal){
        op->reinvite=FALSE;
        op->call_id=NULL;
        op->replaces=NULL;
+       op->referred_by=NULL;
        op->masquerade_via=FALSE;
        op->auto_answer_asked=FALSE;
        return op;
@@ -205,6 +206,9 @@ void sal_op_release(SalOp *op){
        if (op->replaces){
                ms_free(op->replaces);
        }
+       if (op->referred_by){
+               ms_free(op->referred_by);
+       }
        __sal_op_free(op);
 }
 
@@ -494,6 +498,12 @@ int sal_call(SalOp *h, const char *from, const char *to){
                h->sdp_offering=TRUE;
                set_sdp_from_desc(invite,h->base.local_media);
        }else h->sdp_offering=FALSE;
+       if (h->replaces){
+               osip_message_set_header(invite,"Replaces",h->replaces);
+               if (h->referred_by)
+                       osip_message_set_header(invite,"Referred-By",h->referred_by);
+       }
+       
        eXosip_lock();
        err=eXosip_call_send_initial_invite(invite);
        eXosip_unlock();
@@ -610,6 +620,14 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
        return h->result;
 }
 
+int sal_call_set_referer(SalOp *h, SalOp *refered_call){
+       if (refered_call->replaces)
+               h->replaces=ms_strdup(refered_call->replaces);
+       if (refered_call->referred_by)
+               h->referred_by=ms_strdup(refered_call->referred_by);
+       return 0;
+}
+
 int sal_ping(SalOp *op, const char *from, const char *to){
        osip_message_t *options=NULL;
        
@@ -628,7 +646,7 @@ int sal_ping(SalOp *op, const char *from, const char *to){
        return -1;
 }
 
-int sal_refer_accept(SalOp *op){
+int sal_call_accept_refer(SalOp *op){
        osip_message_t *msg=NULL;
        int err=0;
        eXosip_lock();
@@ -648,7 +666,7 @@ int sal_refer_accept(SalOp *op){
        return err;
 }
 
-int sal_refer(SalOp *h, const char *refer_to){
+int sal_call_refer(SalOp *h, const char *refer_to){
        osip_message_t *msg=NULL;
        int err=0;
        eXosip_lock();
@@ -659,6 +677,24 @@ int sal_refer(SalOp *h, const char *refer_to){
        return err;
 }
 
+int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){
+       osip_message_t *msg=NULL;
+       char referto[256]={0};
+       int err=0;
+       eXosip_lock();
+       if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){
+               ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did);
+               eXosip_unlock();
+               return -1;
+       }
+       eXosip_call_build_refer(h->did,referto, &msg);
+       osip_message_set_header(msg,"Referred-By",h->base.from);
+       if (msg) err=eXosip_call_send_request(h->did, msg);
+       else err=-1;
+       eXosip_unlock();
+       return err;
+}
+
 SalOp *sal_call_get_replaces(SalOp *h){
        if (h->replaces!=NULL){
                int cid;
@@ -1240,6 +1276,59 @@ static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){
        }
 }
 
+static void fill_options_answer(osip_message_t *options){
+       osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO");
+       osip_message_set_accept(options,"application/sdp");
+}
+
+static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){
+       osip_header_t *h=NULL;
+       osip_message_t *ans=NULL;
+       ms_message("Receiving REFER request !");
+       osip_message_header_get_byname(ev->request,"Refer-To",0,&h);
+
+       if (h){
+               osip_from_t *from=NULL;
+               char *tmp;
+               osip_from_init(&from);
+       
+               if (osip_from_parse(from,h->hvalue)==0){
+                       if (op ){
+                               osip_uri_header_t *uh=NULL;
+                               osip_header_t *referred_by=NULL;
+                               osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh);
+                               if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){
+                                       ms_message("Found replaces in Refer-To");
+                                       if (op->replaces){
+                                               ms_free(op->replaces);
+                                       }
+                                       op->replaces=ms_strdup(uh->gvalue);
+                               }
+                               osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by);
+                               if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){
+                                       if (op->referred_by)
+                                               ms_free(op->referred_by);
+                                       op->referred_by=ms_strdup(referred_by->hvalue);
+                               }
+                       }
+                       osip_uri_header_freelist(&from->url->url_headers);
+                       osip_from_to_str(from,&tmp);
+                       sal->callbacks.refer_received(sal,op,tmp);
+                       osip_free(tmp);
+                       osip_from_free(from);
+               }
+               eXosip_lock();
+               eXosip_call_build_answer(ev->tid,202,&ans);
+               if (ans)
+                       eXosip_call_send_answer(ev->tid,202,ans);
+               eXosip_unlock();
+       }
+       else
+       {
+               ms_warning("cannot do anything with the refer without destination\n");
+       }
+}
+
 static void call_message_new(Sal *sal, eXosip_event_t *ev){
        osip_message_t *ans=NULL;
        if (ev->request){
@@ -1268,8 +1357,7 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){
                                        eXosip_call_send_answer(ev->tid,200,ans);
                                eXosip_unlock();
                        }
-               }
-               if(MSG_IS_MESSAGE(ev->request)){
+               }else if(MSG_IS_MESSAGE(ev->request)){
                        /* SIP messages could be received into call */
                        text_received(sal, ev);
                        eXosip_lock();
@@ -1277,27 +1365,12 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){
                        if (ans)
                                eXosip_call_send_answer(ev->tid,200,ans);
                        eXosip_unlock();
-               }
-               if(MSG_IS_REFER(ev->request)){
-                       osip_header_t *h=NULL;
+               }else if(MSG_IS_REFER(ev->request)){
                        SalOp *op=find_op(sal,ev);
                        
                        ms_message("Receiving REFER request !");
-                       osip_message_header_get_byname(ev->request,"Refer-To",0,&h);
-                       eXosip_lock();
-                       eXosip_call_build_answer(ev->tid,202,&ans);
-                       if (ans)
-                               eXosip_call_send_answer(ev->tid,202,ans);
-                       eXosip_unlock();
-                       if (h){
-                               sal->callbacks.refer_received(sal,op,h->hvalue);
-                       }
-                       else
-                       {
-                               ms_warning("cannot do anything with the refer without destination\n");
-                       }
-               }
-               if(MSG_IS_NOTIFY(ev->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);
@@ -1314,6 +1387,14 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){
                                eXosip_call_send_answer(ev->tid,200,ans);
                        eXosip_unlock();
                        osip_free(from);
+               }else if (MSG_IS_OPTIONS(ev->request)){
+                       eXosip_lock();
+                       eXosip_call_build_answer(ev->tid,200,&ans);
+                       if (ans){
+                               fill_options_answer(ans);
+                               eXosip_call_send_answer(ev->tid,200,ans);
+                       }
+                       eXosip_unlock();
                }
        }else ms_warning("call_message_new: No request ?");
 }
@@ -1362,6 +1443,8 @@ static void text_received(Sal *sal, eXosip_event_t *ev){
        osip_free(from);
 }
 
+
+
 static void other_request(Sal *sal, eXosip_event_t *ev){
        ms_message("in other_request");
        if (ev->request==NULL) return;
@@ -1371,8 +1454,7 @@ static void other_request(Sal *sal, eXosip_event_t *ev){
        }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){
                osip_message_t *options=NULL;
                eXosip_options_build_answer(ev->tid,200,&options);
-               osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO");
-               osip_message_set_accept(options,"application/sdp");
+               fill_options_answer(options);
                eXosip_options_send_answer(ev->tid,200,options);
        }else if (strcmp(ev->request->sip_method,"WAKEUP")==0
                && comes_from_local_if(ev->request)) {
@@ -1382,12 +1464,7 @@ static void other_request(Sal *sal, eXosip_event_t *ev){
        }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){
                ms_message("Receiving REFER request !");
                if (comes_from_local_if(ev->request)) {
-                       osip_header_t *h=NULL;
-                       osip_message_header_get_byname(ev->request,"Refer-To",0,&h);
-                       eXosip_message_send_answer(ev->tid,200,NULL);
-                       if (h){
-                               sal->callbacks.refer_received(sal,NULL,h->hvalue);
-                       }
+                       process_refer(sal,NULL,ev);
                }else ms_warning("Ignored REFER not coming from this local loopback interface.");
        }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){
                inc_update(sal,ev);
index bfb3d10f26cf781f278754bbb6f94be952780b67..10c8b46b7805436ee59dd5fd66057b8d4f5c34d8 100644 (file)
@@ -57,6 +57,7 @@ struct SalOp{
        osip_call_id_t *call_id; /*used for out of calls transaction in order
                                to retrieve the operation when receiving a response*/
        char *replaces;
+       char *referred_by;
        bool_t supports_session_timers;
        bool_t sdp_offering;
        bool_t reinvite;
index af119e5c828e81a822d63af8ffb860764b8f20b4..e3a50ec460494101e925fa112e97adbc82c45306 160000 (submodule)
@@ -1 +1 @@
-Subproject commit af119e5c828e81a822d63af8ffb860764b8f20b4
+Subproject commit e3a50ec460494101e925fa112e97adbc82c45306
diff --git a/oRTP b/oRTP
index 461dd13a0aad2a075a075bf618e68443475f7a24..930fac6f59b13cdd6cbb5f370911a65f98bad7de 160000 (submodule)
--- a/oRTP
+++ b/oRTP
@@ -1 +1 @@
-Subproject commit 461dd13a0aad2a075a075bf618e68443475f7a24
+Subproject commit 930fac6f59b13cdd6cbb5f370911a65f98bad7de