many bugfixes and improvements for multicall

This commit is contained in:
Simon Morlat 2010-08-20 16:33:11 +02:00
parent 9d37f3591a
commit d32da0079d
13 changed files with 332 additions and 207 deletions

View file

@ -56,13 +56,14 @@ extern char *lpc_strip_blanks(char *input);
static int lpc_cmd_help(LinphoneCore *, char *);
static int lpc_cmd_proxy(LinphoneCore *, char *);
static int lpc_cmd_call(LinphoneCore *, char *);
static int lpc_cmd_calls(LinphoneCore *, char *);
static int lpc_cmd_chat(LinphoneCore *, char *);
static int lpc_cmd_answer(LinphoneCore *, char *);
static int lpc_cmd_autoanswer(LinphoneCore *, char *);
static int lpc_cmd_terminate(LinphoneCore *, char *);
static int lpc_cmd_call_logs(LinphoneCore *, char *);
static int lpc_cmd_ipv6(LinphoneCore *, char *);
static int lpc_cmd_refer(LinphoneCore *, char *);
static int lpc_cmd_transfer(LinphoneCore *, char *);
static int lpc_cmd_quit(LinphoneCore *, char *);
static int lpc_cmd_nat(LinphoneCore *, char *);
static int lpc_cmd_stun(LinphoneCore *, char *);
@ -131,7 +132,10 @@ LPC_COMMAND commands[] = {
{ "help", lpc_cmd_help, "Print commands help", NULL },
{ "call", lpc_cmd_call, "Call a SIP uri",
"'call <sip-url>' \t: initiate a call to the specified destination.\n"
"'call show' \t: show all the current calls status.\n"
"'call show' \t: show all the current calls with their id and status.\n"
},
{ "calls", lpc_cmd_calls, "Show all the current calls with their id and status.\n",
NULL
},
{ "chat", lpc_cmd_chat, "Chat with a SIP uri",
"'chat <sip-url> \"message\"' "
@ -139,12 +143,12 @@ LPC_COMMAND commands[] = {
},
{ "terminate", lpc_cmd_terminate, "Terminate a call",
"'terminate' : Terminate the current call\n"
"'terminate <sip:XXX@XXX.XXX.XXX.XXX>' : Terminate the call with remote address\n"
"'terminate <call id>' : Terminate the call with supplied id\n"
"'terminate <all>' : Terminate all the current calls\n"
},
{ "answer", lpc_cmd_answer, "Answer a call",
"'answer' : Answer the current incoming call\n"
"'answer <sip:XXX@XXX.XXX.XXX.XXX>' : Answer the call with remote address\n"
"'answer <call id>' : Answer the call with given id\n"
},
{ "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode",
"'autoanswer' \t: show current autoanswer mode\n"
@ -177,10 +181,10 @@ LPC_COMMAND commands[] = {
"'ipv6 enable' : enable the use of the ipv6 network.\n"
"'ipv6 disable' : do not use ipv6 network."
},
{ "refer", lpc_cmd_refer,
"Refer the current call to the specified destination.",
"'refer <sip-url>' or 'r <sip-url>' "
": refer the current call to the specified destination."
{ "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"
@ -245,7 +249,7 @@ LPC_COMMAND commands[] = {
"'pause' : pause the current call\n"},
{ "resume", lpc_cmd_resume, "resume a call",
"'resume' : resume the unique call\n"
"'resume <sip:XXX@XXX.XXX.XXX.XXX>' : hold off the call with cid <cid>\n"},
"'resume <call id>' : hold off the call with given id\n"},
{ "mute", lpc_cmd_mute_mic,
"Mute microphone and suspend voice transmission."},
{ "unmute", lpc_cmd_unmute_mic,
@ -398,6 +402,35 @@ lpc_cmd_help(LinphoneCore *lc, char *arg)
static char callee_name[256]={0};
static char caller_name[256]={0};
static const char *get_call_status(LinphoneCall *call){
switch(linphone_call_get_state(call)){
case LinphoneCallPaused:
if (linphone_call_get_refer_to (call)!=NULL){
return "Paused (transfered)";
}else{
return "Paused";
}
break;
case LinphoneCallIncomingReceived:
return "Pending";
break;
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
return "Dialing out";
break;
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallOutgoingRinging:
return "Remote ringing";
break;
default:
if (linphone_call_has_transfer_pending(call)){
return "Running (transfer pending)";
}else
return "Running";
}
return "";
}
static int
lpc_cmd_call(LinphoneCore *lc, char *args)
{
@ -405,36 +438,14 @@ lpc_cmd_call(LinphoneCore *lc, char *args)
{
return 0;
}
if(!strcmp(args,"show"))
{
const MSList *calls = linphone_core_get_calls(lc);
if(calls)
{
const MSList *p_calls = calls;
linphonec_out("<remote>\t\t\t\t<status>\r\n");
while(p_calls != NULL)
{
char *tmp=linphone_call_get_remote_address_as_string(p_calls->data);
linphonec_out("%s\t\t\t%s\r\n",
tmp,
(((LinphoneCall *)p_calls->data)==linphone_core_get_current_call(lc))?"yes":"no");
p_calls = p_calls->next;
ms_free(tmp);
}
}
else
{
linphonec_out("No active call.\n");
}
}
else
{
LinphoneCall *call;
if ( linphone_core_in_call(lc) )
{
linphonec_out("Terminate or hold on the current call first.\n");
return 1;
}
if ( NULL == linphone_core_invite(lc, args) )
if ( NULL == (call=linphone_core_invite(lc, args)) )
{
linphonec_out("Error from linphone_core_invite.\n");
}
@ -446,6 +457,32 @@ lpc_cmd_call(LinphoneCore *lc, char *args)
return 1;
}
static int
lpc_cmd_calls(LinphoneCore *lc, char *args){
const MSList *calls = linphone_core_get_calls(lc);
if(calls)
{
const MSList *p_calls = calls;
linphonec_out("ID\t\tDestination\t\t\t\tStatus\n---------------------------------------------------------------------\n");
while(p_calls != NULL)
{
LinphoneCall *call=(LinphoneCall*)p_calls->data;
char *tmp=linphone_call_get_remote_address_as_string(call);
linphonec_out("%li\t%s\t\t\t%s\r\n",
(long)linphone_call_get_user_pointer (call),
tmp,
get_call_status(call));
p_calls = p_calls->next;
ms_free(tmp);
}
}else
{
linphonec_out("No active call.\n");
}
return 1;
}
static int
lpc_cmd_chat(LinphoneCore *lc, char *args)
{
@ -488,12 +525,34 @@ void linphonec_set_caller(const char *caller){
}
static int
lpc_cmd_refer(LinphoneCore *lc, char *args)
lpc_cmd_transfer(LinphoneCore *lc, char *args)
{
if (args)
linphone_core_refer(lc, linphone_core_get_current_call(lc), args);
else{
linphonec_out("refer needs an argument\n");
if (args){
LinphoneCall *call;
const char *refer_to=NULL;
char arg1[256]={0};
char arg2[266]={0};
int n=sscanf(args,"%s %s",arg1,arg2);
if (n==1 || isalpha(*arg1)){
call=linphone_core_get_current_call(lc);
if (call==NULL && linphone_core_get_calls_nb (lc)==1){
call=(LinphoneCall*)linphone_core_get_calls(lc)->data;
}
refer_to=args;
if (call==NULL){
linphonec_out("No active call, please specify a call id among the ones listed by 'calls' command.\n");
return 0;
}
}else{
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);
}else{
linphonec_out("Transfer command requires at least one argument\n");
return 0;
}
return 1;
}
@ -501,96 +560,64 @@ lpc_cmd_refer(LinphoneCore *lc, char *args)
static int
lpc_cmd_terminate(LinphoneCore *lc, char *args)
{
char *arg1 = args;
char *arg2 = NULL;
char *ptr = args;
if (linphone_core_get_calls(lc)==NULL){
linphonec_out("No active calls");
return 1;
}
if (!args)
{
if(linphone_core_in_call(lc))
{
if ( -1 == linphone_core_terminate_call(lc, linphone_core_get_current_call(lc)) )
{
linphonec_out("Could not stop the active call.\n");
}
}
else
{
linphonec_out("No active call.\n");
if ( -1 == linphone_core_terminate_call(lc, NULL) ){
linphonec_out("Could not stop the active call.\n");
}
return 1;
}
/* Isolate first and second arg */
while(*ptr && !isspace(*ptr)) ++ptr;
if ( *ptr )
{
*ptr='\0';
arg2=ptr+1;
while(*arg2 && isspace(*arg2)) ++arg2;
}
if (arg1 != 0)
{
if(strcmp(arg1,"all")==0)
{
linphonec_out("We are going to stop all the calls.\n");
return (linphone_core_terminate_all_calls(lc)==0)?1:0;
}
else
{
char the_remote_address[255];
int n = sscanf(arg1, "%s", the_remote_address);
if (n == 1)
{
if ( -1 == linphone_core_terminate_call(lc,linphone_core_get_call_by_remote_address(lc,the_remote_address)))
{
linphonec_out("Cannot stop the call with %s.\n",the_remote_address);
}
return 1;
if(strcmp(args,"all")==0){
linphonec_out("We are going to stop all the calls.\n");
linphone_core_terminate_all_calls(lc);
return 1;
}else{
/*the argument is a linphonec call id */
long id=atoi(args);
LinphoneCall *call=linphonec_get_call(id);
if (call){
if (linphone_core_terminate_call(lc,call)==-1){
linphonec_out("Could not stop the call with id %li",id);
}
}
}else return 0;
return 1;
}
return 0;
}
static int
lpc_cmd_answer(LinphoneCore *lc, char *args)
{
char *arg1 = args;
char *arg2 = NULL;
char *ptr = args;
lpc_cmd_answer(LinphoneCore *lc, char *args){
if (!args)
{
//if just one call is present answer the only one in passing NULL to the linphone_core_accept_call ...
if ( -1 == linphone_core_accept_call(lc, NULL) )
{
linphonec_out("No incoming call.\n");
int nb=ms_list_size(linphone_core_get_calls(lc));
if (nb==1){
//if just one call is present answer the only one in passing NULL to the linphone_core_accept_call ...
if ( -1 == linphone_core_accept_call(lc, NULL) )
{
linphonec_out("Fail to accept incoming call\n");
}
}else if (nb==0){
linphonec_out("There are no calls to answer.\n");
}else{
linphonec_out("Multiple calls in progress, please specify call id.\n");
return 0;
}
return 1;
}
// Isolate first and second arg
while(*ptr && !isspace(*ptr)) ++ptr;
if ( *ptr )
{
*ptr='\0';
arg2=ptr+1;
while(*arg2 && isspace(*arg2)) ++arg2;
}
if (arg1 != 0)
{
char the_remote_address[256];
int n = sscanf(arg1, "%s", the_remote_address);
if (n == 1)
{
if ( -1 == linphone_core_accept_call(lc, linphone_core_get_call_by_remote_address(lc,the_remote_address)) )
{
linphonec_out("Cannot answer the call from %s.\n",the_remote_address);
}else{
long id;
if (sscanf(args,"%li",&id)==1){
LinphoneCall *call=linphonec_get_call (id);
if (linphone_core_accept_call (lc,call)==-1){
linphonec_out("Fail to accept call %i\n",id);
}
return 1;
}
}else return 0;
return 1;
}
return 0;
}
@ -1209,40 +1236,42 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){
if(linphone_core_in_call(lc))
{
linphonec_out("There is already a call in process pause or stop it first");
return 1;
}
if (args)
{
char the_remote_address[255];
int n = sscanf(args, "%s", the_remote_address);
if (n == 1)
{
if(linphone_core_resume_call(lc,linphone_core_get_call_by_remote_address(lc,the_remote_address)) < 0)
{
linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args);
return 0;
}
else
long id;
int n = sscanf(args, "%li", &id);
if (n == 1){
LinphoneCall *call=linphonec_get_call (id);
if (call){
if(linphone_core_resume_call(lc,call)==-1)
{
linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args);
return 1;
}
}else
{
return 1;
}
}
}else return 0;
}
else
{
int returned = 0;
const MSList *calls = linphone_core_get_calls(lc);
if(ms_list_size(calls) == 1)
int nbcalls=ms_list_size(calls);
if( nbcalls == 1)
{
if(linphone_core_resume_call(lc,calls->data) < 0)
{
linphonec_out("There was a problem to resume the unique call \n");
returned = 0;
linphonec_out("There was a problem to resume the unique call.\n");
}
else
{
returned = 1;
}
return returned;
return 1;
}else if (nbcalls==0){
linphonec_out("There is no calls at this time.\n");
return 1;
}else{
linphonec_out("There are %i calls at this time, please specify call id as given with 'calls' command.\n");
}
}
return 0;

View file

@ -118,7 +118,7 @@ static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to);
static void linphonec_display_something (LinphoneCore * lc, const char *something);
static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
static void linphonec_display_warning (LinphoneCore * lc, const char *something);
static void linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg);
static void linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event);
static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid);
static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
@ -169,6 +169,24 @@ static ortp_pipe_t server_sock;
#endif /*_WIN32_WCE*/
void linphonec_call_identify(LinphoneCall* call){
static long callid=1;
linphone_call_set_user_pointer (call,(void*)callid);
callid++;
}
LinphoneCall *linphonec_get_call(long id){
const MSList *elem=linphone_core_get_calls(linphonec);
for (;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
if (linphone_call_get_user_pointer (call)==(void*)id){
return call;
}
}
linphonec_out("Sorry, no call with id %i exists at this time.",id);
return NULL;
}
/***************************************************************************
*
* Linphone core callbacks
@ -252,13 +270,12 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern
* Linphone core callback
*/
static void
linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg)
linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event)
{
printf("Notify type %s from %s\n", msg, from);
if(!strcmp(msg,"refer"))
if(!strcmp(event,"refer"))
{
printf("The distant SIP end point get the refer we can close the call\n");
linphonec_parse_command_line(linphonec, "terminate");
linphonec_out("The distand endpoint %s of call %li has been transfered, you can safely close the call.\n",
from,(long)linphone_call_get_user_pointer (call));
}
}
@ -291,27 +308,34 @@ linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf,
static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){
char *from=linphone_call_get_remote_address_as_string(call);
long id=(long)linphone_call_get_user_pointer (call);
switch(st){
case LinphoneCallEnd:
printf("Call with %s ended.\n", from);
linphonec_out("Call %i with %s ended.\n", id, from);
break;
case LinphoneCallResuming:
printf("Resuming call with %s.\n", from);
linphonec_out("Resuming call %i with %s.\n", id, from);
break;
case LinphoneCallStreamsRunning:
printf("Media streams established with %s.\n", from);
linphonec_out("Media streams established with %s for call %i.\n", from,id);
break;
case LinphoneCallPausing:
printf("Pausing call with %s.\n", from);
linphonec_out("Pausing call %i with %s.\n", id, from);
break;
case LinphoneCallPaused:
printf("Call with %s is now paused.\n", from);
linphonec_out("Call %i with %s is now paused.\n", id, from);
break;
case LinphoneCallIncomingReceived:
linphonec_call_identify(call);
id=(long)linphone_call_get_user_pointer (call);
linphonec_set_caller(from);
if ( auto_answer) {
answer_call=TRUE;
}
linphonec_out("Receiving new incoming call from %s, assigned id %i", from,id);
break;
case LinphoneCallOutgoingInit:
linphonec_call_identify(call);
break;
default:
break;
@ -682,11 +706,10 @@ void linphonec_main_loop_exit(void){
void
linphonec_finish(int exit_status)
{
printf("Terminating...\n");
linphonec_out("Terminating...\n");
/* Terminate any pending call */
linphonec_parse_command_line(linphonec, "terminate");
linphonec_command_finished();
linphone_core_terminate_all_calls(linphonec);
#ifdef HAVE_READLINE
linphonec_finish_readline();
#endif

View file

@ -112,6 +112,8 @@ void linphonec_set_autoanswer(bool_t enabled);
bool_t linphonec_get_autoanswer();
void linphonec_command_finished(void);
void linphonec_set_caller(const char *caller);
LinphoneCall *linphonec_get_call(long id);
void linphonec_call_identify(LinphoneCall* call);
#endif /* def LINPHONEC_H */

View file

@ -95,8 +95,8 @@ static void call_received(SalOp *h){
if (lc->vtable.display_status)
lc->vtable.display_status(lc,barmesg);
/* play the ring */
if (lc->sound_conf.ring_sndcard!=NULL && !linphone_core_in_call(lc)){
/* play the ring if this is the only call*/
if (lc->sound_conf.ring_sndcard!=NULL && ms_list_size(lc->calls)==1){
if(lc->ringstream==NULL){
MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
ms_message("Starting local ring...");
@ -106,6 +106,8 @@ static void call_received(SalOp *h){
{
ms_message("the local ring is already started");
}
}else{
/*TODO : play a tone within the context of the current call */
}
sal_call_notify_ringing(h);
#if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
@ -198,6 +200,16 @@ static void call_accepted(SalOp *op){
ms_free(msg);
}
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
}else if (sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly)){
/*we are put on hold when the call is initially accepted */
if (lc->vtable.display_status){
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s - on hold."),tmp);
lc->vtable.display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
}else{
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
}
@ -241,7 +253,7 @@ static void call_ack(SalOp *op){
}
/* this callback is called when an incoming re-INVITE modifies the session*/
static void call_updated(SalOp *op){
static void call_updating(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call->resultdesc)
@ -254,6 +266,13 @@ static void call_updated(SalOp *op){
{
if (call->state==LinphoneCallPaused &&
sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv) && strcmp(call->resultdesc->addr,"0.0.0.0")!=0){
/*make sure we can be resumed */
if (lc->current_call!=NULL && lc->current_call!=call){
ms_warning("Attempt to be resumed but already in call with somebody else!");
/*we are actively running another call, reject with a busy*/
sal_call_decline (op,SalReasonBusy,NULL);
return;
}
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed..."));
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
@ -263,12 +282,18 @@ static void call_updated(SalOp *op){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We are being paused..."));
linphone_call_set_state (call,LinphoneCallPaused,"Call paused");
if (lc->current_call!=call){
ms_error("Inconsitency detected: current call is %p but call %p is being paused !",lc->current_call,call);
}
lc->current_call=NULL;
}
/*accept the modification (sends a 200Ok)*/
sal_call_accept(op);
linphone_call_stop_media_streams (call);
linphone_call_init_media_streams (call);
linphone_call_start_media_streams (call);
}
if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc);
}
static void call_terminated(SalOp *op, const char *from){
@ -459,12 +484,18 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call){
if (call->refer_to!=NULL){
ms_free(call->refer_to);
}
call->refer_to=ms_strdup(referto);
call->refer_pending=TRUE;
linphone_call_set_state(call,LinphoneCallRefered,"Refered");
if (lc->vtable.display_status){
char *msg=ms_strdup_printf(_("We are transferred to %s"),referto);
lc->vtable.display_status(lc,msg);
ms_free(msg);
}
if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc);
sal_refer_accept(op);
}else if (lc->vtable.refer_received){
lc->vtable.refer_received(lc,referto);
@ -479,10 +510,10 @@ static void text_received(Sal *sal, const char *from, const char *msg){
static void notify(SalOp *op, const char *from, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
ms_message("get a %s notify from %s",msg,from);
if(lc->vtable.notify_recv)
lc->vtable.notify_recv(lc,from,msg);
lc->vtable.notify_recv(lc,call,from,msg);
}
static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
@ -525,7 +556,7 @@ SalCallbacks linphone_sal_callbacks={
call_ringing,
call_accepted,
call_ack,
call_updated,
call_updating,
call_terminated,
call_failure,
auth_requested,

View file

@ -87,7 +87,7 @@ static int find_port_offset(LinphoneCore *lc){
MSList *elem;
int audio_port;
bool_t already_used=FALSE;
for(offset=0;offset<100;++offset){
for(offset=0;offset<100;offset+=2){
audio_port=linphone_core_get_audio_port (lc)+offset;
already_used=FALSE;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
@ -204,13 +204,17 @@ static void linphone_call_set_terminated(LinphoneCall *call){
}
linphone_call_log_completed(call->log,call, status);
if (linphone_core_del_call(lc,call) != 0){
ms_error("Could not remove the call from the list !!!");
}
if (call == lc->current_call){
ms_message("Resetting the current call");
lc->current_call=NULL;
linphone_core_start_pending_refered_calls(lc);
}
if (linphone_core_del_call(lc,call) != 0){
ms_error("Could not remove the call from the list !!!");
}
if (ms_list_size(lc->calls)==0)
linphone_core_notify_all_friends(lc,lc->presence_mode);
@ -226,7 +230,11 @@ static void linphone_call_set_terminated(LinphoneCall *call){
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
LinphoneCore *lc=call->core;
if (call->state!=cstate){
call->state=cstate;
if (cstate!=LinphoneCallRefered){
/*LinphoneCallRefered is rather an event, not a state.
Indeed it does not change the state of the call (still paused or running)*/
call->state=cstate;
}
if (lc->vtable.call_state_changed)
lc->vtable.call_state_changed(lc,call,cstate,message);
}
@ -251,6 +259,9 @@ static void linphone_call_destroy(LinphoneCall *obj)
if (obj->ping_op) {
sal_op_release(obj->ping_op);
}
if (obj->refer_to){
ms_free(obj->refer_to);
}
ms_free(obj);
}
@ -336,7 +347,7 @@ LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
}
/**
* Returns the refer-to uri (if the call received was transfered).
* Returns the refer-to uri (if the call was transfered).
**/
const char *linphone_call_get_refer_to(const LinphoneCall *call){
return call->refer_to;
@ -346,6 +357,18 @@ LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
return call->log->dir;
}
/**
* Returns true if this calls has received a transfer that has not been
* executed yet.
* Pending transfers are executed when this call is being paused or closed,
* locally or by remote endpoint.
* If the call is already paused while receiving the transfer request, the
* transfer immediately occurs.
**/
bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
return call->refer_pending;
}
/**
* @}
**/

View file

@ -1671,25 +1671,22 @@ void linphone_core_iterate(LinphoneCore *lc){
call = linphone_core_get_current_call(lc);
if(call)
{
if (call->state==LinphoneCallConnected)
if (one_second_elapsed)
{
if (one_second_elapsed)
{
RtpSession *as=NULL,*vs=NULL;
lc->prevtime=curtime;
if (call->audiostream!=NULL)
as=call->audiostream->session;
if (call->videostream!=NULL)
vs=call->videostream->session;
display_bandwidth(as,vs);
}
#ifdef VIDEO_ENABLED
RtpSession *as=NULL,*vs=NULL;
lc->prevtime=curtime;
if (call->audiostream!=NULL)
as=call->audiostream->session;
if (call->videostream!=NULL)
video_stream_iterate(call->videostream);
#endif
if (call->audiostream!=NULL && disconnect_timeout>0)
disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
vs=call->videostream->session;
display_bandwidth(as,vs);
}
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL)
video_stream_iterate(call->videostream);
#endif
if (call->audiostream!=NULL && disconnect_timeout>0)
disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
}
if (linphone_core_video_preview_enabled(lc)){
if (lc->previewstream==NULL && lc->calls==NULL)
@ -1835,6 +1832,19 @@ bool_t linphone_core_is_in_communication_with(LinphoneCore *lc, const char *to)
return returned;
}
void linphone_core_start_pending_refered_calls(LinphoneCore *lc){
MSList *elem;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
if (call->refer_pending){
ms_message("Starting new call to refered address %s",call->refer_to);
call->refer_pending=FALSE;
linphone_core_invite(lc,call->refer_to);
break;
}
}
}
LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){
const MSList *elem;
LinphoneProxyConfig *found_cfg=NULL;
@ -2036,7 +2046,13 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr
return call;
}
int linphone_core_refer(LinphoneCore *lc, LinphoneCall *call, const char *url)
/**
* Performs a simple call transfer to the specified destination.
*
* The remote endpoint is expected to issue a new call to the specified destination.
* The current call remains active and thus can be later paused or terminated.
**/
int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url)
{
char *real_url=NULL;
LinphoneAddress *real_parsed_url=linphone_core_interpret_url(lc,url);
@ -2053,6 +2069,7 @@ int linphone_core_refer(LinphoneCore *lc, LinphoneCall *call, const char *url)
real_url=linphone_address_as_string (real_parsed_url);
sal_refer(call->op,real_url);
ms_free(real_url);
linphone_address_destroy(real_parsed_url);
return 0;
}
@ -2114,7 +2131,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call)
MSList *elem;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneCall *c=(LinphoneCall*)elem->data;
if (c!=call && (c->state!=LinphoneCallPaused || c->state!=LinphoneCallPausing)){
if (c!=call && (c->state!=LinphoneCallPaused)){
ms_warning("Cannot accept this call as another one is running, pause it before.");
return -1;
}
@ -2181,8 +2198,10 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call)
LinphoneCall *call;
if (the_call == NULL){
call = linphone_core_get_current_call(lc);
if(call == NULL){
ms_warning("No currently active call to terminate !");
if (ms_list_size(lc->calls)==1){
call=(LinphoneCall*)lc->calls->data;
}else{
ms_warning("No unique call to terminate !");
return -1;
}
}
@ -2276,6 +2295,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call)
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Pausing the current call..."));
lc->current_call=NULL;
linphone_core_start_pending_refered_calls(lc);
return 0;
}

View file

@ -172,6 +172,7 @@ void linphone_call_ref(LinphoneCall *call);
void linphone_call_unref(LinphoneCall *call);
LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call);
const char *linphone_call_get_refer_to(const LinphoneCall *call);
bool_t linphone_call_has_transfer_pending(const LinphoneCall *call);
void *linphone_call_get_user_pointer(LinphoneCall *call);
void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer);
@ -419,7 +420,7 @@ typedef void (*DisplayUrlCb)(struct _LinphoneCore *lc, const char *message, cons
/** Callback prototype */
typedef void (*LinphoneCoreCbFunc)(struct _LinphoneCore *lc,void * user_data);
/** Callback prototype */
typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, const char *from, const char *msg);
typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const char *from, const char *event);
/** Callback prototype */
typedef void (*NotifyPresenceReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * fid);
/** Callback prototype */
@ -509,7 +510,7 @@ LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url);
LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr);
int linphone_core_refer(LinphoneCore *lc, LinphoneCall *call, const char *url);
int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to);
bool_t linphone_core_inc_invite_pending(LinphoneCore*lc);

View file

@ -76,6 +76,7 @@ struct _LinphoneCall
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
char *refer_to;
bool_t refer_pending;
bool_t media_pending;
bool_t audio_muted;
};
@ -184,7 +185,7 @@ void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float
void linphone_core_stop_waiting(LinphoneCore *lc);
int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
void linphone_core_start_pending_refered_calls(LinphoneCore *lc);
extern SalCallbacks linphone_sal_callbacks;

View file

@ -187,7 +187,7 @@ typedef void (*SalOnCallReceived)(SalOp *op);
typedef void (*SalOnCallRinging)(SalOp *op);
typedef void (*SalOnCallAccepted)(SalOp *op);
typedef void (*SalOnCallAck)(SalOp *op);
typedef void (*SalOnCallUpdated)(SalOp *op);
typedef void (*SalOnCallUpdating)(SalOp *op);/*< Called when a reINVITE is received*/
typedef void (*SalOnCallTerminated)(SalOp *op, const char *from);
typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code);
typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username);
@ -210,7 +210,7 @@ typedef struct SalCallbacks{
SalOnCallRinging call_ringing;
SalOnCallAccepted call_accepted;
SalOnCallAck call_ack;
SalOnCallUpdated call_updated;
SalOnCallUpdating call_updating;
SalOnCallTerminated call_terminated;
SalOnCallFailure call_failure;
SalOnAuthRequested auth_requested;
@ -273,6 +273,7 @@ void *sal_op_get_user_pointer(const SalOp *op);
int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc);
int sal_call(SalOp *h, const char *from, const char *to);
int sal_call_notify_ringing(SalOp *h);
/*accept an incoming call or, during a call accept a reINVITE*/
int sal_call_accept(SalOp*h);
int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/);
int sal_call_hold(SalOp *h, bool_t holdon);

