From f6537cb2b541f3904a1988bf781d399b6bf3e8a2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 2 Jun 2010 14:18:07 +0200 Subject: [PATCH] fix release of call objects --- coreapi/callbacks.c | 22 +++++------- coreapi/linphonecall.c | 76 +++++++++++++++++++++++++++++++++++------- coreapi/linphonecore.c | 24 ++++++------- 3 files changed, 85 insertions(+), 37 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 4b53ffdad..31b5e723a 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -82,17 +82,11 @@ static void call_received(SalOp *h){ to=sal_op_get_to(h); call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h); - if(linphone_core_add_call(lc,call)!= 0) - { - ms_warning("we cannot have more calls\n"); - sal_call_decline(h,SalReasonMedia,NULL); - linphone_call_unref(call); - return; - } + if(linphone_core_get_current_call(lc)!=NULL) //we are already in call just inform that an incoming call is going on { char temp[256]; - snprintf(temp,sizeof(temp),"A new incoming call from %s during call",from); + snprintf(temp,sizeof(temp)-1,"A new incoming call from %s during call",from); lc->vtable.display_status(lc,temp); } sal_call_set_local_media_description(h,call->localdesc); @@ -104,6 +98,8 @@ static void call_received(SalOp *h){ 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); @@ -330,18 +326,19 @@ static void call_terminated(SalOp *op, const char *from){ lc->vtable.show(lc); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call terminated.")); - linphone_call_set_terminated(call); + call->state=LinphoneCallTerminated; gstate_new_state(lc, GSTATE_CALL_END, NULL); if (lc->vtable.bye_recv!=NULL){ LinphoneAddress *addr=linphone_address_new(from); char *tmp; linphone_address_clean(addr); tmp=linphone_address_as_string(addr); - lc->vtable.bye_recv(lc,call); + if (lc->vtable.bye_recv!=NULL) + lc->vtable.bye_recv(lc,call); ms_free(tmp); linphone_address_destroy(addr); } - linphone_call_unref(call); + linphone_call_set_terminated(call); } static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){ @@ -413,10 +410,9 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if(call == linphone_core_get_current_call(lc)) linphone_core_stop_media_streams(lc,call); if (call!=NULL) { - linphone_call_set_terminated(call); - linphone_call_unref(call);//TODO not an unref here ???//AUREL if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg); else gstate_new_state(lc, GSTATE_CALL_END, NULL); + linphone_call_set_terminated(call); } } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 26ece225b..ac165a629 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -151,20 +151,45 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro return call; } +/* this function is called internally to get rid of a call. + It performs the following tasks: + - remove the call from the internal list of calls + - unref the LinphoneCall object + - update the call logs accordingly +*/ + void linphone_call_set_terminated(LinphoneCall *call){ LinphoneCallStatus status=LinphoneCallAborted; + LinphoneCore *lc=call->core; + + if (ms_list_size(lc->calls)==0) + linphone_core_notify_all_friends(lc,lc->prev_mode); + + linphone_core_update_allocated_audio_bandwidth(lc); if (call->state==LinphoneCallAVRunning){ status=LinphoneCallSuccess; + } linphone_call_log_completed(call->log,call, status); call->state=LinphoneCallTerminated; + if (linphone_core_del_call(lc,call) != 0){ + ms_error("could not remove the call from the list !!!"); + } + if (call == linphone_core_get_current_call(lc)){ + ms_message("destroying the current call\n"); + linphone_core_unset_the_current_call(lc); + } + if (call->op!=NULL) { + /* so that we cannot have anymore upcalls for SAL + concerning this call*/ + sal_op_release(call->op); + call->op=NULL; + } + linphone_call_unref(call); } static void linphone_call_destroy(LinphoneCall *obj) { - linphone_core_notify_all_friends(obj->core,obj->core->prev_mode); - - linphone_core_update_allocated_audio_bandwidth(obj->core); if (obj->op!=NULL) { sal_op_release(obj->op); obj->op=NULL; @@ -180,40 +205,62 @@ static void linphone_call_destroy(LinphoneCall *obj) if (obj->ping_op) { sal_op_release(obj->ping_op); } - if(linphone_core_del_call(obj->core,obj) != 0) - { - ms_error("could not remove the call from the list !!!"); - } - if(obj == linphone_core_get_current_call(obj->core)) - { - ms_message("destroying the current call\n"); - linphone_core_unset_the_current_call(obj->core); - } ms_free(obj); } +/** + * @addtogroup calls + * @{ +**/ + +/** + * Increments the call 's reference count. + * An application that wishes to retain a pointer to call object + * must use this function to unsure the pointer remains + * valid. Once the application no more needs this pointer, + * it must call linphone_call_unref(). +**/ void linphone_call_ref(LinphoneCall *obj){ obj->refcnt++; } +/** + * Decrements the call object reference count. + * See linphone_call_ref(). +**/ void linphone_call_unref(LinphoneCall *obj){ obj->refcnt--; if (obj->refcnt==0) linphone_call_destroy(obj); } +/** + * Returns true if the call is paused. +**/ bool_t linphone_call_paused(LinphoneCall *call){ return call->state==LinphoneCallPaused; } +/** + * Returns the remote address associated to this call + * +**/ const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){ return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to; } +/** + * Returns the remote address associated to this call as a string. + * + * The result string must be freed by user using ms_free(). +**/ char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){ return linphone_address_as_string(linphone_call_get_remote_address(call)); } +/** + * Retrieves the call's current state. +**/ LinphoneCallState linphone_call_get_state(const LinphoneCall *call){ return call->state; } @@ -241,3 +288,8 @@ void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer) { call->user_pointer = user_pointer; } + +/** + * @} +**/ + diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ac10f2453..a58061421 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1523,7 +1523,7 @@ static void linphone_core_do_plugin_tasks(LinphoneCore *lc){ * serialized with a mutex. **/ void linphone_core_iterate(LinphoneCore *lc){ - MSList *the_call; + MSList *calls; LinphoneCall *call; int disconnect_timeout = linphone_core_get_nortp_timeout(lc); time_t curtime=time(NULL); @@ -1550,10 +1550,13 @@ void linphone_core_iterate(LinphoneCore *lc){ proxy_update(lc); //we have to iterate for each call - the_call = lc->calls; - while(the_call != NULL) - { - call = (LinphoneCall *)the_call->data; + calls= lc->calls; + while(calls!= NULL){ + call = (LinphoneCall *)calls->data; + /* get immediately a reference to next one in case the one + we are going to examine is destroy and removed during + linphone_core_start_invite() */ + calls=calls->next; 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); @@ -1566,10 +1569,7 @@ void linphone_core_iterate(LinphoneCore *lc){ 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) { @@ -1840,7 +1840,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro lc->vtable.display_status(lc,_("could not call")); if(call == linphone_core_get_current_call(lc)) linphone_core_stop_media_streams(lc,call); - linphone_call_unref(call); + linphone_call_set_terminated (call); }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, real_url); ms_free(real_url); ms_free(from); @@ -2377,7 +2377,6 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) lc->vtable.display_status(lc,_("Call ended") ); gstate_new_state(lc, GSTATE_CALL_END, NULL); linphone_call_set_terminated(call); - linphone_call_unref(call); return 0; } @@ -3788,6 +3787,7 @@ bool_t linphone_core_can_we_add_call(LinphoneCore *lc) { if(linphone_core_get_calls_nb(lc) < NB_MAX_CALLS) return TRUE; + ms_error("Maximum amount of simultaneous calls reached !"); return FALSE; } @@ -3828,7 +3828,7 @@ int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) if(linphone_core_can_we_add_call(lc)) { MSList *the_calls = lc->calls; - the_calls = ms_list_append(the_calls,(void *)call); + the_calls = ms_list_append(the_calls,call); lc->calls = the_calls; return 0; }