From 950c65ffd9077845ddf9f69a84d588d92a627ad0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 31 Jul 2012 17:14:15 +0200 Subject: [PATCH] Defer ringing when ICE is activated to be able to gather local candidates. --- coreapi/callbacks.c | 70 ++--------------- coreapi/linphonecall.c | 174 +++++++++++++++++++++++------------------ coreapi/linphonecore.c | 72 +++++++++++++++++ coreapi/linphonecore.h | 2 + 4 files changed, 176 insertions(+), 142 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 8ec8f39b..cd3290aa 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -140,16 +140,10 @@ static bool_t already_a_call_pending(LinphoneCore *lc){ static void call_received(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); - char *barmesg; LinphoneCall *call; const char *from,*to; - char *tmp; - LinphoneAddress *from_parsed; LinphoneAddress *from_addr, *to_addr; - SalMediaDescription *md; - bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE); bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE); - const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc); /* first check if we can answer successfully to this invite */ if (lc->presence_mode==LinphoneStatusBusy || @@ -188,72 +182,18 @@ static void call_received(SalOp *h){ call=linphone_call_new_incoming(lc,from_addr,to_addr,h); sal_call_set_local_media_description(h,call->localdesc); - md=sal_call_get_final_media_description(h); - - if (md && sal_media_description_empty(md)){ - sal_call_decline(h,SalReasonMedia,NULL); - linphone_call_unref(call); - return; - } /* the call is acceptable so we can now add it to our list */ linphone_core_add_call(lc,call); - - from_parsed=linphone_address_new(sal_op_get_from(h)); - linphone_address_clean(from_parsed); - tmp=linphone_address_as_string(from_parsed); - linphone_address_destroy(from_parsed); - barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), - (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_(".")); - if (lc->vtable.show) lc->vtable.show(lc); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,barmesg); - - /* play the ring if this is the only call*/ - if (ms_list_size(lc->calls)==1){ - lc->current_call=call; - if (lc->ringstream && lc->dmfs_playing_start_time!=0){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - lc->dmfs_playing_start_time=0; - } - if (lc->sound_conf.ring_sndcard!=NULL){ - if(lc->ringstream==NULL && lc->sound_conf.local_ring){ - MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; - ms_message("Starting local ring..."); - lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard); - } - else - { - ms_message("the local ring is already started"); - } - } - }else{ - /* else play a tone within the context of the current call */ - call->ringing_beep=TRUE; - linphone_core_play_tone(lc); - } - - linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */ - linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); - - if (call->state==LinphoneCallIncomingReceived){ - sal_call_notify_ringing(h,propose_early_media || ringback_tone!=NULL); - if (propose_early_media || ringback_tone!=NULL){ - linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); - md=sal_call_get_final_media_description(h); - linphone_core_update_streams(lc,call,md); - } - if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ - linphone_core_accept_call(lc,call); - } + if (linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) { + /* Defer ringing until the end of the ICE candidates gathering process. */ + ms_message("Defer ringing to gather ICE candidates"); + return; } - linphone_call_unref(call); - ms_free(barmesg); - ms_free(tmp); + linphone_core_notify_incoming_call(lc,call); } static void call_ringing(SalOp *h){ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 75518a14..e2948f59 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -390,7 +390,14 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->camera_active=call->params.has_video; switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: - linphone_core_gather_ice_candidates(call->core, call); + linphone_call_init_media_streams(call); + linphone_call_start_media_streams_for_ice_gathering(call); + if (linphone_core_gather_ice_candidates(call->core,call)<0) { + /* Ice candidates gathering failed, proceed with the call anyway. */ + ice_session_destroy(sal_op_get_ice_session(call->op)); + sal_op_set_ice_session(call->op, NULL); + linphone_call_stop_media_streams(call); + } break; case LinphonePolicyUseStun: linphone_core_run_stun_tests(call->core,call); @@ -1469,6 +1476,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ rtp_session_unregister_event_queue(call->audiostream->session,call->audiostream_app_evq); ortp_ev_queue_flush(call->audiostream_app_evq); ortp_ev_queue_destroy(call->audiostream_app_evq); + call->audiostream_app_evq=NULL; if (call->audiostream->ec){ const char *state_str=NULL; @@ -1690,98 +1698,110 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse } #ifdef VIDEO_ENABLED if (call->videostream!=NULL) { + OrtpEvent *ev; + // Beware that the application queue should not depend on treatments fron the // mediastreamer queue. video_stream_iterate(call->videostream); - if (call->videostream_app_evq){ - OrtpEvent *ev; - while (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq))){ - OrtpEventType evt=ortp_event_get_type(ev); - OrtpEventData *evd=ortp_event_get_data(ev); - if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ - linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); - } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { - call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->session); - if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp); - call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); - } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { - memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->session), sizeof(jitter_stats_t)); - if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp); - call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); - } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) { - linphone_core_update_call(lc, call, &call->current_params); - } - } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { - if (call->state==LinphoneCallOutgoingInit) { - linphone_call_stop_media_streams(call); - if (evd->info.ice_processing_successful==FALSE) { - ice_session_destroy(sal_op_get_ice_session(call->op)); - sal_op_set_ice_session(call->op, NULL); - } - linphone_core_start_invite(call->core,call,NULL); - } + while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){ + OrtpEventType evt=ortp_event_get_type(ev); + OrtpEventData *evd=ortp_event_get_data(ev); + if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ + linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); + } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { + call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->session); + if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL) + freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp); + call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet; + evd->packet = NULL; + if (lc->vtable.call_stats_updated) + lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); + } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { + memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->session), sizeof(jitter_stats_t)); + if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL) + freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp); + call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet; + evd->packet = NULL; + if (lc->vtable.call_stats_updated) + lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); + } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) { + linphone_core_update_call(lc, call, &call->current_params); + } + } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { + IceSession *ice_session = sal_op_get_ice_session(call->op); + linphone_call_stop_media_streams(call); + if (evd->info.ice_processing_successful==TRUE) { + ice_session_compute_candidates_foundations(ice_session); + ice_session_eliminate_redundant_candidates(ice_session); + ice_session_choose_default_candidates(ice_session); + } else { + ice_session_destroy(ice_session); + sal_op_set_ice_session(call->op, NULL); + } + if (call->state==LinphoneCallOutgoingInit) { + linphone_core_start_invite(call->core,call,NULL); + } else { + linphone_core_notify_incoming_call(call->core,call); } - ortp_event_destroy(ev); } + ortp_event_destroy(ev); } } #endif if (call->audiostream!=NULL) { + OrtpEvent *ev; + // Beware that the application queue should not depend on treatments fron the // mediastreamer queue. audio_stream_iterate(call->audiostream); - if (call->audiostream_app_evq){ - OrtpEvent *ev; - while (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq))){ - OrtpEventType evt=ortp_event_get_type(ev); - OrtpEventData *evd=ortp_event_get_data(ev); - if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ - linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); - } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { - linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified); - } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { - call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->session); - if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp); - call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); - } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { - memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->session), sizeof(jitter_stats_t)); - if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp); - call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); - } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) { - linphone_core_update_call(lc, call, &call->current_params); - } - } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { - if (call->state==LinphoneCallOutgoingInit) { - linphone_call_stop_media_streams(call); - if (evd->info.ice_processing_successful==FALSE) { - ice_session_destroy(sal_op_get_ice_session(call->op)); - sal_op_set_ice_session(call->op, NULL); - } - linphone_core_start_invite(call->core,call,NULL); - } + while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){ + OrtpEventType evt=ortp_event_get_type(ev); + OrtpEventData *evd=ortp_event_get_data(ev); + if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ + linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); + } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { + linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified); + } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { + call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->session); + if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL) + freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp); + call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet; + evd->packet = NULL; + if (lc->vtable.call_stats_updated) + lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); + } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { + memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->session), sizeof(jitter_stats_t)); + if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL) + freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp); + call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet; + evd->packet = NULL; + if (lc->vtable.call_stats_updated) + lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); + } else if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + if (ice_session_role(sal_op_get_ice_session(call->op)) == IR_Controlling) { + linphone_core_update_call(lc, call, &call->current_params); + } + } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { + IceSession *ice_session = sal_op_get_ice_session(call->op); + linphone_call_stop_media_streams(call); + if (evd->info.ice_processing_successful==TRUE) { + ice_session_compute_candidates_foundations(ice_session); + ice_session_eliminate_redundant_candidates(ice_session); + ice_session_choose_default_candidates(ice_session); + } else { + ice_session_destroy(sal_op_get_ice_session(call->op)); + sal_op_set_ice_session(call->op, NULL); + } + if (call->state==LinphoneCallOutgoingInit) { + linphone_core_start_invite(call->core,call,NULL); + } else { + linphone_core_notify_incoming_call(call->core,call); } - ortp_event_destroy(ev); } + ortp_event_destroy(ev); } } if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 ) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 060259a4..73ef52c3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2373,6 +2373,78 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } +void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ + char *barmesg; + char *tmp; + LinphoneAddress *from_parsed; + SalMediaDescription *md; + bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE); + const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc); + + /* Regenerate final media description to include all ICE candidates. */ + md=sal_call_get_final_media_description(call->op); + + if (md && sal_media_description_empty(md)){ + sal_call_decline(call->op,SalReasonMedia,NULL); + linphone_call_unref(call); + return; + } + + from_parsed=linphone_address_new(sal_op_get_from(call->op)); + linphone_address_clean(from_parsed); + tmp=linphone_address_as_string(from_parsed); + linphone_address_destroy(from_parsed); + barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), + (sal_call_autoanswer_asked(call->op)) ?_(" and asked autoanswer."):_(".")); + if (lc->vtable.show) lc->vtable.show(lc); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,barmesg); + + /* play the ring if this is the only call*/ + if (ms_list_size(lc->calls)==1){ + lc->current_call=call; + if (lc->ringstream && lc->dmfs_playing_start_time!=0){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; + lc->dmfs_playing_start_time=0; + } + if (lc->sound_conf.ring_sndcard!=NULL){ + if(lc->ringstream==NULL && lc->sound_conf.local_ring){ + MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; + ms_message("Starting local ring..."); + lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard); + } + else + { + ms_message("the local ring is already started"); + } + } + }else{ + /* else play a tone within the context of the current call */ + call->ringing_beep=TRUE; + linphone_core_play_tone(lc); + } + + linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); + + if (call->state==LinphoneCallIncomingReceived){ + sal_call_notify_ringing(call->op,propose_early_media || ringback_tone!=NULL); + + if (propose_early_media || ringback_tone!=NULL){ + linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); + md=sal_call_get_final_media_description(call->op); + linphone_core_update_streams(lc,call,md); + } + if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ + linphone_core_accept_call(lc,call); + } + } + linphone_call_unref(call); + + ms_free(barmesg); + ms_free(tmp); +} + /** * @ingroup call_control * Updates a running call according to supplied call parameters or parameters changed in the LinphoneCore. diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 10f6108c..67e887c6 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -783,6 +783,8 @@ int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); +void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); + bool_t linphone_core_in_call(const LinphoneCore *lc); LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc); -- 2.39.2