diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 0fa8fc0d7..46daca009 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -743,6 +743,15 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const 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->transferer){ + linphone_call_unref(call->transferer); + call->transferer=NULL; + } + if (call->transfer_target){ + linphone_call_unref(call->transfer_target); + call->transfer_target=NULL; + } linphone_call_unref(call); } } @@ -773,6 +782,12 @@ static void linphone_call_destroy(LinphoneCall *obj) if (obj->refer_to){ ms_free(obj->refer_to); } + if (obj->transferer){ + linphone_call_unref(obj->transferer); + } + if (obj->transfer_target){ + linphone_call_unref(obj->transfer_target); + } if (obj->owns_call_log) linphone_call_log_destroy(obj->log); if (obj->auth_token) { @@ -940,6 +955,21 @@ const char *linphone_call_get_refer_to(const LinphoneCall *call){ return call->refer_to; } +/** + * Returns the transferer if this call was started automatically as a result of an incoming transfer request. + * The call in which the transfer request was received is returned in this case. +**/ +LinphoneCall *linphone_call_get_transferer_call(const LinphoneCall *call){ + return call->transferer; +} + +/** + * When this call has received a transfer request, returns the new call that was automatically created as a result of the transfer. +**/ +LinphoneCall *linphone_call_get_transfer_target_call(const LinphoneCall *call){ + return call->transfer_target; +} + /** * Returns direction of the call (incoming or outgoing). **/ @@ -2468,6 +2498,10 @@ void linphone_call_log_completed(LinphoneCall *call){ call_logs_write_to_config_file(lc); } +/** + * Returns the current transfer state, if a transfer has been initiated from this call. + * @see linphone_core_transfer_call() , linphone_core_transfer_call_to_another() +**/ LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) { return call->transfer_state; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 426c85c3e..0184afab0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2333,7 +2333,10 @@ void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){ call->refer_pending=FALSE; newcall=linphone_core_invite_with_params(lc,call->refer_to,cp); linphone_call_params_destroy(cp); - if (newcall) linphone_core_notify_refer_state(lc,call,newcall); + if (newcall) { + call->transfer_target=linphone_call_ref(newcall); + linphone_core_notify_refer_state(lc,call,newcall); + } } } @@ -2670,6 +2673,10 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const linphone_call_unref(call); return NULL; } + if (params && params->referer){ + call->transferer=linphone_call_ref(params->referer); + } + /* this call becomes now the current one*/ lc->current_call=call; linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); @@ -2728,6 +2735,10 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const * @ingroup call_control * The remote endpoint is expected to issue a new call to the specified destination. * The current call remains active and thus can be later paused or terminated. + * + * It is possible to follow the progress of the transfer provided that transferee sends notification about it. + * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. **/ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url) { @@ -2764,6 +2775,10 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char * This method will send a transfer request to the transfered person. The phone of the transfered is then * expected to automatically call to the destination of the transfer. The receiver of the transfer will then automatically * close the call with us (the 'dest' call). + * + * It is possible to follow the progress of the transfer provided that transferee sends notification about it. + * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. **/ int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){ int result = sal_call_refer_with_replaces (call->op,dest->op); @@ -3312,25 +3327,23 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) call = the_call; } switch (call->state) { - case LinphoneCallReleased: - case LinphoneCallEnd: - ms_warning("No need to terminate a call [%p] in state [%s]",call,linphone_call_state_to_string(call->state)); - return -1; - case LinphoneCallIncomingReceived: - case LinphoneCallIncomingEarlyMedia: - return linphone_core_decline_call(lc,call,LinphoneReasonDeclined); - case LinphoneCallOutgoingInit: { - /* In state OutgoingInit, op has to be destroyed */ - sal_op_release(call->op); - call->op = NULL; + case LinphoneCallReleased: + case LinphoneCallEnd: + ms_warning("No need to terminate a call [%p] in state [%s]",call,linphone_call_state_to_string(call->state)); + return -1; + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + return linphone_core_decline_call(lc,call,LinphoneReasonDeclined); + case LinphoneCallOutgoingInit: { + /* In state OutgoingInit, op has to be destroyed */ + sal_op_release(call->op); + call->op = NULL; + break; + } + default: + sal_call_terminate(call->op); break; - } - - default: - sal_call_terminate(call->op); - break; } - terminate_call(lc,call); return 0; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 6fe0fc7c4..97f94fc83 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -121,7 +121,9 @@ struct _LinphoneCall; typedef struct _LinphoneCall LinphoneCall; /** - * Enum describing failure reasons. + * Enum describing various failure reasons or contextual information for some events. + * @see linphone_call_get_reason() + * @see linphone_proxy_config_get_error() * @ingroup misc **/ enum _LinphoneReason{ @@ -134,8 +136,7 @@ enum _LinphoneReason{ LinphoneReasonBusy, /**identity); MSList* lcs=ms_list_append(NULL,marie->lc); @@ -946,6 +948,7 @@ static void simple_call_transfer(void) { CU_ASSERT_TRUE(call(marie,pauline)); + marie_calling_pauline=linphone_core_get_current_call(marie->lc); pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); reset_counters(&marie->stat); @@ -961,6 +964,9 @@ static void simple_call_transfer(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPaused,1,2000)); /*marie calling laure*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + + CU_ASSERT_PTR_NOT_NULL(linphone_call_get_transfer_target_call(marie_calling_pauline)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); @@ -970,6 +976,11 @@ static void simple_call_transfer(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + + marie_calling_laure=linphone_core_get_current_call(marie->lc); + CU_ASSERT_PTR_NOT_NULL_FATAL(marie_calling_laure); + CU_ASSERT_TRUE(linphone_call_get_transferer_call(marie_calling_laure)==marie_calling_pauline); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallConnected,1,2000)); /*terminate marie to pauline call*/