Commit e07a927d authored by Simon Morlat's avatar Simon Morlat

implemented attended transfer (untested yet)

parent c6c7d662
......@@ -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;
......
......@@ -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);
}
}
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -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];
};
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
......
mediastreamer2 @ e3a50ec4
Subproject commit af119e5c828e81a822d63af8ffb860764b8f20b4
Subproject commit e3a50ec460494101e925fa112e97adbc82c45306
oRTP @ 930fac6f
Subproject commit 461dd13a0aad2a075a075bf618e68443475f7a24
Subproject commit 930fac6f59b13cdd6cbb5f370911a65f98bad7de
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment