diff --git a/console/linphonec.c b/console/linphonec.c index 86187ad..024075c 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -123,6 +123,8 @@ static void linphonec_display_url (LinphoneCore * lc, const char *something, con static void linphonec_display_warning (LinphoneCore * lc, const char *something); static void stub () {} static void linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg); +static void linphonec_ack_paused_received(LinphoneCore *lc, LinphoneCall *call); +static void linphonec_ack_resumed_received(LinphoneCore *lc, LinphoneCall *call); static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid); static void linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); @@ -185,6 +187,8 @@ LinphoneCoreVTable linphonec_vtable .paused_recv = linphonec_paused_received, .resumed_recv = linphonec_resumed_received, .notify_recv = linphonec_notify_received, + .ack_paused_recv = linphonec_ack_paused_received, + .ack_resumed_recv = linphonec_ack_resumed_received, .notify_presence_recv = linphonec_notify_presence_received, .new_unknown_subscriber = linphonec_new_unknown_subscriber, .auth_info_requested = linphonec_prompt_for_auth, @@ -348,6 +352,34 @@ linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg) * Linphone core callback */ static void +linphonec_ack_paused_received(LinphoneCore *lc, LinphoneCall *call) +{ + char *from=linphone_call_get_remote_address_as_string(call); + if(from) + { + linphonec_out("the previous pause sent to %s has been acknowledged\n",from); + ms_free(from); + } +} + +/* + * Linphone core callback + */ +static void +linphonec_ack_resumed_received(LinphoneCore *lc, LinphoneCall *call) +{ + char *from=linphone_call_get_remote_address_as_string(call); + if(from) + { + linphonec_out("the previous resume sent to %s has been acknowledged\n",from); + ms_free(from); + } +} + +/* + * Linphone core callback + */ +static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid) { char *tmp=linphone_address_as_string(linphone_friend_get_address(fid)); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 67611e2..1af84c1 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -37,6 +37,10 @@ static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ ring_stop(lc->ringstream); lc->ringstream=NULL; } + if(!linphone_core_in_call(lc)) + { + linphone_core_set_as_current_call(lc,call); + } if(call == linphone_core_get_current_call(lc)) linphone_core_start_media_streams(lc,call); } @@ -114,8 +118,15 @@ static void call_received(SalOp *h){ /* play the ring */ if (lc->sound_conf.ring_sndcard!=NULL && !linphone_core_in_call(lc)){ - ms_message("Starting local ring..."); - lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); + if(lc->ringstream==NULL) + { + ms_message("Starting local ring..."); + lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); + } + else + { + ms_message("the local ring is already started"); + } } call->state=LinphoneCallRinging; sal_call_notify_ringing(h); @@ -166,6 +177,11 @@ static void call_ringing(SalOp *h){ call->state=LinphoneCallRinging; } +/* + * could be reach : + * - when the call is accepted + * - when a request is accepted (pause, resume) + */ static void call_accepted(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); @@ -174,7 +190,10 @@ static void call_accepted(SalOp *op){ return ; } if (call->state==LinphoneCallAVRunning){ - return ; /*already accepted*/ + ms_message("GET ACK of resume\n"); + if(lc->vtable.ack_resumed_recv) + lc->vtable.ack_resumed_recv(lc,call); + return ; //already accepted } if ((lc->audiostream!=NULL) && (lc->audiostream->ticker!=NULL)){ /*case where we accepted early media */ @@ -192,8 +211,18 @@ static void call_accepted(SalOp *op){ call->media_pending=FALSE; } if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ - gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); - linphone_connect_incoming(lc,call); + //if we initiate a pause + if(call->state == LinphoneCallPaused) + { + ms_message("GET ACK of pause\n"); + if(lc->vtable.ack_paused_recv) + lc->vtable.ack_paused_recv(lc,call); + }//if there is an accepted incoming call + else + { + gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); + linphone_connect_incoming(lc,call); + } }else{ /*send a bye*/ ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); @@ -289,7 +318,8 @@ static void call_terminated(SalOp *op, const char *from){ return; } ms_message("Current call terminated..."); - if (lc->ringstream!=NULL) { + //we stop the call only if we have this current call or if we are in call + if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) { ring_stop(lc->ringstream); lc->ringstream=NULL; } @@ -501,6 +531,10 @@ static void ping_reply(SalOp *op){ linphone_core_start_invite(call->core,call,NULL); } } + else + { + ms_warning("ping reply without call attached..."); + } } SalCallbacks linphone_sal_callbacks={ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5f7ae7a..e45a121 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1359,9 +1359,22 @@ static void display_bandwidth(RtpSession *as, RtpSession *vs){ (vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0); } -static void linphone_core_disconnected(LinphoneCore *lc){ - lc->vtable.display_warning(lc,_("Remote end seems to have disconnected, the call is going to be closed.")); - linphone_core_terminate_call(lc,NULL); +static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ + char temp[256]; + char *from; + if(call) + from = linphone_call_get_remote_address_as_string(call); + if(from) + { + snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from); + free(from); + } + else + { + snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed."); + } + lc->vtable.display_warning(lc,temp); + linphone_core_terminate_call(lc,call);//TODO failure ?? } static void monitor_network_state(LinphoneCore *lc, time_t curtime){ @@ -1477,6 +1490,8 @@ static void linphone_core_do_plugin_tasks(LinphoneCore *lc){ * serialized with a mutex. **/ void linphone_core_iterate(LinphoneCore *lc){ + MSList *the_call; + LinphoneCall *call; int disconnect_timeout = linphone_core_get_nortp_timeout(lc); time_t curtime=time(NULL); int elapsed; @@ -1499,21 +1514,35 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->auto_net_state_mon) monitor_network_state(lc,curtime); proxy_update(lc); - LinphoneCall *call = linphone_core_get_current_call(lc); - if(call){ + + //we have to iterate for each call + the_call = lc->calls; + while(the_call != NULL) + { + call = (LinphoneCall *)the_call->data; if (call->state==LinphoneCallPreEstablishing && (curtime-call->start_time>=2)){ - /*start the call even if the OPTIONS reply did not arrive*/ - linphone_core_start_invite(lc,call,NULL); - } - if (call->dir==LinphoneCallIncoming && call->state==LinphoneCallRinging){ - elapsed=curtime-call->start_time; - ms_message("incoming call ringing for %i seconds",elapsed); - if (elapsed>lc->sip_conf.inc_timeout){ - call->log->status=LinphoneCallMissed; - linphone_core_terminate_call(lc,NULL); + /*start the call even if the OPTIONS reply did not arrive*/ + linphone_core_start_invite(lc,call,NULL); } - }else if (call->state==LinphoneCallAVRunning){ - if (one_second_elapsed){ + if (call->dir==LinphoneCallIncoming && call->state==LinphoneCallRinging){ + elapsed=curtime-call->start_time; + ms_message("incoming call ringing for %i seconds",elapsed); + if (elapsed>lc->sip_conf.inc_timeout){ + call->log->status=LinphoneCallMissed; + linphone_core_terminate_call(lc,call); + } + } + + the_call = the_call->next; + }//end while + //and consider the current call + call = linphone_core_get_current_call(lc); + if(call) + { + if (call->state==LinphoneCallAVRunning) + { + if (one_second_elapsed) + { RtpSession *as=NULL,*vs=NULL; lc->prevtime=curtime; if (lc->audiostream!=NULL) @@ -1541,7 +1570,7 @@ void linphone_core_iterate(LinphoneCore *lc){ toggle_video_preview(lc,FALSE); } if (disconnected) - linphone_core_disconnected(lc); + linphone_core_disconnected(lc,call); linphone_core_do_plugin_tasks(lc); @@ -1749,7 +1778,9 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro ms_free(contact); } call->state=LinphoneCallInit; - linphone_core_init_media_streams(lc,call); + //TODO : should probably not be done here + if(! linphone_core_in_call(lc) ) + linphone_core_init_media_streams(lc,call); if (!lc->sip_conf.sdp_200_ack){ call->media_pending=TRUE; sal_call_set_local_media_description(call->op,call->localdesc); @@ -1852,7 +1883,6 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr linphone_call_unref(call); return NULL; } - linphone_core_set_as_current_call(lc,call); if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){ err=linphone_core_start_invite(lc,call,dest_proxy); }else{ @@ -1904,6 +1934,9 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ } void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call){ +#ifdef PRINTF_DEBUG + printf("%s(%d)\n",__FUNCTION__,__LINE__); +#endif SalMediaDescription *md=call->localdesc; lc->audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc)); if (linphone_core_echo_limiter_enabled(lc)){ @@ -2064,10 +2097,22 @@ static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md, } void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ +#ifdef PRINTF_DEBUG + printf("%s(%d)\n",__FUNCTION__,__LINE__); +#endif LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); const char *tool="linphone-" LINPHONE_VERSION; char *cname; int used_pt=-1; + if(lc->audiostream == NULL) + { + ms_warning("init media stream is needed before starting"); + linphone_core_init_media_streams(lc,call); + /* + * example of problem : + * 2 incomings calls, you answer and pause one, afterward if you try to answer the other call you will get SEGFAULT + */ + } /* adjust rtp jitter compensation. It must be at least the latency of the sound card */ int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp); @@ -2157,6 +2202,9 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ } void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){ +#ifdef PRINTF_DEBUG + printf("%s(%d)\n",__FUNCTION__,__LINE__); +#endif if (lc->audiostream!=NULL) { audio_stream_stop(lc->audiostream); lc->audiostream=NULL; @@ -2297,13 +2345,10 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) * @param lc The LinphoneCore **/ int linphone_core_terminate_all_calls(LinphoneCore *lc){ - MSList *calls; - - calls = lc->calls; - while(calls->next != NULL) + while(lc->calls) { - linphone_core_terminate_call(lc,(LinphoneCall *)calls->data); - calls = calls->next; + LinphoneCall *the_call = lc->calls->data; + linphone_core_terminate_call(lc,the_call); } ms_list_free(lc->calls); return -1; @@ -2370,10 +2415,15 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call) ms_error("The call asked to be paused was not the current on\n"); return -3; } - sal_call_hold(call->op,TRUE); + if(sal_call_hold(call->op,TRUE) != 0) + { + lc->vtable.display_warning(lc,_("Could not pause the call")); + } call->state = LinphoneCallPaused; linphone_core_unset_the_current_call(lc); linphone_core_stop_media_streams(lc,call); + //have to be done ... because if another call is incoming before this pause, you will get sound on the end point paused + linphone_core_init_media_streams(lc,call); lc->vtable.display_status(lc,_("Pause the current call")); return 0; } @@ -2407,13 +2457,21 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) return -2; } } + if(call->state == LinphoneCallInit || call->state == LinphoneCallPreEstablishing || call->state == LinphoneCallRinging ) + { + ms_warning("we cannot resume a call when the communication is not established"); + return -3; + } if(linphone_core_get_current_call(lc) != NULL) { ms_error("There is already a call in process pause or stop it first\n"); - return -3; + return -4; } linphone_core_init_media_streams(lc,call); - sal_call_hold(call->op,FALSE); + if(sal_call_hold(call->op,FALSE) != 0) + { + lc->vtable.display_warning(lc,_("Could not resume the call")); + } call->state = LinphoneCallAVRunning; linphone_core_set_as_current_call(lc,call); linphone_core_start_media_streams(lc,call); @@ -3544,18 +3602,18 @@ LpConfig *linphone_core_get_config(LinphoneCore *lc){ static void linphone_core_uninit(LinphoneCore *lc) { - if(linphone_core_get_calls_nb(lc)){ - int i; - linphone_core_terminate_all_calls(lc); - for(i=0;i<10;++i){ -#ifndef WIN32 - usleep(50000); + while(lc->calls) + { + LinphoneCall *the_call = lc->calls->data; + linphone_core_terminate_call(lc,the_call); + linphone_core_iterate(lc); +#ifdef WIN32 + Sleep(50000); #else - Sleep(50); + usleep(50000); #endif - linphone_core_iterate(lc); - } } + if (lc->friends) ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, NULL); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 5c25073..d7ac4ab 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -408,6 +408,10 @@ typedef void (*PausedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); /** Callback prototype */ typedef void (*ResumedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); /** Callback prototype */ +typedef void (*AckPausedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); +/** Callback prototype */ +typedef void (*AckResumedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); +/** Callback prototype */ typedef void (*DisplayStatusCb)(struct _LinphoneCore *lc, const char *message); /** Callback prototype */ typedef void (*DisplayMessageCb)(struct _LinphoneCore *lc, const char *message); @@ -450,8 +454,10 @@ typedef struct _LinphoneVTable RingingReceivedCb ringing_recv; /**< Notify that the distant phone is ringing*/ ConnectedReceivedCb connected_recv; /**< Notify that the distant phone answered the call*/ FailureReceivedCb failure_recv; /**< Notify that the call failed*/ - PausedReceivedCb paused_recv; /**< Notify that the call failed*/ - ResumedReceivedCb resumed_recv; /**< Notify that the call failed*/ + PausedReceivedCb paused_recv; /**< Notify that the call has been paused*/ + ResumedReceivedCb resumed_recv; /**< Notify that the call has been resumed*/ + AckPausedReceivedCb ack_paused_recv;/**< Notify that the previous command pause sent to the call has been acknowledge*/ + AckResumedReceivedCb ack_resumed_recv;/**< Notify that the previous command resumed sent to the call has been acknowledge*/ NotifyPresenceReceivedCb notify_presence_recv; /**< Notify received presence events*/ NewUnknownSubscriberCb new_unknown_subscriber; /**< Notify about unknown subscriber */ AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 94a51fa..6091f18 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1427,6 +1427,9 @@ static void other_request_reply(Sal *sal,eXosip_event_t *ev){ } static bool_t process_event(Sal *sal, eXosip_event_t *ev){ +#ifdef PRINTF_DEBUG + printf("EVENT (%d)\n",ev->type); +#endif ms_message("linphone process event get a message %d\n",ev->type); switch(ev->type){ case EXOSIP_CALL_ANSWERED: @@ -1716,7 +1719,10 @@ int sal_call_hold(SalOp *h, bool_t holdon) int err=0; osip_message_t *reinvite; - eXosip_call_build_request(h->did,"INVITE",&reinvite); + if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS) + return -1; + if(reinvite==NULL) + return -2; osip_message_set_subject(reinvite,osip_strdup("Phone Call Hold")); osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); if (h->base.root->session_expires!=0){