Defer ringing when ICE is activated to be able to gather local candidates.

This commit is contained in:
Ghislain MARY 2012-07-31 17:14:15 +02:00
parent 53d44ea8ee
commit 950c65ffd9
4 changed files with 176 additions and 142 deletions

View file

@ -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){

View file

@ -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 )

View file

@ -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.

View file

@ -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);