Commit 2e515642 authored by Simon Morlat's avatar Simon Morlat
Browse files

fix bad call state notification (Released) when receiving a call with incompatible codecs.

Normally this should not trigger any notification.
Fix bug allowing two incoming calls to be notified if ICE is used.
parent 9db4ae27
......@@ -224,7 +224,8 @@ static bool_t already_a_call_pending(LinphoneCore *lc){
|| call->state==LinphoneCallOutgoingInit
|| call->state==LinphoneCallOutgoingProgress
|| call->state==LinphoneCallOutgoingEarlyMedia
|| call->state==LinphoneCallOutgoingRinging){
|| call->state==LinphoneCallOutgoingRinging
|| call->state==LinphoneCallIdle){ /*case of an incoming call for which ICE candidate gathering is pending.*/
return TRUE;
}
}
......@@ -239,6 +240,7 @@ static void call_received(SalOp *h){
LinphoneAddress *to_addr=NULL;
/*this mode is deprcated because probably useless*/
bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",FALSE);
SalMediaDescription *md;
/* first check if we can answer successfully to this invite */
if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) {
......@@ -301,8 +303,19 @@ static void call_received(SalOp *h){
linphone_address_destroy(to_addr);
return;
}
call=linphone_call_new_incoming(lc,from_addr,to_addr,h);
linphone_call_make_local_media_description(lc,call);
sal_call_set_local_media_description(call->op,call->localdesc);
md=sal_call_get_final_media_description(call->op);
if (md){
if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){
sal_call_decline(call->op,SalReasonNotAcceptable,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);
......@@ -372,6 +385,10 @@ static void call_ringing(SalOp *h){
md=sal_call_get_final_media_description(h);
if (md==NULL){
linphone_core_stop_dtmf_stream(lc);
if (call->state==LinphoneCallOutgoingEarlyMedia){
/*already doing early media */
return;
}
if (lc->ringstream!=NULL) return;/*already ringing !*/
if (lc->sound_conf.play_sndcard!=NULL){
MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
......@@ -422,7 +439,7 @@ static void call_accepted(SalOp *op){
/* Handle remote ICE attributes if any. */
if (call->ice_session != NULL) {
linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
linphone_call_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
}
#ifdef BUILD_UPNP
if (call->upnp_session != NULL) {
......
......@@ -381,6 +381,19 @@ void linphone_call_increment_local_media_description(LinphoneCall *call){
md->session_ver++;
}
void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call){
if (call->ice_session != NULL) {
_update_local_media_description_from_ice(call->localdesc, call->ice_session);
linphone_core_update_ice_state_in_call_stats(call);
}
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
linphone_core_update_upnp_state_in_call_stats(call);
}
#endif //BUILD_UPNP
}
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
MSList *l;
PayloadType *pt;
......@@ -463,18 +476,9 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
setup_rtcp_xr(call, md);
update_media_description_from_stun(md,&call->ac,&call->vc);
if (call->ice_session != NULL) {
linphone_core_update_local_media_description_from_ice(md, call->ice_session);
linphone_core_update_ice_state_in_call_stats(call);
}
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
linphone_core_update_upnp_state_in_call_stats(call);
}
#endif //BUILD_UPNP
linphone_address_destroy(addr);
call->localdesc=md;
linphone_call_update_local_media_description_from_ice_or_upnp(call);
linphone_address_destroy(addr);
if (old_md){
call->localdesc_changed=sal_media_description_equals(md,old_md);
sal_media_description_unref(old_md);
......@@ -840,7 +844,50 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
return call;
}
/* this function is called internally to get rid of a call.
/*
* Frees the media resources of the call.
* This has to be done at the earliest, unlike signaling resources that sometimes need to be kept a bit more longer.
* It is called by linphone_call_set_terminated() (for termination of calls signaled to the application), or directly by the destructor of LinphoneCall
* (_linphone_call_destroy) if the call was never notified to the application.
*/
void linphone_call_free_media_resources(LinphoneCall *call){
linphone_call_stop_media_streams(call);
ms_media_stream_sessions_uninit(&call->sessions[0]);
ms_media_stream_sessions_uninit(&call->sessions[1]);
linphone_call_delete_upnp_session(call);
linphone_call_delete_ice_session(call);
linphone_call_stats_uninit(&call->stats[0]);
linphone_call_stats_uninit(&call->stats[1]);
}
/*
* Called internally when reaching the Released state, to perform cleanups to break circular references.
**/
static void linphone_call_set_released(LinphoneCall *call){
if (call->op!=NULL) {
/*transfer the last error so that it can be obtained even in Released state*/
if (call->non_op_error.reason==SalReasonNone){
const SalErrorInfo *ei=sal_op_get_error_info(call->op);
sal_error_info_set(&call->non_op_error,ei->reason,ei->protocol_code,ei->status_string,ei->warnings);
}
/* so that we cannot have anymore upcalls for SAL
concerning this call*/
sal_op_release(call->op);
call->op=NULL;
}
/*it is necessary to reset pointers to other call to prevent circular references that would result in memory never freed.*/
if (call->referer){
linphone_call_unref(call->referer);
call->referer=NULL;
}
if (call->transfer_target){
linphone_call_unref(call->transfer_target);
call->transfer_target=NULL;
}
linphone_call_unref(call);
}
/* this function is called internally to get rid of a call that was notified to the application, because it reached the end or error state.
It performs the following tasks:
- remove the call from the internal list of calls
- update the call logs accordingly
......@@ -849,17 +896,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
static void linphone_call_set_terminated(LinphoneCall *call){
LinphoneCore *lc=call->core;
linphone_call_stop_media_streams(call);
ms_media_stream_sessions_uninit(&call->sessions[0]);
ms_media_stream_sessions_uninit(&call->sessions[1]);
linphone_call_delete_upnp_session(call);
linphone_call_delete_ice_session(call);
linphone_core_update_allocated_audio_bandwidth(lc);
linphone_call_stats_uninit(&call->stats[0]);
linphone_call_stats_uninit(&call->stats[1]);
linphone_call_free_media_resources(call);
linphone_call_log_completed(call);
if (call == lc->current_call){
ms_message("Resetting the current call");
lc->current_call=NULL;
......@@ -868,7 +907,6 @@ static void linphone_call_set_terminated(LinphoneCall *call){
if (linphone_core_del_call(lc,call) != 0){
ms_error("Could not remove the call from the list !!!");
}
linphone_core_conference_check_uninit(lc);
if (call->ringing_beep){
linphone_core_stop_dtmf(lc);
......@@ -931,11 +969,7 @@ const char *linphone_call_state_to_string(LinphoneCallState cs){
return "undefined state";
}
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message) {
linphone_call_set_state_base(call, cstate, message,FALSE);
}
void linphone_call_set_state_base(LinphoneCall *call, LinphoneCallState cstate, const char *message,bool_t silently){
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
LinphoneCore *lc=call->core;
if (call->state!=cstate){
......@@ -974,45 +1008,24 @@ void linphone_call_set_state_base(LinphoneCall *call, LinphoneCallState cstate,
call->log->connected_date_time=time(NULL);
}
if (!silently)
linphone_core_notify_call_state_changed(lc,call,cstate,message);
linphone_core_notify_call_state_changed(lc,call,cstate,message);
linphone_reporting_call_state_updated(call);
/*cancelling DTMF sequence, if any*/
if (cstate!=LinphoneCallStreamsRunning&&call->dtmfs_timer!=NULL){
if (cstate!=LinphoneCallStreamsRunning && call->dtmfs_timer!=NULL){
linphone_call_cancel_dtmfs(call);
}
if (cstate==LinphoneCallReleased){
if (call->op!=NULL) {
/*transfer the last error so that it can be obtained even in Released state*/
if (call->non_op_error.reason==SalReasonNone){
const SalErrorInfo *ei=sal_op_get_error_info(call->op);
sal_error_info_set(&call->non_op_error,ei->reason,ei->protocol_code,ei->status_string,ei->warnings);
}
/* so that we cannot have anymore upcalls for SAL
concerning this call*/
sal_op_release(call->op);
call->op=NULL;
}
/*it is necessary to reset pointers to other call to prevent circular references that would result in memory never freed.*/
if (call->referer){
linphone_call_unref(call->referer);
call->referer=NULL;
}
if (call->transfer_target){
linphone_call_unref(call->transfer_target);
call->transfer_target=NULL;
}
linphone_call_unref(call);
linphone_call_set_released(call);
}
}
}
static void linphone_call_destroy(LinphoneCall *obj)
{
static void linphone_call_destroy(LinphoneCall *obj){
ms_message("Call [%p] freed.",obj);
if (obj->audiostream || obj->videostream){
linphone_call_free_media_resources(obj);
}
if (obj->op!=NULL) {
sal_op_release(obj->op);
obj->op=NULL;
......@@ -1031,9 +1044,11 @@ static void linphone_call_destroy(LinphoneCall *obj)
}
if (obj->ping_op) {
sal_op_release(obj->ping_op);
obj->ping_op=NULL;
}
if (obj->refer_to){
ms_free(obj->refer_to);
obj->refer_to=NULL;
}
if (obj->referer){
linphone_call_unref(obj->referer);
......@@ -1041,20 +1056,30 @@ static void linphone_call_destroy(LinphoneCall *obj)
}
if (obj->transfer_target){
linphone_call_unref(obj->transfer_target);
obj->transfer_target=NULL;
}
if (obj->log) {
linphone_call_log_unref(obj->log);
obj->log=NULL;
}
if (obj->auth_token) {
ms_free(obj->auth_token);
obj->auth_token=NULL;
}
if (obj->dtmfs_timer) {
linphone_call_cancel_dtmfs(obj);
}
linphone_call_params_unref(obj->params);
linphone_call_params_unref(obj->current_params);
if (obj->params){
linphone_call_params_unref(obj->params);
obj->params=NULL;
}
if (obj->current_params){
linphone_call_params_unref(obj->current_params);
obj->current_params=NULL;
}
if (obj->remote_params != NULL) {
linphone_call_params_unref(obj->remote_params);
obj->remote_params=NULL;
}
sal_error_info_reset(&obj->non_op_error);
}
......@@ -1497,7 +1522,7 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
if (has_video) _linphone_call_prepare_ice_for_stream(call,1,TRUE);
/*start ICE gathering*/
if (incoming_offer)
linphone_core_update_ice_from_remote_media_description(call,remote); /*this may delete the ice session*/
linphone_call_update_ice_from_remote_media_description(call,remote); /*this may delete the ice session*/
if (call->ice_session && !ice_session_candidates_gathered(call->ice_session)){
if (call->audiostream->ms.state==MSStreamInitialized)
audio_stream_prepare_sound(call->audiostream, NULL, NULL);
......@@ -2839,6 +2864,8 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
break;
case LinphoneCallIdle:
linphone_call_stop_media_streams_for_ice_gathering(call);
linphone_call_update_local_media_description_from_ice_or_upnp(call);
sal_call_set_local_media_description(call->op,call->localdesc);
linphone_core_notify_incoming_call(call->core, call);
break;
default:
......
......@@ -1299,6 +1299,7 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){
*/
void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
lc->net_conf.download_bw=bw;
linphone_core_update_allocated_audio_bandwidth(lc);
if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","download_bw",bw);
}
......@@ -1315,6 +1316,7 @@ void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
*/
void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
lc->net_conf.upload_bw=bw;
linphone_core_update_allocated_audio_bandwidth(lc);
if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw);
}
......@@ -1821,6 +1823,7 @@ int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs)
if (lc->codecs_conf.audio_codecs!=NULL) ms_list_free(lc->codecs_conf.audio_codecs);
lc->codecs_conf.audio_codecs=codecs;
_linphone_core_codec_config_write(lc);
linphone_core_update_allocated_audio_bandwidth(lc);
return 0;
}
......@@ -3216,22 +3219,9 @@ 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);
linphone_call_make_local_media_description(lc,call);
sal_call_set_local_media_description(call->op,call->localdesc);
md=sal_call_get_final_media_description(call->op);
if (md){
if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){
sal_call_decline(call->op,SalReasonNotAcceptable,NULL);
linphone_call_set_state_base(call, LinphoneCallError, NULL,TRUE);
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);
......@@ -6395,11 +6385,17 @@ bool_t linphone_core_can_we_add_call(LinphoneCore *lc)
return FALSE;
}
static void notify_soundcard_usage(LinphoneCore *lc, bool_t used){
MSSndCard *card=lc->sound_conf.capt_sndcard;
if (card && ms_snd_card_get_capabilities(card) & MS_SND_CARD_CAP_IS_SLOW){
ms_snd_card_set_usage_hint(card,used);
}
}
int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call)
{
if(linphone_core_can_we_add_call(lc))
{
if (linphone_core_can_we_add_call(lc)){
if (lc->calls==NULL) notify_soundcard_usage(lc,TRUE);
lc->calls = ms_list_append(lc->calls,call);
return 0;
}
......@@ -6422,6 +6418,7 @@ int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call)
return -1;
}
lc->calls = the_calls;
if (lc->calls==NULL) notify_soundcard_usage(lc,FALSE);
return 0;
}
......
......@@ -86,6 +86,7 @@ int linphone_core_enable_payload_type(LinphoneCore *lc, LinphonePayloadType *pt,
if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
payload_type_set_enable(pt,enabled);
_linphone_core_codec_config_write(lc);
linphone_core_update_allocated_audio_bandwidth(lc);
return 0;
}
ms_error("Enabling codec not in audio or video list of PayloadType !");
......@@ -113,6 +114,7 @@ void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, LinphonePayloadTyp
if (pt->type==PAYLOAD_VIDEO || pt->flags & PAYLOAD_TYPE_IS_VBR){
pt->normal_bitrate=bitrate*1000;
pt->flags|=PAYLOAD_TYPE_BITRATE_OVERRIDE;
linphone_core_update_allocated_audio_bandwidth(lc);
}else{
ms_error("Cannot set an explicit bitrate for codec %s/%i, because it is not VBR.",pt->mime_type,pt->clock_rate);
return;
......@@ -189,7 +191,6 @@ int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const LinphonePaylo
return get_audio_payload_bandwidth(lc,pt,maxbw);
}else if (pt->type==PAYLOAD_VIDEO){
int video_bw;
linphone_core_update_allocated_audio_bandwidth(lc);
if (maxbw<=0) {
video_bw=1500; /*default bitrate for video stream when no bandwidth limit is set, around 1.5 Mbit/s*/
}else{
......@@ -700,7 +701,7 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
}
}
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
{
const char *rtp_addr, *rtcp_addr;
IceSessionState session_state = ice_session_state(session);
......@@ -821,7 +822,7 @@ static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed){
call->videostream->ms.ice_check_list=NULL;
}
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
{
bool_t ice_restarted = FALSE;
......
......@@ -188,8 +188,7 @@ typedef struct _PortConfig{
int rtcp_port;
}PortConfig;
struct _LinphoneCall
{
struct _LinphoneCall{
belle_sip_object_t base;
void *user_data;
struct _LinphoneCore *core;
......@@ -377,8 +376,9 @@ void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, Linphone
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call);
void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev);
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call);
void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md);
void linphone_core_send_initial_subscribes(LinphoneCore *lc);
......@@ -413,7 +413,6 @@ void linphone_call_delete_upnp_session(LinphoneCall *call);
void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call);
void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md);
void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call);
void linphone_call_set_state_base(LinphoneCall *call, LinphoneCallState cstate, const char *message,bool_t silently);
int _linphone_core_apply_transports(LinphoneCore *lc);
const char * linphone_core_get_identity(LinphoneCore *lc);
......
......@@ -840,6 +840,8 @@ int linphone_upnp_call_process(LinphoneCall *call) {
linphone_core_proceed_with_invite_if_ready(lc, call, NULL);
break;
case LinphoneCallIdle:
linphone_call_update_local_media_description_from_ice_or_upnp(call);
sal_call_set_local_media_description(call->op,call->localdesc);
linphone_core_notify_incoming_call(lc, call);
break;
default:
......
mediastreamer2 @ 71115380
Subproject commit e07bc4ba689e5f5dfc868b69ba4919f3e149b346
Subproject commit 71115380b55d0a3f5a40405baaed2535b1913dda
......@@ -704,24 +704,37 @@ static void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mi
#endif
static void call_failed_because_of_codecs(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall* out_call;
int begin,leaked_objects;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
{
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall* out_call;
disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1);
disable_all_audio_codecs_except_one(pauline->lc,"pcma",-1);
out_call = linphone_core_invite(pauline->lc,"marie");
linphone_call_ref(out_call);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1));
disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1);
disable_all_audio_codecs_except_one(pauline->lc,"pcma",-1);
out_call = linphone_core_invite(pauline->lc,"marie");
linphone_call_ref(out_call);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1));
/*flexisip will retain the 488 until the "urgent reply" timeout (I.E 5s) arrives.*/
CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,7000));
CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonNotAcceptable);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0);
/*flexisip will retain the 488 until the "urgent reply" timeout (I.E 5s) arrives.*/
CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,7000));
CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonNotAcceptable);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallReleased,0);
linphone_call_unref(out_call);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
linphone_call_unref(out_call);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_TRUE(leaked_objects==0);
if (leaked_objects>0){
belle_sip_object_dump_active_objects();
}
}
static void call_with_dns_time_out(void) {
......@@ -2042,8 +2055,6 @@ static void call_with_mkv_file_player(void) {
char *recordpath;
double similar;
ortp_set_log_level_mask(ORTP_ERROR | ORTP_FATAL | ORTP_MESSAGE | ORTP_WARNING);
if (!is_format_supported(marie->lc,"mkv")){
ms_warning("Test skipped, no mkv support.");
goto end;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment