]> sjero.net Git - linphone/commitdiff
many bugfixes and improvements for multicall
authorSimon Morlat <simon.morlat@linphone.org>
Fri, 20 Aug 2010 14:33:11 +0000 (16:33 +0200)
committerSimon Morlat <simon.morlat@linphone.org>
Fri, 20 Aug 2010 14:33:11 +0000 (16:33 +0200)
13 files changed:
console/commands.c
console/linphonec.c
console/linphonec.h
coreapi/callbacks.c
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/linphonecore.h
coreapi/private.h
coreapi/sal.h
coreapi/sal_eXosip2.c
mediastreamer2
oRTP
po/POTFILES.in

index 2f07bbdad79d70f02882a998c1babe008f341dcc..c3e1e472fda1668ea148ceebc522847aa5e8585f 100644 (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");
-               }
-               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;
index c00d87632bc4f6595d4c92e78b7dcf6ce244b612..df86abb8fbf85b4b2dc13ec7c2ed94afe357d2e1 100644 (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
index 90b6f68425e17540ed1ba29e523f161838c02450..235aa5e97addd36c5ddde04b44e2f58acff8f108 100644 (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 */
 
index aa8bf3f30881b1f192b45bb0948e35b241d1a694..6d0cd8b8fe1960f5f017ee7c8e96dc9731a9fc0a 100644 (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,
index fbb4f02121eacfcec0caa133492245cb605d0847..871d00e5702299374e3ce17f9c3c5aee4a518a2d 100644 (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;
+}
+
 /**
  * @}
 **/
index 6cf8725f30d961dd8f742d879f960a3bd465bf1b..38f69d23d5e016511f03993bd571295e7ffdfefa 100644 (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;
 }
 
index a1ed9d317e94fe5c4b6d205790b37b65edc208c2..d0c680d928562ecd8cfb0d5f7d60a2f93b1c0b16 100644 (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);
 
index e5d0e9055592ab4c7448ed419c3983293dd4477b..cb3ff78e278a1000ecaa21c2f2301de663b25754 100644 (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;
 
 
index fd3f6f21bc76b31ed10d0d6f3a15e161d1adf22a..7c6c7867bb545451d0dcbd475b2d0f74620868a4 100644 (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);
index ec0b7aff88f09af691d254bc12090fc2eea1e939..8e4afe22e4ca14ce5a3ef05513041d0c1200a38d 100644 (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);
index 236222b3f08baf502742b6c75633f50e3a14917f..6cc9076b9cc4d6b88e7a0b93e6abdd1ad881e832 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 236222b3f08baf502742b6c75633f50e3a14917f
+Subproject commit 6cc9076b9cc4d6b88e7a0b93e6abdd1ad881e832
diff --git a/oRTP b/oRTP
index a084620745b1b1c81ec93501ffbb3de373f7c8c9..d2a8cb0890c7547703a092c839c55db10449ef92 160000 (submodule)
--- a/oRTP
+++ b/oRTP
@@ -1 +1 @@
-Subproject commit a084620745b1b1c81ec93501ffbb3de373f7c8c9
+Subproject commit d2a8cb0890c7547703a092c839c55db10449ef92
index 2b0f2734f9e185649c02db51711ea7a0624b354f..3fcfbdd201be78602c434d3009da6cdf8a202447 100644 (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
+