mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-31 10:19:23 +00:00
implemented attended transfer (untested yet)
This commit is contained in:
parent
c6c7d662de
commit
e07a927d7e
11 changed files with 184 additions and 52 deletions
|
|
@ -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 (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;
|
||||
}
|
||||
|
||||
if (call->state==LinphoneCallConnected){
|
||||
/*call already accepted*/
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit af119e5c828e81a822d63af8ffb860764b8f20b4
|
||||
Subproject commit e3a50ec460494101e925fa112e97adbc82c45306
|
||||
2
oRTP
2
oRTP
|
|
@ -1 +1 @@
|
|||
Subproject commit 461dd13a0aad2a075a075bf618e68443475f7a24
|
||||
Subproject commit 930fac6f59b13cdd6cbb5f370911a65f98bad7de
|
||||
Loading…
Add table
Reference in a new issue