View file

@ -284,8 +284,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub;
if (ctx->callbacks.call_terminated==NULL)
ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub;
if (ctx->callbacks.call_updated==NULL)
ctx->callbacks.call_updated=(SalOnCallUpdated)unimplemented_stub;
if (ctx->callbacks.call_updating==NULL)
ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub;
if (ctx->callbacks.auth_requested==NULL)
ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub;
if (ctx->callbacks.auth_success==NULL)
@ -773,35 +773,27 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){
sal_media_description_unref(op->base.remote_media);
op->base.remote_media=NULL;
}
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&msg);
eXosip_unlock();
if (msg==NULL) return;
if (op->base.root->session_expires!=0){
if (op->supports_session_timers) osip_message_set_supported(msg, "timer");
}
if (op->base.contact){
_osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(msg,op->base.contact);
if (op->result){
sal_media_description_unref(op->result);
op->result=NULL;
}
if (sdp){
op->sdp_offering=FALSE;
op->base.remote_media=sal_media_description_new();
sdp_to_media_description(sdp,op->base.remote_media);
sdp_message_free(sdp);
sdp_process(op);
if (op->sdp_answer!=NULL){
set_sdp(msg,op->sdp_answer);
sdp_message_free(op->sdp_answer);
op->sdp_answer=NULL;
}
sal->callbacks.call_updating(op);
}else {
op->sdp_offering=TRUE;
set_sdp_from_desc(msg,op->base.local_media);
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&msg);
if (msg!=NULL){
set_sdp_from_desc(msg,op->base.local_media);
eXosip_call_send_answer(ev->tid,200,msg);
}
eXosip_unlock();
}
eXosip_lock();
eXosip_call_send_answer(ev->tid,200,msg);
eXosip_unlock();
}
static void handle_ack(Sal *sal, eXosip_event_t *ev){
@ -820,7 +812,7 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){
sdp_message_free(sdp);
}
if (op->reinvite){
sal->callbacks.call_updated(op);
if (sdp) sal->callbacks.call_updating(op);
op->reinvite=FALSE;
}else{
sal->callbacks.call_ack(op);

@ -1 +1 @@
Subproject commit 236222b3f08baf502742b6c75633f50e3a14917f
Subproject commit 6cc9076b9cc4d6b88e7a0b93e6abdd1ad881e832

2
oRTP

@ -1 +1 @@
Subproject commit a084620745b1b1c81ec93501ffbb3de373f7c8c9
Subproject commit d2a8cb0890c7547703a092c839c55db10449ef92

View file

@ -72,3 +72,5 @@ mediastreamer2/src/audiomixer.c
mediastreamer2/src/chanadapt.c
mediastreamer2/src/itc.c
mediastreamer2/src/extdisplay.c
mediastreamer2/src/msiounit.c