Commit d32da007 authored by Simon Morlat's avatar Simon Morlat
Browse files

many bugfixes and improvements for multicall

parent 9d37f359
......@@ -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");
}
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)) )
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("Cannot answer the call from %s.\n",the_remote_address);
linphonec_out("Fail to accept incoming call\n");
}
return 1;
}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;
}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);
}
}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;
}
else
{
returned = 1;
linphonec_out("There was a problem to resume the unique call.\n");
}
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;
......
......@@ -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
......
......@@ -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 */
......
......@@ -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);