Improve API so that it is more object-oriented.

This commit is contained in:
Ghislain MARY 2017-02-13 16:18:37 +01:00
parent 7276f565f2
commit e53d4cf70d
11 changed files with 1113 additions and 815 deletions

View file

@ -50,7 +50,7 @@ static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *old
return result;
}
void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
void linphone_core_update_streams_destinations(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
SalStreamDescription *new_audiodesc = NULL;
SalStreamDescription *new_videodesc = NULL;
char *rtp_addr, *rtcp_addr;
@ -124,55 +124,55 @@ void linphone_call_update_frozen_payloads(LinphoneCall *call, SalMediaDescriptio
}
}
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state){
SalMediaDescription *oldmd=call->resultdesc;
int md_changed=0;
void linphone_call_update_streams(LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state) {
LinphoneCore *lc = linphone_call_get_core(call);
SalMediaDescription *oldmd = call->resultdesc;
int md_changed = 0;
if (!((call->state == LinphoneCallIncomingEarlyMedia) && (linphone_core_get_ring_during_incoming_early_media(lc)))) {
linphone_core_stop_ringing(lc);
}
if (!new_md) {
ms_error("linphone_core_update_streams() called with null media description");
ms_error("linphone_call_update_streams() called with null media description");
return;
}
linphone_call_update_biggest_desc(call, call->localdesc);
sal_media_description_ref(new_md);
call->resultdesc=new_md;
if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){
call->resultdesc = new_md;
if ((call->audiostream && (call->audiostream->ms.state == MSStreamStarted)) || (call->videostream && (call->videostream->ms.state == MSStreamStarted))) {
clear_early_media_destinations(call);
/* we already started media: check if we really need to restart it*/
if (oldmd){
/* We already started media: check if we really need to restart it */
if (oldmd) {
md_changed = media_parameters_changed(call, oldmd, new_md);
if ((md_changed & ( SAL_MEDIA_DESCRIPTION_CODEC_CHANGED
|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED
|SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED
|SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED
|SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION ))){
|SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION ))) {
ms_message("Media descriptions are different, need to restart the streams.");
} else if ( call->playing_ringbacktone) {
} else if (call->playing_ringbacktone) {
ms_message("Playing ringback tone, will restart the streams.");
} else {
if (md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) {
if (call->all_muted){
if (call->all_muted) {
ms_message("Early media finished, unmuting inputs...");
/*we were in early media, now we want to enable real media */
/* We were in early media, now we want to enable real media */
call->all_muted = FALSE;
if (call->audiostream)
linphone_core_enable_mic(lc, linphone_core_mic_enabled(lc));
if (call->audiostream) linphone_core_enable_mic(lc, linphone_core_mic_enabled(lc));
#ifdef VIDEO_ENABLED
if (call->videostream && call->camera_enabled)
if (call->videostream && call->camera_enabled) {
linphone_call_enable_camera(call, linphone_call_camera_enabled(call));
}
#endif
}
/*FIXME ZRTP, might be restarted in any cases ? */
ms_message("No need to restart streams, SDP is unchanged.");
goto end;
}else {
} else {
if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) {
ms_message("Network parameters have changed, update them.");
linphone_core_update_streams_destinations(lc, call, oldmd, new_md);
linphone_core_update_streams_destinations(call, oldmd, new_md);
}
if (md_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) {
ms_message("Crypto parameters have changed, update them.");
@ -182,34 +182,35 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
}
}
}
linphone_call_stop_media_streams (call);
if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED){
ms_message("Media ip type has changed, destroying sessions context on call [%p]",call);
linphone_call_stop_media_streams(call);
if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED) {
ms_message("Media ip type has changed, destroying sessions context on call [%p]", call);
ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]);
ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]);
ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]);
}
linphone_call_init_media_streams (call);
linphone_call_init_media_streams(call);
}
if (call->audiostream==NULL){
/*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/
linphone_call_init_media_streams (call);
if (call->audiostream == NULL) {
/* This happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them */
linphone_call_init_media_streams(call);
}
if (call->params->real_early_media && call->state==LinphoneCallOutgoingEarlyMedia){
if (call->params->real_early_media && (call->state == LinphoneCallOutgoingEarlyMedia)) {
prepare_early_media_forking(call);
}
linphone_call_start_media_streams(call, target_state);
if (call->state==LinphoneCallPausing && call->paused_by_app && bctbx_list_size(lc->calls)==1){
linphone_core_play_named_tone(lc,LinphoneToneCallOnHold);
if ((call->state == LinphoneCallPausing) && call->paused_by_app && (bctbx_list_size(lc->calls) == 1)) {
linphone_core_play_named_tone(lc, LinphoneToneCallOnHold);
}
linphone_call_update_frozen_payloads(call, new_md);
end:
if (oldmd)
sal_media_description_unref(oldmd);
end:
if (oldmd) sal_media_description_unref(oldmd);
}
#if 0
static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){
bctbx_list_t *elem;
@ -476,7 +477,7 @@ static void call_ringing(SalOp *h){
linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
linphone_core_stop_ringing(lc);
ms_message("Doing early media...");
linphone_core_update_streams(lc,call,md, call->state);
linphone_call_update_streams(call, md, call->state);
if ((linphone_call_params_get_audio_direction(linphone_call_get_current_params(call)) == LinphoneMediaDirectionInactive) && call->audiostream) {
if (lc->ringstream != NULL) return; /* Already ringing! */
start_remote_ring(lc, call);
@ -523,7 +524,7 @@ static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *o
#ifdef BUILD_UPNP
if (call->upnp_session != NULL && rmd) {
linphone_core_update_upnp_from_remote_media_description(call, rmd);
linphone_call_update_upnp_from_remote_media_description(call, rmd);
}
#endif //BUILD_UPNP
@ -582,8 +583,8 @@ static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *o
if (next_state != LinphoneCallIdle){
linphone_call_update_remote_session_id_and_ver(call);
linphone_core_update_ice_state_in_call_stats(call);
linphone_core_update_streams(lc, call, md, next_state);
linphone_call_update_ice_state_in_call_stats(call);
linphone_call_update_streams(call, md, next_state);
linphone_call_fix_call_parameters(call, rmd);
linphone_call_set_state(call, next_state, next_state_str);
}else{
@ -599,7 +600,7 @@ static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *o
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
ms_error("Incompatible SDP answer received, need to abort the call");
linphone_core_abort_call(lc,call,_("Incompatible, check codecs or security settings..."));
linphone_call_abort(call, _("Incompatible, check codecs or security settings..."));
break;
/*otherwise we are able to resume previous state*/
default:
@ -641,7 +642,7 @@ static void call_accepted(SalOp *op){
static void call_resumed(LinphoneCore *lc, LinphoneCall *call){
linphone_core_notify_display_status(lc,_("We have been resumed."));
_linphone_core_accept_call_update(lc,call,NULL,LinphoneCallStreamsRunning,"Connected (streams running)");
_linphone_call_accept_update(call,NULL,LinphoneCallStreamsRunning,"Connected (streams running)");
}
static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
@ -653,7 +654,7 @@ static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
if (lp_config_get_int(lc->config, "sip", "inactive_video_on_pause", 0)) {
linphone_call_params_set_video_direction(params, LinphoneMediaDirectionInactive);
}
_linphone_core_accept_call_update(lc,call,params,LinphoneCallPausedByRemote,"Call paused by remote");
_linphone_call_accept_update(call,params,LinphoneCallPausedByRemote,"Call paused by remote");
linphone_call_params_unref(params);
}
@ -695,7 +696,7 @@ static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t
case LinphoneCallIncomingEarlyMedia:
if (is_update) {
linphone_call_set_state(call, LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote");
_linphone_core_accept_call_update(lc,call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate));
_linphone_call_accept_update(call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate));
}
break;
case LinphoneCallStreamsRunning:
@ -709,7 +710,7 @@ static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t
break;
case LinphoneCallPaused:
/*we'll remain in pause state but accept the offer anyway according to default parameters*/
_linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state));
_linphone_call_accept_update(call,NULL,call->state,linphone_call_state_to_string(call->state));
break;
case LinphoneCallUpdating:
case LinphoneCallPausing:
@ -908,7 +909,7 @@ static void call_failure(SalOp *op){
linphone_address_unref(call->log->to);
}
call->log->to = linphone_address_ref(redirection_to);
linphone_core_restart_invite(lc, call);
linphone_call_restart_invite(call);
return;
}
}
@ -941,19 +942,19 @@ static void call_failure(SalOp *op){
if (call->params->avpf_enabled == TRUE) {
if (i == 0) ms_message("Retrying call [%p] with SAVP", call);
call->params->avpf_enabled = FALSE;
linphone_core_restart_invite(lc, call);
linphone_call_restart_invite(call);
return;
} else if (!linphone_core_is_media_encryption_mandatory(lc)) {
if (i == 0) ms_message("Retrying call [%p] with AVP", call);
call->params->media_encryption = LinphoneMediaEncryptionNone;
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
linphone_core_restart_invite(lc, call);
linphone_call_restart_invite(call);
return;
}
} else if (call->params->avpf_enabled == TRUE) {
if (i == 0) ms_message("Retrying call [%p] with AVP", call);
call->params->avpf_enabled = FALSE;
linphone_core_restart_invite(lc, call);
linphone_call_restart_invite(call);
return;
}
}
@ -1216,7 +1217,7 @@ static void ping_reply(SalOp *op){
if (call){
if (call->state==LinphoneCallOutgoingInit){
call->ping_replied=TRUE;
linphone_core_proceed_with_invite_if_ready(call->core,call,NULL);
linphone_call_proceed_with_invite_if_ready(call, NULL);
}
}
else

View file

@ -445,7 +445,7 @@ int LocalConference::removeFromConference(LinphoneCall *call, bool_t active){
linphone_call_params_unref(params);
} else{
ms_message("Pausing call to actually remove from conference");
err=_linphone_core_pause_call(m_core,call);
err=_linphone_call_pause(call);
}
return err;
}
@ -529,7 +529,7 @@ int LocalConference::enter() {
return -1;
}
if (m_core->current_call != NULL) {
_linphone_core_pause_call(m_core, m_core->current_call);
_linphone_call_pause(m_core->current_call);
}
if (m_localParticipantStream==NULL) addLocalEndpoint();
return 0;

View file

@ -630,12 +630,12 @@ void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall
/*set this to FALSE once flexisip are updated everywhere, let's say in December 2016.*/
bool_t use_nortpproxy = lp_config_get_int(lc->config, "sip", "ice_uses_nortpproxy", TRUE);
_update_local_media_description_from_ice(call->localdesc, call->ice_session, use_nortpproxy);
linphone_core_update_ice_state_in_call_stats(call);
linphone_call_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);
linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
linphone_call_update_upnp_state_in_call_stats(call);
}
#endif //BUILD_UPNP
}
@ -1504,7 +1504,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
if(!lc->rtp_conf.disable_upnp) {
call->upnp_session = linphone_upnp_session_new(call);
if (call->upnp_session != NULL) {
if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
if (linphone_call_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
}
@ -4365,7 +4365,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
default:
break;
}
linphone_core_update_ice_state_in_call_stats(call);
linphone_call_update_ice_state_in_call_stats(call);
} else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
if (evd->info.ice_processing_successful==FALSE) {
ms_warning("No STUN answer from [%s], continuing without STUN",linphone_core_get_stun_server(call->core));
@ -4373,14 +4373,14 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
linphone_call_on_ice_gathering_finished(call);
switch (call->state) {
case LinphoneCallUpdating:
linphone_core_start_update_call(call->core, call);
linphone_call_start_update(call);
break;
case LinphoneCallUpdatedByRemote:
linphone_core_start_accept_call_update(call->core, call,call->prevstate,linphone_call_state_to_string(call->prevstate));
linphone_call_start_accept_update(call, call->prevstate,linphone_call_state_to_string(call->prevstate));
break;
case LinphoneCallOutgoingInit:
linphone_call_stop_media_streams_for_ice_gathering(call);
linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
linphone_call_proceed_with_invite_if_ready(call, NULL);
break;
case LinphoneCallIdle:
linphone_call_stop_media_streams_for_ice_gathering(call);
@ -4393,8 +4393,8 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
}
} else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
if (call->state==LinphoneCallUpdatedByRemote){
linphone_core_start_accept_call_update(call->core, call,call->prevstate,linphone_call_state_to_string(call->prevstate));
linphone_core_update_ice_state_in_call_stats(call);
linphone_call_start_accept_update(call, call->prevstate, linphone_call_state_to_string(call->prevstate));
linphone_call_update_ice_state_in_call_stats(call);
}
} else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
ice_session_restart(call->ice_session, IR_Controlling);
@ -4917,6 +4917,734 @@ RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stre
return meta_rtcp;
}
int linphone_call_pause(LinphoneCall *call) {
int err = _linphone_call_pause(call);
if (err == 0) call->paused_by_app = TRUE;
return err;
}
/* Internal version that does not play tone indication*/
int _linphone_call_pause(LinphoneCall *call) {
LinphoneCore *lc;
const char *subject = NULL;
if ((call->state != LinphoneCallStreamsRunning) && (call->state != LinphoneCallPausedByRemote)) {
ms_warning("Cannot pause this call, it is not active.");
return -1;
}
if (sal_media_description_has_dir(call->resultdesc, SalStreamSendRecv)) {
subject = "Call on hold";
} else if (sal_media_description_has_dir(call->resultdesc, SalStreamRecvOnly)) {
subject = "Call on hold for me too";
} else {
ms_error("No reason to pause this call, it is already paused or inactive.");
return -1;
}
lc = linphone_call_get_core(call);
call->broken = FALSE;
linphone_call_set_state(call, LinphoneCallPausing, "Pausing call");
linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if (call->upnp_session != NULL) {
linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
}
#endif // BUILD_UPNP
sal_call_set_local_media_description(call->op, call->localdesc);
if (sal_call_update(call->op, subject, FALSE) != 0) {
linphone_core_notify_display_warning(lc, _("Could not pause the call"));
}
lc->current_call = NULL;
linphone_core_notify_display_status(lc, _("Pausing the current call..."));
if (call->audiostream || call->videostream || call->textstream)
linphone_call_stop_media_streams(call);
call->paused_by_app = FALSE;
return 0;
}
int linphone_call_resume(LinphoneCall *call) {
LinphoneCore *lc;
const char *subject = "Call resuming";
char *remote_address;
char *display_status;
if (call->state != LinphoneCallPaused) {
ms_warning("we cannot resume a call that has not been established and paused before");
return -1;
}
lc = linphone_call_get_core(call);
if (call->params->in_conference == FALSE) {
if (linphone_core_sound_resources_locked(lc)) {
ms_warning("Cannot resume call %p because another call is locking the sound resources.", call);
return -1;
}
linphone_core_preempt_sound_resources(lc);
ms_message("Resuming call %p", call);
}
call->was_automatically_paused = FALSE;
call->broken = FALSE;
/* Stop playing music immediately. If remote side is a conference it
prevents the participants to hear it while the 200OK comes back. */
if (call->audiostream) audio_stream_play(call->audiostream, NULL);
linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if (call->upnp_session != NULL) {
linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
}
#endif // BUILD_UPNP
if (!lc->sip_conf.sdp_200_ack) {
sal_call_set_local_media_description(call->op, call->localdesc);
} else {
sal_call_set_local_media_description(call->op, NULL);
}
sal_media_description_set_dir(call->localdesc, SalStreamSendRecv);
if (call->params->in_conference && !call->current_params->in_conference) subject = "Conference";
if (sal_call_update(call->op, subject, FALSE) != 0) {
return -1;
}
linphone_call_set_state(call, LinphoneCallResuming,"Resuming");
if (call->params->in_conference == FALSE)
lc->current_call = call;
remote_address = linphone_call_get_remote_address_as_string(call);
display_status = ms_strdup_printf("Resuming the call with with %s", remote_address);
ms_free(remote_address);
linphone_core_notify_display_status(lc, display_status);
ms_free(display_status);
if (lc->sip_conf.sdp_200_ack) {
/* We are NOT offering, set local media description after sending the call so that we are ready to
process the remote offer when it will arrive. */
sal_call_set_local_media_description(call->op, call->localdesc);
}
return 0;
}
static void terminate_call(LinphoneCall *call) {
LinphoneCore *lc = linphone_call_get_core(call);
if ((call->state == LinphoneCallIncomingReceived) && (call->non_op_error.reason != SalReasonRequestTimeout))
call->non_op_error.reason=SalReasonDeclined;
/* Stop ringing */
linphone_core_stop_ringing(lc);
linphone_call_stop_media_streams(call);
#ifdef BUILD_UPNP
linphone_call_delete_upnp_session(call);
#endif // BUILD_UPNP
linphone_core_notify_display_status(lc, _("Call ended") );
linphone_call_set_state(call, LinphoneCallEnd, "Call terminated");
}
int linphone_call_terminate(LinphoneCall *call) {
ms_message("Terminate call [%p] which is currently in state %s", call, linphone_call_state_to_string(call->state));
switch (call->state) {
case LinphoneCallReleased:
case LinphoneCallEnd:
case LinphoneCallError:
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_call_decline(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;
}
terminate_call(call);
return 0;
}
int linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) {
char *real_url = NULL;
LinphoneCore *lc;
LinphoneAddress *real_parsed_url;
if (call->state != LinphoneCallIncomingReceived) {
ms_error("Bad state for call redirection.");
return -1;
}
lc = linphone_call_get_core(call);
real_parsed_url = linphone_core_interpret_url(lc, redirect_uri);
if (!real_parsed_url) {
/* Bad url */
ms_error("Bad redirect URI: %s", redirect_uri ? redirect_uri : "NULL");
return -1;
}
real_url = linphone_address_as_string(real_parsed_url);
sal_call_decline(call->op, SalReasonRedirect, real_url);
ms_free(real_url);
sal_error_info_set(&call->non_op_error, SalReasonRedirect, 603, "Call redirected", NULL);
terminate_call(call);
linphone_address_unref(real_parsed_url);
return 0;
}
int linphone_call_decline(LinphoneCall * call, LinphoneReason reason) {
if ((call->state != LinphoneCallIncomingReceived) && (call->state != LinphoneCallIncomingEarlyMedia)) {
ms_error("Cannot decline a call that is in state %s", linphone_call_state_to_string(call->state));
return -1;
}
sal_call_decline(call->op, linphone_reason_to_sal(reason), NULL);
terminate_call(call);
return 0;
}
int linphone_call_accept(LinphoneCall *call) {
return linphone_call_accept_with_params(call, NULL);
}
int linphone_call_accept_with_params(LinphoneCall *call, const LinphoneCallParams *params) {
LinphoneCore *lc;
SalOp *replaced;
SalMediaDescription *new_md;
bool_t was_ringing = FALSE;
bctbx_list_t *iterator, *copy;
switch (call->state) {
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
break;
default:
ms_error("linphone_core_accept_call_with_params() call [%p] is in state [%s], operation not permitted.",
call, linphone_call_state_to_string(call->state));
return -1;
}
lc = linphone_call_get_core(call);
for (iterator = copy = bctbx_list_copy(linphone_core_get_calls(lc)); iterator != NULL; iterator = bctbx_list_next(iterator)) {
LinphoneCall *a_call = (LinphoneCall *)bctbx_list_get_data(iterator);
if (a_call == call) continue;
switch (a_call->state) {
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
ms_message("Already existing call [%p] in state [%s], canceling it before accepting new call [%p]",
a_call, linphone_call_state_to_string(a_call->state), call);
linphone_call_terminate(a_call);
break;
default:
break; /* Nothing to do */
}
}
bctbx_list_free(copy);
/* Check if this call is supposed to replace an already running one */
replaced = sal_call_get_replaces(call->op);
if (replaced) {
LinphoneCall *rc = (LinphoneCall *)sal_op_get_user_pointer(replaced);
if (rc) {
ms_message("Call %p replaces call %p. This last one is going to be terminated automatically.", call, rc);
linphone_call_terminate(rc);
}
}
if (lc->current_call != call) {
linphone_core_preempt_sound_resources(lc);
}
/* Stop ringing */
if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)) {
ms_message("Stop ringing");
linphone_core_stop_ringing(lc);
was_ringing = TRUE;
}
if (call->ringing_beep) {
linphone_core_stop_dtmf(lc);
call->ringing_beep = FALSE;
}
/* Try to be best-effort in giving real local or routable contact address */
linphone_call_set_contact_op(call);
if (params) {
linphone_call_set_new_params(call, params);
linphone_call_prepare_ice(call, TRUE);
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op, call->localdesc);
sal_op_set_sent_custom_header(call->op, params->custom_headers);
}
/* Give a chance a set card prefered sampling frequency */
if (call->localdesc->streams[0].max_rate > 0) {
ms_message("Configuring prefered card sampling rate to [%i]", call->localdesc->streams[0].max_rate);
if (lc->sound_conf.play_sndcard)
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate);
if (lc->sound_conf.capt_sndcard)
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate);
}
if (!was_ringing && (call->audiostream->ms.state == MSStreamInitialized) && !lc->use_files) {
audio_stream_prepare_sound(call->audiostream, lc->sound_conf.play_sndcard, lc->sound_conf.capt_sndcard);
}
linphone_call_update_remote_session_id_and_ver(call);
sal_call_accept(call->op);
linphone_core_notify_display_status(lc, _("Connected."));
lc->current_call = call;
linphone_call_set_state(call, LinphoneCallConnected, "Connected");
new_md = sal_call_get_final_media_description(call->op);
linphone_call_stop_ice_for_inactive_streams(call, new_md);
if (new_md) {
linphone_call_update_streams(call, new_md, LinphoneCallStreamsRunning);
linphone_call_set_state(call, LinphoneCallStreamsRunning, "Connected (streams running)");
} else {
call->expect_media_in_ack = TRUE;
}
ms_message("Call answered");
return 0;
}
int linphone_call_accept_early_media(LinphoneCall* call) {
return linphone_call_accept_early_media_with_params(call, NULL);
}
int linphone_call_accept_early_media_with_params(LinphoneCall *call, const LinphoneCallParams *params) {
SalMediaDescription* md;
if (call->state != LinphoneCallIncomingReceived) {
ms_error("Bad state %s for linphone_core_accept_early_media_with_params()", linphone_call_state_to_string(call->state));
return -1;
}
/* Try to be best-effort in giving real local or routable contact address for 100Rel case */
linphone_call_set_contact_op(call);
/* If parameters are passed, update the media description */
if (params) {
linphone_call_set_new_params(call, params);
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op, call->localdesc);
sal_op_set_sent_custom_header(call->op, params->custom_headers);
}
sal_call_notify_ringing(call->op, TRUE);
linphone_call_set_state(call, LinphoneCallIncomingEarlyMedia, "Incoming call early media");
md = sal_call_get_final_media_description(call->op);
if (md) linphone_call_update_streams(call, md, call->state);
return 0;
}
int linphone_call_update(LinphoneCall *call, const LinphoneCallParams *params) {
int err = 0;
LinphoneCallState nextstate;
LinphoneCallState initial_state = call->state;
const LinphoneCallParams *current_params;
LinphoneCore *lc;
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
bool_t has_video = FALSE;
#endif
switch (initial_state) {
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
nextstate = LinphoneCallEarlyUpdating;
break;
case LinphoneCallStreamsRunning:
case LinphoneCallPausedByRemote:
case LinphoneCallUpdatedByRemote:
nextstate = LinphoneCallUpdating;
break;
case LinphoneCallPaused:
nextstate = LinphoneCallPausing;
break;
case LinphoneCallOutgoingProgress:
case LinphoneCallPausing:
case LinphoneCallResuming:
case LinphoneCallUpdating:
nextstate = initial_state;
break;
default:
ms_error("linphone_call_update() is not allowed in [%s] state", linphone_call_state_to_string(call->state));
return -1;
}
lc = linphone_call_get_core(call);
current_params = linphone_call_get_current_params(call);
if ((current_params != NULL) && (current_params == params)) {
ms_warning("linphone_call_update() is given the current params of the call, this probably not what you intend to do!");
}
linphone_call_check_ice_session(call, IR_Controlling, TRUE);
if (params != NULL) {
call->broken = FALSE;
linphone_call_set_state(call, nextstate, "Updating call");
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
has_video = call->params->has_video;
/* Video removal */
if ((call->videostream != NULL) && !params->has_video) {
if (call->upnp_session != NULL) {
if (linphone_call_update_upnp(call) < 0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
}
}
}
#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */
linphone_call_set_new_params(call, params);
err = linphone_call_prepare_ice(call, FALSE);
if (err == 1) {
ms_message("Defer call update to gather ICE candidates");
return 0;
}
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
/* Video adding */
if (!has_video && call->params->has_video) {
if(call->upnp_session != NULL) {
ms_message("Defer call update to add uPnP port mappings");
video_stream_prepare_video(call->videostream);
if (linphone_call_update_upnp(call) < 0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
} else {
return err;
}
}
}
#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */
if ((err = linphone_call_start_update(call)) && (call->state != initial_state)) {
/* Restore initial state */
linphone_call_set_state(call, initial_state, "Restore initial state");
}
} else {
#ifdef VIDEO_ENABLED
if ((call->videostream != NULL) && (call->state == LinphoneCallStreamsRunning)) {
video_stream_set_sent_video_size(call->videostream, linphone_core_get_preferred_video_size(lc));
video_stream_set_fps(call->videostream, linphone_core_get_preferred_framerate(lc));
if (call->camera_enabled && (call->videostream->cam != lc->video_conf.device)) {
video_stream_change_camera(call->videostream, lc->video_conf.device);
} else {
video_stream_update_video_params(call->videostream);
}
}
#endif
}
return err;
}
int linphone_call_start_update(LinphoneCall *call) {
const char *subject;
int err;
bool_t no_user_consent = call->params->no_user_consent;
LinphoneCore *lc = linphone_call_get_core(call);
linphone_call_fill_media_multicast_addr(call);
if (!no_user_consent) linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if (call->upnp_session != NULL) {
linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
}
#endif // BUILD_UPNP
if (call->params->in_conference) {
subject = "Conference";
} else if (call->params->internal_call_update) {
subject = "ICE processing concluded";
} else if (no_user_consent) {
subject = "Refreshing";
} else {
subject = "Media change";
}
linphone_core_notify_display_status(lc, _("Modifying call parameters..."));
if (!lc->sip_conf.sdp_200_ack) {
sal_call_set_local_media_description(call->op, call->localdesc);
} else {
sal_call_set_local_media_description(call->op, NULL);
}
if (call->dest_proxy && call->dest_proxy->op) {
/* Give a chance to update the contact address if connectivity has changed */
sal_op_set_contact_address(call->op, sal_op_get_contact_address(call->dest_proxy->op));
} else {
sal_op_set_contact_address(call->op, NULL);
}
err = sal_call_update(call->op, subject, no_user_consent);
if (lc->sip_conf.sdp_200_ack) {
/* We are NOT offering, set local media description after sending the call so that we are ready to
process the remote offer when it will arrive. */
sal_call_set_local_media_description(call->op, call->localdesc);
}
return err;
}
int linphone_call_defer_update(LinphoneCall *call) {
if (call->state != LinphoneCallUpdatedByRemote) {
ms_error("linphone_call_defer_update() not done in state LinphoneCallUpdatedByRemote");
return -1;
}
if (call->expect_media_in_ack) {
ms_error("linphone_call_defer_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)");
return -1;
}
call->defer_update=TRUE;
return 0;
}
int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next_state, const char *state_info) {
SalMediaDescription *md;
if ((call->ice_session != NULL) && (ice_session_nb_losing_pairs(call->ice_session) > 0)) {
/* Defer the sending of the answer until there are no losing pairs left */
return 0;
}
linphone_call_make_local_media_description(call);
linphone_call_update_remote_session_id_and_ver(call);
sal_call_set_local_media_description(call->op, call->localdesc);
sal_call_accept(call->op);
md = sal_call_get_final_media_description(call->op);
linphone_call_stop_ice_for_inactive_streams(call, md);
if (md && !sal_media_description_empty(md)) {
linphone_call_update_streams(call, md, next_state);
}
linphone_call_set_state(call, next_state, state_info);
return 0;
}
int _linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info) {
SalMediaDescription *remote_desc;
bool_t keep_sdp_version;
LinphoneCore *lc = linphone_call_get_core(call);
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
bool_t old_has_video = call->params->has_video;
#endif
remote_desc = sal_call_get_remote_media_description(call->op);
keep_sdp_version = lp_config_get_int(lc->config, "sip", "keep_sdp_version", 0);
if (keep_sdp_version && (remote_desc->session_id == call->remote_session_id) && (remote_desc->session_ver == call->remote_session_ver)) {
/* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */
ms_warning("SDP version has not changed, send same SDP as before.");
sal_call_accept(call->op);
linphone_call_set_state(call, next_state, state_info);
return 0;
}
if (params == NULL) {
if (!sal_call_is_offerer(call->op)) {
/* Reset call param for multicast because this param is only relevant when offering */
linphone_call_params_enable_audio_multicast(call->params, FALSE);
linphone_call_params_enable_video_multicast(call->params, FALSE);
}
} else {
linphone_call_set_new_params(call, params);
}
if (call->params->has_video && !linphone_core_video_enabled(lc)) {
ms_warning("Requested video but video support is globally disabled. Refusing video.");
call->params->has_video = FALSE;
}
if (call->current_params->in_conference) {
ms_warning("Video isn't supported in conference");
call->params->has_video = FALSE;
}
/* Update multicast params according to call params */
linphone_call_fill_media_multicast_addr(call);
linphone_call_check_ice_session(call, IR_Controlled, TRUE);
linphone_call_init_media_streams(call); /* So that video stream is initialized if necessary */
if (linphone_call_prepare_ice(call, TRUE) == 1) {
return 0; /* Deferred until completion of ICE gathering */
}
#ifdef BUILD_UPNP
if (call->upnp_session != NULL) {
linphone_call_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op));
#ifdef VIDEO_ENABLED
if ((call->params->has_video) && (call->params->has_video != old_has_video)) {
video_stream_prepare_video(call->videostream);
if (linphone_call_update_upnp(call) < 0) {
/* uPnP update failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
} else return 0;
}
#endif // VIDEO_ENABLED
}
#endif // BUILD_UPNP
linphone_call_start_accept_update(call, next_state, state_info);
return 0;
}
int linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params) {
if (call->state != LinphoneCallUpdatedByRemote) {
ms_error("linphone_call_accept_update(): invalid state %s to call this function.", linphone_call_state_to_string(call->state));
return -1;
}
if (call->expect_media_in_ack) {
ms_error("linphone_call_accept_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)");
return -1;
}
return _linphone_call_accept_update(call, params, call->prevstate, linphone_call_state_to_string(call->prevstate));
}
int linphone_call_transfer(LinphoneCall *call, const char *refer_to) {
char *real_url = NULL;
LinphoneCore *lc = linphone_call_get_core(call);
LinphoneAddress *real_parsed_url = linphone_core_interpret_url(lc, refer_to);
if (!real_parsed_url) {
/* bad url */
return -1;
}
//lc->call = NULL; // Do not do that you will lose the call afterward...
real_url = linphone_address_as_string(real_parsed_url);
sal_call_refer(call->op, real_url);
ms_free(real_url);
linphone_address_unref(real_parsed_url);
linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit);
return 0;
}
int linphone_call_transfer_to_another(LinphoneCall *call, LinphoneCall *dest) {
int result = sal_call_refer_with_replaces (call->op, dest->op);
linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit);
return result;
}
int linphone_call_abort(LinphoneCall *call, const char *error) {
LinphoneCore *lc = linphone_call_get_core(call);
sal_call_terminate(call->op);
/* Stop ringing */
linphone_core_stop_ringing(lc);
linphone_call_stop_media_streams(call);
#ifdef BUILD_UPNP
linphone_call_delete_upnp_session(call);
#endif // BUILD_UPNP
linphone_core_notify_display_status(lc, _("Call aborted"));
linphone_call_set_state(call, LinphoneCallError, error);
return 0;
}
int linphone_call_proceed_with_invite_if_ready(LinphoneCall *call, LinphoneProxyConfig *dest_proxy) {
bool_t ice_ready = FALSE;
bool_t upnp_ready = FALSE;
bool_t ping_ready = FALSE;
if (call->ice_session != NULL) {
if (ice_session_candidates_gathered(call->ice_session)) ice_ready = TRUE;
} else {
ice_ready = TRUE;
}
#ifdef BUILD_UPNP
if (call->upnp_session != NULL) {
if (linphone_upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE;
} else {
upnp_ready = TRUE;
}
#else
upnp_ready=TRUE;
#endif // BUILD_UPNP
if (call->ping_op != NULL) {
if (call->ping_replied == TRUE) ping_ready = TRUE;
} else {
ping_ready = TRUE;
}
if ((ice_ready == TRUE) && (upnp_ready == TRUE) && (ping_ready == TRUE)) {
return linphone_call_start_invite(call, NULL);
}
return 0;
}
int linphone_call_start_invite(LinphoneCall *call, const LinphoneAddress *destination /* = NULL if to be taken from the call log */) {
int err;
char *real_url, *barmsg;
char *from;
LinphoneCore *lc = linphone_call_get_core(call);
/* Try to be best-effort in giving real local or routable contact address */
linphone_call_set_contact_op(call);
linphone_core_stop_dtmf_stream(lc);
linphone_call_make_local_media_description(call);
if (lc->ringstream == NULL) {
if (lc->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard) {
/* Give a chance a set card prefered sampling frequency */
if (call->localdesc->streams[0].max_rate > 0) {
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate);
}
if (!lc->use_files) {
audio_stream_prepare_sound(call->audiostream, lc->sound_conf.play_sndcard, lc->sound_conf.capt_sndcard);
}
}
}
real_url = linphone_address_as_string(destination ? destination : call->log->to);
from = linphone_address_as_string(call->log->from);
if (!lc->sip_conf.sdp_200_ack) {
/* We are offering, set local media description before sending the call */
sal_call_set_local_media_description(call->op, call->localdesc);
}
barmsg = ms_strdup_printf("%s %s", _("Contacting"), real_url);
linphone_core_notify_display_status(lc, barmsg);
ms_free(barmsg);
linphone_call_ref(call); /* Take a ref because sal_call() may destroy the call if no SIP transport is available */
err = sal_call(call->op, from, real_url);
if (err < 0) {
if ((call->state != LinphoneCallError) && (call->state != LinphoneCallReleased)) {
/* sal_call() may invoke call_failure() and call_released() SAL callbacks synchronously,
in which case there is no need to perform a state change here. */
linphone_core_notify_display_status(lc, _("Could not call"));
linphone_call_stop_media_streams(call);
linphone_call_set_state(call, LinphoneCallError, "Call failed");
}
goto end;
}
if (lc->sip_conf.sdp_200_ack) {
/* We are NOT offering, set local media description after sending the call so that we are ready to
process the remote offer when it will arrive. */
sal_call_set_local_media_description(call->op, call->localdesc);
}
call->log->call_id = ms_strdup(sal_op_get_call_id(call->op)); /* Must be known at that time */
linphone_call_set_state(call, LinphoneCallOutgoingProgress, "Outgoing call in progress");
end:
linphone_call_unref(call); /* Revert the ref taken before calling sal_call() */
ms_free(real_url);
ms_free(from);
return err;
}
int linphone_call_restart_invite(LinphoneCall *call) {
linphone_call_create_op(call);
linphone_call_stop_media_streams(call);
ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]);
ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]);
ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]);
linphone_call_init_media_streams(call);
return linphone_call_start_invite(call, NULL);
}
void linphone_call_set_broken(LinphoneCall *call){
switch(call->state){
/*for all the early states, we prefer to drop the call*/
@ -4954,7 +5682,7 @@ static void linphone_call_repair_by_invite_with_replaces(LinphoneCall *call) {
sal_op_kill_dialog(call->op);
linphone_call_create_op(call);
sal_call_set_replaces(call->op, call_id, from_tag, to_tag);
linphone_core_start_invite(call->core, call, NULL);
linphone_call_start_invite(call, NULL);
}
void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call) {

View file

@ -2806,7 +2806,7 @@ void linphone_core_iterate(LinphoneCore *lc){
elapsed = (int)(current_real_time - call->log->start_date_time);
/* 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() */
linphone_call_start_invite() */
calls=calls->next;
linphone_call_background_tasks(call,one_second_elapsed);
if (call->state==LinphoneCallOutgoingInit && (elapsed>=lc->sip_conf.delayed_timeout)){
@ -2823,7 +2823,7 @@ void linphone_core_iterate(LinphoneCore *lc){
linphone_call_delete_upnp_session(call);
}
#endif //BUILD_UPNP
linphone_core_start_invite(lc,call, NULL);
linphone_call_start_invite(call, NULL);
}
if (call->state==LinphoneCallIncomingReceived || call->state==LinphoneCallIncomingEarlyMedia){
if (one_second_elapsed) ms_message("incoming call ringing for %i seconds",elapsed);
@ -2920,7 +2920,7 @@ LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *
if (call->state!=LinphoneCallPaused){
ms_message("Automatically pausing current call to accept transfer.");
_linphone_core_pause_call(lc,call);
_linphone_call_pause(call);
call->was_automatically_paused=TRUE;
}
@ -3038,109 +3038,6 @@ const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAdd
return linphone_core_get_primary_contact(lc);
}
int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){
bool_t ice_ready = FALSE;
bool_t upnp_ready = FALSE;
bool_t ping_ready = FALSE;
if (call->ice_session != NULL) {
if (ice_session_candidates_gathered(call->ice_session)) ice_ready = TRUE;
} else {
ice_ready = TRUE;
}
#ifdef BUILD_UPNP
if (call->upnp_session != NULL) {
if (linphone_upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE;
} else {
upnp_ready = TRUE;
}
#else
upnp_ready=TRUE;
#endif //BUILD_UPNP
if (call->ping_op != NULL) {
if (call->ping_replied == TRUE) ping_ready = TRUE;
} else {
ping_ready = TRUE;
}
if ((ice_ready == TRUE) && (upnp_ready == TRUE) && (ping_ready == TRUE)) {
return linphone_core_start_invite(lc, call, NULL);
}
return 0;
}
int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call){
linphone_call_create_op(call);
linphone_call_stop_media_streams(call);
ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]);
ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]);
ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]);
linphone_call_init_media_streams(call);
return linphone_core_start_invite(lc,call, NULL);
}
int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const LinphoneAddress* destination /* = NULL if to be taken from the call log */){
int err;
char *real_url,*barmsg;
char *from;
/*try to be best-effort in giving real local or routable contact address */
linphone_call_set_contact_op(call);
linphone_core_stop_dtmf_stream(lc);
linphone_call_make_local_media_description(call);
if (lc->ringstream==NULL) {
if (lc->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard){
/*give a chance a set card prefered sampling frequency*/
if (call->localdesc->streams[0].max_rate>0) {
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate);
}
if (!lc->use_files)
audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
}
}
real_url=linphone_address_as_string( destination ? destination : call->log->to);
from=linphone_address_as_string(call->log->from);
if (!lc->sip_conf.sdp_200_ack){
/*we are offering, set local media description before sending the call*/
sal_call_set_local_media_description(call->op,call->localdesc);
}
barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url);
linphone_core_notify_display_status(lc,barmsg);
ms_free(barmsg);
linphone_call_ref(call); /* Take a ref because sal_call() may destroy the call if no SIP transport is available */
err=sal_call(call->op,from,real_url);
if (err < 0){
if (call->state != LinphoneCallError &&
call->state != LinphoneCallReleased){
/*sal_call() may invoke call_failure() and call_released() SAL callbacks synchronously,
* in which case there is no need to perform a state change here.*/
linphone_core_notify_display_status(lc,_("Could not call"));
linphone_call_stop_media_streams(call);
linphone_call_set_state(call,LinphoneCallError,"Call failed");
}
goto end;
}
if (lc->sip_conf.sdp_200_ack){
/*we are NOT offering, set local media description after sending the call so that we are ready to
process the remote offer when it will arrive*/
sal_call_set_local_media_description(call->op,call->localdesc);
}
call->log->call_id=ms_strdup(sal_op_get_call_id(call->op)); /*must be known at that time*/
linphone_call_set_state(call,LinphoneCallOutgoingProgress,"Outgoing call in progress");
end:
linphone_call_unref(call); /* Revert the ref taken before calling sal_call() */
ms_free(real_url);
ms_free(from);
return err;
}
LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){
LinphoneCall *call;
LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL);
@ -3279,13 +3176,13 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
}
else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
#ifdef BUILD_UPNP
if (linphone_core_update_upnp(lc,call)<0) {
if (linphone_call_update_upnp(call) < 0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
} else {
defer = TRUE;
}
#endif //BUILD_UPNP
#endif // BUILD_UPNP
}
if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){
@ -3305,7 +3202,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
}
if (defer==FALSE) {
if (linphone_core_start_invite(lc,call,NULL) != 0){
if (linphone_call_start_invite(call,NULL) != 0){
/*the call has already gone to error and released state, so do not return it*/
call = NULL;
}
@ -3317,30 +3214,15 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
}
int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url) {
char *real_url=NULL;
LinphoneAddress *real_parsed_url=linphone_core_interpret_url(lc,url);
if (!real_parsed_url){
/* bad url */
return -1;
}
if (call==NULL){
if (call == NULL) {
ms_warning("No established call to refer.");
return -1;
}
//lc->call=NULL; //Do not do that you will lose the call afterward . . .
real_url=linphone_address_as_string (real_parsed_url);
sal_call_refer(call->op,real_url);
ms_free(real_url);
linphone_address_unref(real_parsed_url);
linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit);
return 0;
return linphone_call_transfer(call, url);
}
int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){
int result = sal_call_refer_with_replaces (call->op,dest->op);
linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit);
return result;
int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest) {
return linphone_call_transfer_to_another(call, dest);
}
bool_t linphone_core_is_incoming_invite_pending(LinphoneCore*lc){
@ -3413,509 +3295,62 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
ms_free(tmp);
}
int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, const LinphoneCallParams* params) {
if (call->state==LinphoneCallIncomingReceived){
SalMediaDescription* md;
/*try to be best-effort in giving real local or routable contact address for 100Rel case*/
linphone_call_set_contact_op(call);
// if parameters are passed, update the media description
if ( params ) {
linphone_call_set_new_params(call,params);
linphone_call_make_local_media_description (call);
sal_call_set_local_media_description ( call->op,call->localdesc );
sal_op_set_sent_custom_header ( call->op,params->custom_headers );
}
sal_call_notify_ringing(call->op, TRUE);
linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media");
md=sal_call_get_final_media_description(call->op);
if (md) linphone_core_update_streams(lc, call, md, call->state);
return 0;
}else{
ms_error("Bad state %s for linphone_core_accept_early_media_with_params()", linphone_call_state_to_string(call->state));
}
return -1;
int linphone_core_accept_early_media_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
return linphone_call_accept_early_media_with_params(call, params);
}
int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call){
return linphone_core_accept_early_media_with_params(lc, call, NULL);
int linphone_core_accept_early_media(LinphoneCore *lc, LinphoneCall *call) {
return linphone_call_accept_early_media(call);
}
int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
const char *subject;
int err;
bool_t no_user_consent=call->params->no_user_consent;
linphone_call_fill_media_multicast_addr(call);
if (!no_user_consent) linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
}
#endif //BUILD_UPNP
if (call->params->in_conference){
subject="Conference";
}else if (call->params->internal_call_update){
subject="ICE processing concluded";
}else if (no_user_consent){
subject="Refreshing";
}else{
subject="Media change";
}
linphone_core_notify_display_status(lc,_("Modifying call parameters..."));
if (!lc->sip_conf.sdp_200_ack){
sal_call_set_local_media_description (call->op,call->localdesc);
} else {
sal_call_set_local_media_description (call->op,NULL);
}
if (call->dest_proxy && call->dest_proxy->op){
/*give a chance to update the contact address if connectivity has changed*/
sal_op_set_contact_address(call->op,sal_op_get_contact_address(call->dest_proxy->op));
}else sal_op_set_contact_address(call->op,NULL);
err= sal_call_update(call->op,subject,no_user_consent);
if (lc->sip_conf.sdp_200_ack){
/*we are NOT offering, set local media description after sending the call so that we are ready to
process the remote offer when it will arrive*/
sal_call_set_local_media_description(call->op,call->localdesc);
}
return err;
int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
return linphone_call_update(call, params);
}
int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
int err=0;
LinphoneCallState nextstate, initial_state;
const LinphoneCallParams *current_params;
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
bool_t has_video = FALSE;
#endif
switch(initial_state=call->state){
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
nextstate=LinphoneCallEarlyUpdating;
break;
case LinphoneCallStreamsRunning:
case LinphoneCallPausedByRemote:
case LinphoneCallUpdatedByRemote:
nextstate=LinphoneCallUpdating;
break;
case LinphoneCallPaused:
nextstate=LinphoneCallPausing;
break;
case LinphoneCallOutgoingProgress:
case LinphoneCallPausing:
case LinphoneCallResuming:
case LinphoneCallUpdating:
nextstate=call->state;
break;
default:
ms_error("linphone_core_update_call() is not allowed in [%s] state",linphone_call_state_to_string(call->state));
return -1;
}
current_params = linphone_call_get_current_params(call);
if ((current_params != NULL) && (current_params == params)) {
ms_warning("linphone_core_update_call() is given the current params of the call, this probably not what you intend to do!");
}
linphone_call_check_ice_session(call, IR_Controlling, TRUE);
if (params!=NULL){
call->broken = FALSE;
linphone_call_set_state(call,nextstate,"Updating call");
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
has_video = call->params->has_video;
// Video removing
if((call->videostream != NULL) && !params->has_video) {
if(call->upnp_session != NULL) {
if (linphone_core_update_upnp(lc, call)<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
}
}
}
#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */
linphone_call_set_new_params(call,params);
err=linphone_call_prepare_ice(call,FALSE);
if (err==1) {
ms_message("Defer call update to gather ICE candidates");
return 0;
}
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
// Video adding
if (!has_video && call->params->has_video) {
if(call->upnp_session != NULL) {
ms_message("Defer call update to add uPnP port mappings");
video_stream_prepare_video(call->videostream);
if (linphone_core_update_upnp(lc, call)<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
} else {
return err;
}
}
}
#endif //defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
if ((err = linphone_core_start_update_call(lc, call)) && call->state!=initial_state) {
/*Restore initial state*/
linphone_call_set_state(call,initial_state,"Restore initial state");
}
}else{
#ifdef VIDEO_ENABLED
if ((call->videostream != NULL) && (call->state == LinphoneCallStreamsRunning)) {
video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
video_stream_set_fps(call->videostream, linphone_core_get_preferred_framerate(lc));
if (call->camera_enabled && call->videostream->cam!=lc->video_conf.device){
video_stream_change_camera(call->videostream, lc->video_conf.device);
}else video_stream_update_video_params(call->videostream);
}
#endif
}
return err;
int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call) {
return linphone_call_defer_update(call);
}
int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call){
if (call->state==LinphoneCallUpdatedByRemote){
if (call->expect_media_in_ack){
ms_error("linphone_core_defer_call_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)");
return -1;
}
call->defer_update=TRUE;
return 0;
}else{
ms_error("linphone_core_defer_call_update() not done in state LinphoneCallUpdatedByRemote");
}
return -1;
int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
return linphone_call_accept_update(call, params);
}
int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState next_state, const char *state_info){
SalMediaDescription *md;
if (call->ice_session != NULL) {
if (ice_session_nb_losing_pairs(call->ice_session) > 0) {
/* Defer the sending of the answer until there are no losing pairs left. */
return 0;
}
static LinphoneCall * get_unique_call(LinphoneCore *lc) {
LinphoneCall *call = linphone_core_get_current_call(lc);
if ((call == NULL) && (linphone_core_get_calls_nb(lc) == 1)) {
call = (LinphoneCall *)bctbx_list_get_data(linphone_core_get_calls(lc));
}
linphone_call_make_local_media_description(call);
linphone_call_update_remote_session_id_and_ver(call);
sal_call_set_local_media_description(call->op,call->localdesc);
sal_call_accept(call->op);
md=sal_call_get_final_media_description(call->op);
linphone_call_stop_ice_for_inactive_streams(call, md);
if (md && !sal_media_description_empty(md)){
linphone_core_update_streams(lc, call, md, next_state);
}
linphone_call_set_state(call,next_state,state_info);
return 0;
return call;
}
int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
if (call->state != LinphoneCallUpdatedByRemote){
ms_error("linphone_core_accept_update(): invalid state %s to call this function.",
linphone_call_state_to_string(call->state));
return -1;
}
if (call->expect_media_in_ack){
ms_error("linphone_core_accept_call_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)");
return -1;
}
return _linphone_core_accept_call_update(lc, call, params, call->prevstate, linphone_call_state_to_string(call->prevstate));
int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) {
return linphone_core_accept_call_with_params(lc, call, NULL);
}
int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info){
SalMediaDescription *remote_desc;
bool_t keep_sdp_version;
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
bool_t old_has_video = call->params->has_video;
#endif
remote_desc = sal_call_get_remote_media_description(call->op);
keep_sdp_version = lp_config_get_int(lc->config, "sip", "keep_sdp_version", 0);
if (keep_sdp_version &&(remote_desc->session_id == call->remote_session_id) && (remote_desc->session_ver == call->remote_session_ver)) {
/* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */
ms_warning("SDP version has not changed, send same SDP as before.");
sal_call_accept(call->op);
linphone_call_set_state(call,next_state,state_info);
return 0;
}
if (params==NULL){
if (!sal_call_is_offerer(call->op)) {
/*reset call param for multicast because this param is only relevant when offering*/
linphone_call_params_enable_audio_multicast(call->params,FALSE);
linphone_call_params_enable_video_multicast(call->params,FALSE);
}
}else
linphone_call_set_new_params(call,params);
if (call->params->has_video && !linphone_core_video_enabled(lc)){
ms_warning("linphone_core_accept_call_update(): requested video but video support is globally disabled. Refusing video.");
call->params->has_video=FALSE;
}
if (call->current_params->in_conference) {
ms_warning("Video isn't supported in conference");
call->params->has_video = FALSE;
}
/*update multicast params according to call params*/
linphone_call_fill_media_multicast_addr(call);
linphone_call_check_ice_session(call, IR_Controlled, TRUE);
linphone_call_init_media_streams(call); /*so that video stream is initialized if necessary*/
if (linphone_call_prepare_ice(call,TRUE)==1)
return 0;/*deferred to completion of ICE gathering*/
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op));
#ifdef VIDEO_ENABLED
if ((call->params->has_video) && (call->params->has_video != old_has_video)) {
video_stream_prepare_video(call->videostream);
if (linphone_core_update_upnp(lc, call)<0) {
/* uPnP update failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
} else return 0;
}
#endif //VIDEO_ENABLED
}
#endif //BUILD_UPNP
linphone_core_start_accept_call_update(lc, call, next_state, state_info);
return 0;
}
int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call){
return linphone_core_accept_call_with_params(lc,call,NULL);
}
int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
SalOp *replaced;
SalMediaDescription *new_md;
bool_t was_ringing=FALSE;
bctbx_list_t * iterator, *copy;
if (call==NULL){
//if just one call is present answer the only one ...
if(linphone_core_get_calls_nb (lc) != 1)
return -1;
else
call = (LinphoneCall*)linphone_core_get_calls(lc)->data;
}
switch(call->state){
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
break;
default:
ms_error("linphone_core_accept_call_with_params() call [%p] is in state [%s], operation not permitted.",
call, linphone_call_state_to_string(call->state));
return -1;
break;
}
for (iterator=copy=bctbx_list_copy(linphone_core_get_calls(lc));iterator!=NULL;iterator=iterator->next) {
LinphoneCall *a_call=(LinphoneCall*)iterator->data;
if (a_call==call) continue;
switch(a_call->state){
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
ms_message("Already existing call [%p] in state [%s], canceling it before accepting new call [%p]",a_call
,linphone_call_state_to_string(a_call->state)
,call);
linphone_core_terminate_call(lc,a_call);
break;
default:
break; /*nothing to do*/
}
}
bctbx_list_free(copy);
/* check if this call is supposed to replace an already running one*/
replaced=sal_call_get_replaces(call->op);
if (replaced){
LinphoneCall *rc=(LinphoneCall*)sal_op_get_user_pointer (replaced);
if (rc){
ms_message("Call %p replaces call %p. This last one is going to be terminated automatically.",
call,rc);
linphone_core_terminate_call(lc,rc);
}
}
if (lc->current_call!=call){
linphone_core_preempt_sound_resources(lc);
}
/*stop ringing */
if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)) {
ms_message("stop ringing");
linphone_core_stop_ringing(lc);
was_ringing=TRUE;
}
if (call->ringing_beep){
linphone_core_stop_dtmf(lc);
call->ringing_beep=FALSE;
}
/*try to be best-effort in giving real local or routable contact address */
linphone_call_set_contact_op(call);
if (params){
linphone_call_set_new_params(call,params);
linphone_call_prepare_ice(call,TRUE);
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op,call->localdesc);
sal_op_set_sent_custom_header(call->op,params->custom_headers);
}
/*give a chance a set card prefered sampling frequency*/
if (call->localdesc->streams[0].max_rate>0) {
ms_message ("configuring prefered card sampling rate to [%i]",call->localdesc->streams[0].max_rate);
if (lc->sound_conf.play_sndcard)
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate);
if (lc->sound_conf.capt_sndcard)
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate);
}
if (!was_ringing && call->audiostream->ms.state==MSStreamInitialized && !lc->use_files){
audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
}
linphone_call_update_remote_session_id_and_ver(call);
sal_call_accept(call->op);
linphone_core_notify_display_status(lc,_("Connected."));
lc->current_call=call;
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
new_md=sal_call_get_final_media_description(call->op);
linphone_call_stop_ice_for_inactive_streams(call, new_md);
if (new_md){
linphone_core_update_streams(lc, call, new_md, LinphoneCallStreamsRunning);
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
}else call->expect_media_in_ack=TRUE;
ms_message("call answered.");
return 0;
}
int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error){
sal_call_terminate(call->op);
/*stop ringing*/
linphone_core_stop_ringing(lc);
linphone_call_stop_media_streams(call);
#ifdef BUILD_UPNP
linphone_call_delete_upnp_session(call);
#endif //BUILD_UPNP
linphone_core_notify_display_status(lc,_("Call aborted") );
linphone_call_set_state(call,LinphoneCallError,error);
return 0;
}
static void terminate_call(LinphoneCore *lc, LinphoneCall *call){
if (call->state==LinphoneCallIncomingReceived){
if (call->non_op_error.reason!=SalReasonRequestTimeout)
call->non_op_error.reason=SalReasonDeclined;
}
/*stop ringing*/
linphone_core_stop_ringing(lc);
linphone_call_stop_media_streams(call);
#ifdef BUILD_UPNP
linphone_call_delete_upnp_session(call);
#endif //BUILD_UPNP
linphone_core_notify_display_status(lc,_("Call ended") );
linphone_call_set_state(call,LinphoneCallEnd,"Call terminated");
}
int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri){
if (call->state==LinphoneCallIncomingReceived){
char *real_url=NULL;
LinphoneAddress *real_parsed_url=linphone_core_interpret_url(lc,redirect_uri);
if (!real_parsed_url){
/* bad url */
ms_error("Bad redirect URI: %s", redirect_uri?redirect_uri:"NULL");
return -1;
}
real_url=linphone_address_as_string (real_parsed_url);
sal_call_decline(call->op,SalReasonRedirect,real_url);
ms_free(real_url);
sal_error_info_set(&call->non_op_error,SalReasonRedirect,603,"Call redirected",NULL);
terminate_call(lc,call);
linphone_address_unref(real_parsed_url);
}else{
ms_error("Bad state for call redirection.");
return -1;
}
return 0;
}
int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) {
LinphoneCall *call;
if (the_call == NULL){
call = linphone_core_get_current_call(lc);
if (bctbx_list_size(lc->calls)==1){
call=(LinphoneCall*)lc->calls->data;
}else{
ms_warning("No unique call to terminate !");
int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
if (call == NULL) {
call = get_unique_call(lc);
if (call == NULL) {
ms_warning("No unique call to accept!");
return -1;
}
}
else
{
call = the_call;
}
ms_message("Terminate call [%p] which is currently in state %s", call, linphone_call_state_to_string(call->state));
switch (call->state) {
case LinphoneCallReleased:
case LinphoneCallEnd:
case LinphoneCallError:
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;
}
terminate_call(lc,call);
return 0;
return linphone_call_accept_with_params(call, params);
}
int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason){
if (call->state!=LinphoneCallIncomingReceived && call->state!=LinphoneCallIncomingEarlyMedia){
ms_error("linphone_core_decline_call(): Cannot decline a call that is in state %s",linphone_call_state_to_string(call->state));
return -1;
}
int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri) {
return linphone_call_redirect(call, redirect_uri);
}
sal_call_decline(call->op,linphone_reason_to_sal(reason),NULL);
terminate_call(lc,call);
return 0;
int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call) {
if (call == NULL) {
call = get_unique_call(lc);
if (call == NULL) {
ms_warning("No unique call to terminate!");
return -1;
}
}
return linphone_call_terminate(call);
}
int linphone_core_terminate_all_calls(LinphoneCore *lc){
@ -3928,6 +3363,10 @@ int linphone_core_terminate_all_calls(LinphoneCore *lc){
return 0;
}
int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall *call, LinphoneReason reason) {
return linphone_call_decline(call, reason);
}
const bctbx_list_t *linphone_core_get_calls(LinphoneCore *lc) {
return lc->calls;
}
@ -3940,46 +3379,8 @@ LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc){
return lc->current_call;
}
int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){
int err=_linphone_core_pause_call(lc,call);
if (err==0) call->paused_by_app=TRUE;
return err;
}
/* Internal version that does not play tone indication*/
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){
const char *subject=NULL;
if (call->state!=LinphoneCallStreamsRunning && call->state!=LinphoneCallPausedByRemote){
ms_warning("Cannot pause this call, it is not active.");
return -1;
}
if (sal_media_description_has_dir(call->resultdesc, SalStreamSendRecv)) {
subject = "Call on hold";
} else if (sal_media_description_has_dir(call->resultdesc, SalStreamRecvOnly)) {
subject = "Call on hold for me too";
} else {
ms_error("No reason to pause this call, it is already paused or inactive.");
return -1;
}
call->broken = FALSE;
linphone_call_set_state(call, LinphoneCallPausing, "Pausing call");
linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
}
#endif //BUILD_UPNP
sal_call_set_local_media_description(call->op,call->localdesc);
if (sal_call_update(call->op,subject,FALSE) != 0){
linphone_core_notify_display_warning(lc,_("Could not pause the call"));
}
lc->current_call=NULL;
linphone_core_notify_display_status(lc,_("Pausing the current call..."));
if (call->audiostream || call->videostream || call->textstream)
linphone_call_stop_media_streams (call);
call->paused_by_app=FALSE;
return 0;
int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) {
return linphone_call_pause(call);
}
int linphone_core_pause_all_calls(LinphoneCore *lc){
@ -3988,7 +3389,7 @@ int linphone_core_pause_all_calls(LinphoneCore *lc){
LinphoneCall *call=(LinphoneCall *)elem->data;
LinphoneCallState cs=linphone_call_get_state(call);
if (cs==LinphoneCallStreamsRunning || cs==LinphoneCallPausedByRemote){
_linphone_core_pause_call(lc,call);
_linphone_call_pause(call);
}
}
return 0;
@ -4006,7 +3407,7 @@ int linphone_core_preempt_sound_resources(LinphoneCore *lc){
current_call=linphone_core_get_current_call(lc);
if(current_call != NULL){
ms_message("Pausing automatically the current call.");
err = _linphone_core_pause_call(lc,current_call);
err = _linphone_call_pause(current_call);
}
if (lc->ringstream){
linphone_core_stop_ringing(lc);
@ -4014,60 +3415,8 @@ int linphone_core_preempt_sound_resources(LinphoneCore *lc){
return err;
}
int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){
char temp[255]={0};
const char *subject="Call resuming";
char *tmp;
if(call->state!=LinphoneCallPaused ){
ms_warning("we cannot resume a call that has not been established and paused before");
return -1;
}
if (call->params->in_conference==FALSE){
if (linphone_core_sound_resources_locked(lc)){
ms_warning("Cannot resume call %p because another call is locking the sound resources.",call);
return -1;
}
linphone_core_preempt_sound_resources(lc);
ms_message("Resuming call %p",call);
}
call->was_automatically_paused=FALSE;
call->broken = FALSE;
/* Stop playing music immediately. If remote side is a conference it
prevents the participants to hear it while the 200OK comes back.*/
if (call->audiostream) audio_stream_play(call->audiostream, NULL);
linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
}
#endif //BUILD_UPNP
if (!lc->sip_conf.sdp_200_ack){
sal_call_set_local_media_description(call->op,call->localdesc);
} else {
sal_call_set_local_media_description(call->op,NULL);
}
sal_media_description_set_dir(call->localdesc,SalStreamSendRecv);
if (call->params->in_conference && !call->current_params->in_conference) subject="Conference";
if ( sal_call_update(call->op,subject,FALSE) != 0){
return -1;
}
linphone_call_set_state(call,LinphoneCallResuming,"Resuming");
if (call->params->in_conference==FALSE)
lc->current_call=call;
snprintf(temp,sizeof(temp)-1,"Resuming the call with %s",(tmp = linphone_call_get_remote_address_as_string(call)));
ms_free(tmp);
linphone_core_notify_display_status(lc,temp);
if (lc->sip_conf.sdp_200_ack){
/*we are NOT offering, set local media description after sending the call so that we are ready to
process the remote offer when it will arrive*/
sal_call_set_local_media_description(call->op,call->localdesc);
}
return 0;
int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call) {
return linphone_call_resume(call);
}
static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *raddr){

View file

@ -69,8 +69,12 @@ bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const LinphonePayloa
return FALSE;
}
bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const LinphonePayloadType *pt){
if (pt->type==PAYLOAD_VIDEO) return TRUE;
bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const LinphonePayloadType *pt) {
return linphone_payload_type_is_vbr(pt);
}
bool_t linphone_payload_type_is_vbr(const LinphonePayloadType *pt) {
if (pt->type == PAYLOAD_VIDEO) return TRUE;
return !!(pt->flags & PAYLOAD_TYPE_IS_VBR);
}
@ -85,12 +89,20 @@ int linphone_core_enable_payload_type(LinphoneCore *lc, LinphonePayloadType *pt,
return -1;
}
int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt){
int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt) {
return linphone_payload_type_get_number(pt);
}
int linphone_payload_type_get_number(const PayloadType *pt) {
return payload_type_get_number(pt);
}
void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, int number){
payload_type_set_number(pt,number);
void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, int number) {
linphone_payload_type_set_number(pt, number);
}
void linphone_payload_type_set_number(PayloadType *pt, int number) {
payload_type_set_number(pt, number);
}
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
@ -772,8 +784,7 @@ const char *linphone_ice_state_to_string(LinphoneIceState state){
return "invalid";
}
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
{
void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call) {
IceCheckList *audio_check_list;
IceCheckList *video_check_list;
IceCheckList *text_check_list;
@ -891,7 +902,7 @@ void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call, SalMediaDes
}
}
linphone_core_update_ice_state_in_call_stats(call);
linphone_call_update_ice_state_in_call_stats(call);
}
void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session, bool_t use_nortpproxy) {

View file

@ -414,7 +414,7 @@ const LinphoneAuthInfo *_linphone_core_find_tls_auth_info(LinphoneCore *lc);
const LinphoneAuthInfo *_linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain, bool_t ignore_realm);
void linphone_core_update_proxy_register(LinphoneCore *lc);
int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error);
int linphone_call_abort(LinphoneCall *call, const char *error);
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphonePresenceModel *presence);
@ -532,7 +532,7 @@ void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, Linphone
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
LINPHONE_PUBLIC void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable);
LINPHONE_PUBLIC void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, bool_t enable);
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call);
void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call);
LINPHONE_PUBLIC void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev);
void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call, SalMediaDescription *result);
void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session, bool_t use_nortpproxy);
@ -579,14 +579,14 @@ void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose);
void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses);
void linphone_core_stop_waiting(LinphoneCore *lc);
int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const LinphoneAddress* destination/* = NULL if to be taken from the call log */);
int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call);
int linphone_call_proceed_with_invite_if_ready(LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
int linphone_call_start_invite(LinphoneCall *call, const LinphoneAddress *destination/* = NULL if to be taken from the call log */);
int linphone_call_restart_invite(LinphoneCall *call);
/*
* param automatic_offering aims is to take into account previous answer for video in case of automatic re-invite.
* Purpose is to avoid to re-ask video previously declined */
int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState next_state, const char *state_info);
int linphone_call_start_update(LinphoneCall *call);
int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next_state, const char *state_info);
void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call);
bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md);
extern SalCallbacks linphone_sal_callbacks;
@ -946,7 +946,7 @@ LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *l
void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason);
void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile);
LINPHONE_PUBLIC const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id);
int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info);
int _linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info);
typedef struct _LinphoneTaskList{
MSList *hooks;
@ -1148,7 +1148,7 @@ void linphone_call_make_local_media_description(LinphoneCall *call);
void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params);
void linphone_call_increment_local_media_description(LinphoneCall *call);
void linphone_call_fill_media_multicast_addr(LinphoneCall *call);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state);
void linphone_call_update_streams(LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state);
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit);
@ -1199,7 +1199,7 @@ void linphone_call_set_broken(LinphoneCall *call);
void linphone_call_repair_if_broken(LinphoneCall *call);
void linphone_core_repair_calls(LinphoneCore *lc);
int linphone_core_preempt_sound_resources(LinphoneCore *lc);
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
int _linphone_call_pause(LinphoneCall *call);
/*conferencing subsystem*/
void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted);

View file

@ -679,7 +679,7 @@ int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortB
* uPnP Core interfaces
*/
int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool_t video) {
int linphone_call_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool_t video) {
LinphoneCore *lc = call->core;
UpnpContext *lupnp = lc->upnp;
int ret = -1;
@ -725,7 +725,7 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) {
int linphone_call_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) {
bool_t audio = FALSE;
bool_t video = FALSE;
int i;
@ -741,14 +741,14 @@ int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call,
}
}
return linphone_core_update_upnp_audio_video(call, audio, video);
return linphone_call_update_upnp_audio_video(call, audio, video);
}
int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) {
return linphone_core_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL);
int linphone_call_update_upnp(LinphoneCall *call) {
return linphone_call_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL);
}
void linphone_core_update_upnp_state_in_call_stats(LinphoneCall *call) {
void linphone_call_update_upnp_state_in_call_stats(LinphoneCall *call) {
call->stats[LINPHONE_CALL_STATS_AUDIO].upnp_state = call->upnp_session->audio->state;
call->stats[LINPHONE_CALL_STATS_VIDEO].upnp_state = call->upnp_session->video->state;
}
@ -799,7 +799,7 @@ int linphone_upnp_call_process(LinphoneCall *call) {
/*
* Update stat
*/
linphone_core_update_upnp_state_in_call_stats(call);
linphone_call_update_upnp_state_in_call_stats(call);
/*
* Update session state
@ -832,13 +832,13 @@ int linphone_upnp_call_process(LinphoneCall *call) {
switch (call->state) {
case LinphoneCallUpdating:
linphone_core_start_update_call(lc, call);
linphone_call_start_update(call);
break;
case LinphoneCallUpdatedByRemote:
linphone_core_start_accept_call_update(lc, call,call->prevstate,linphone_call_state_to_string(call->prevstate));
linphone_call_start_accept_update(call, call->prevstate, linphone_call_state_to_string(call->prevstate));
break;
case LinphoneCallOutgoingInit:
linphone_core_proceed_with_invite_if_ready(lc, call, NULL);
linphone_call_proceed_with_invite_if_ready(call, NULL);
break;
case LinphoneCallIdle:
linphone_call_update_local_media_description_from_ice_or_upnp(call);
@ -1056,7 +1056,7 @@ bool_t linphone_core_upnp_hook(void *data) {
return TRUE;
}
int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session) {
int linphone_call_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session) {
int i;
SalStreamDescription *stream;
UpnpStream *upnpStream;

View file

@ -27,9 +27,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
typedef struct _UpnpSession UpnpSession;
typedef struct _UpnpContext UpnpContext;
int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session);
int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call);
int linphone_call_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session);
int linphone_call_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
int linphone_call_update_upnp(LinphoneCall *call);
int linphone_upnp_call_process(LinphoneCall *call);
UpnpSession* linphone_upnp_session_new(LinphoneCall *call);
@ -43,6 +43,6 @@ LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx);
const char *linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx);
int linphone_upnp_context_get_external_port(UpnpContext *ctx);
bool_t linphone_upnp_context_is_ready_for_register(UpnpContext *ctx);
void linphone_core_update_upnp_state_in_call_stats(LinphoneCall *call);
void linphone_call_update_upnp_state_in_call_stats(LinphoneCall *call);
#endif //LINPHONE_UPNP_H

View file

@ -352,6 +352,176 @@ LINPHONE_PUBLIC RtpTransport * linphone_call_get_meta_rtp_transport(LinphoneCall
**/
LINPHONE_PUBLIC RtpTransport * linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index);
/**
* Pauses the call. If a music file has been setup using linphone_core_set_play_file(),
* this file will be played to the remote user.
* The only way to resume a paused call is to call linphone_call_resume().
* @param[in] call LinphoneCall object
* @return 0 on success, -1 on failure
* @see linphone_call_resume()
**/
LINPHONE_PUBLIC int linphone_call_pause(LinphoneCall *call);
/**
* Resumes a call.
* The call needs to have been paused previously with linphone_call_pause().
* @param[in] call LinphoneCall object
* @return 0 on success, -1 on failure
* @see linphone_call_pause()
**/
LINPHONE_PUBLIC int linphone_call_resume(LinphoneCall *call);
/**
* Terminates a call.
* @param[in] call LinphoneCall object
* @return 0 on success, -1 on failure
**/
LINPHONE_PUBLIC int linphone_call_terminate(LinphoneCall *call);
/**
* Redirect the specified call to the given redirect URI.
* @param[in] call A LinphoneCall object
* @param[in] redirect_uri The URI to redirect the call to
* @return 0 if successful, -1 on error.
*/
LINPHONE_PUBLIC int linphone_call_redirect(LinphoneCall *call, const char *redirect_uri);
/**
* Decline a pending incoming call, with a reason.
* @param[in] call A LinphoneCall object that must be in the IncomingReceived state
* @param[in] reason The reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy
* @return 0 on success, -1 on failure
**/
LINPHONE_PUBLIC int linphone_call_decline(LinphoneCall * call, LinphoneReason reason);
/**
* Accept an incoming call.
*
* Basically the application is notified of incoming calls within the
* call_state_changed callback of the #LinphoneCoreVTable structure, where it will receive
* a LinphoneCallIncoming event with the associated LinphoneCall object.
* The application can later accept the call using this method.
* @param[in] call A LinphoneCall object
* @return 0 on success, -1 on failure
**/
LINPHONE_PUBLIC int linphone_call_accept(LinphoneCall *call);
/**
* Accept an incoming call, with parameters.
*
* Basically the application is notified of incoming calls within the
* call_state_changed callback of the #LinphoneCoreVTable structure, where it will receive
* a LinphoneCallIncoming event with the associated LinphoneCall object.
* The application can later accept the call using this method.
* @param[in] call A LinphoneCall object
* @param[in] params The specific parameters for this call, for example whether video is accepted or not. Use NULL to use default parameters
* @return 0 on success, -1 on failure
**/
LINPHONE_PUBLIC int linphone_call_accept_with_params(LinphoneCall *call, const LinphoneCallParams *params);
/**
* Accept an early media session for an incoming call.
* This is identical as calling linphone_call_accept_early_media_with_params() with NULL parameters.
* @param[in] call A LinphoneCall object
* @return 0 if successful, -1 otherwise
* @see linphone_call_accept_early_media_with_params()
**/
LINPHONE_PUBLIC int linphone_call_accept_early_media(LinphoneCall *call);
/**
* When receiving an incoming, accept to start a media session as early-media.
* This means the call is not accepted but audio & video streams can be established if the remote party supports early media.
* However, unlike after call acceptance, mic and camera input are not sent during early-media, though received audio & video are played normally.
* The call can then later be fully accepted using linphone_call_accept() or linphone_call_accept_with_params().
* @param[in] call A LinphoneCall object
* @param[in] params The call parameters to use (can be NULL)
* @return 0 if successful, -1 otherwise
**/
LINPHONE_PUBLIC int linphone_call_accept_early_media_with_params(LinphoneCall *call, const LinphoneCallParams *params);
/**
* Updates a running call according to supplied call parameters or parameters changed in the LinphoneCore.
* In this version this is limited to the following use cases:
* - setting up/down the video stream according to the video parameter of the LinphoneCallParams (see linphone_call_params_enable_video() ).
* - changing the size of the transmitted video after calling linphone_core_set_preferred_video_size()
* In case no changes are requested through the LinphoneCallParams argument, then this argument can be omitted and set to NULL.
* WARNING: Updating a call in the LinphoneCallPaused state will still result in a paused call even if the media directions set in the
* params are sendrecv. To resume a paused call, you need to call linphone_call_resume().
* @param[in] call A LinphoneCall update
* @param[in] params The new call parameters to use (may be NULL)
* @return 0 if successful, -1 otherwise.
**/
LINPHONE_PUBLIC int linphone_call_update(LinphoneCall *call, const LinphoneCallParams *params);
/**
* When receiving a #LinphoneCallUpdatedByRemote state notification, prevent LinphoneCore from performing an automatic answer.
*
* When receiving a #LinphoneCallUpdatedByRemote state notification (ie an incoming reINVITE), the default behaviour of
* LinphoneCore is defined by the "defer_update_default" option of the "sip" section of the config. If this option is 0 (the default)
* then the LinphoneCore automatically answers the reINIVTE with call parameters unchanged.
* However when for example when the remote party updated the call to propose a video stream, it can be useful
* to prompt the user before answering. This can be achieved by calling linphone_core_defer_call_update() during
* the call state notification, to deactivate the automatic answer that would just confirm the audio but reject the video.
* Then, when the user responds to dialog prompt, it becomes possible to call linphone_call_accept_update() to answer
* the reINVITE, with eventually video enabled in the LinphoneCallParams argument.
*
* The #LinphoneCallUpdatedByRemote notification can also arrive when receiving an INVITE without SDP. In such case, an unchanged offer is made
* in the 200Ok, and when the ACK containing the SDP answer is received, #LinphoneCallUpdatedByRemote is triggered to notify the application of possible
* changes in the media session. However in such case defering the update has no meaning since we just generating an offer.
*
* @param[in] call A LinphoneCall object
* @return 0 if successful, -1 if the linphone_call_defer_update() was done outside a valid #LinphoneCallUpdatedByRemote notification
**/
LINPHONE_PUBLIC int linphone_call_defer_update(LinphoneCall *call);
/**
* Accept call modifications initiated by other end.
*
* This call may be performed in response to a #LinphoneCallUpdatedByRemote state notification.
* When such notification arrives, the application can decide to call linphone_call_defer_update() so that it can
* have the time to prompt the user. linphone_call_get_remote_params() can be used to get information about the call parameters
* requested by the other party, such as whether a video stream is requested.
*
* When the user accepts or refuse the change, linphone_call_accept_update() can be done to answer to the other party.
* If params is NULL, then the same call parameters established before the update request will continue to be used (no change).
* If params is not NULL, then the update will be accepted according to the parameters passed.
* Typical example is when a user accepts to start video, then params should indicate that video stream should be used
* (see linphone_call_params_enable_video()).
* @param[in] call A LinphoneCall object
* @param[in] params A LinphoneCallParams object describing the call parameters to accept
* @return 0 if successful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state)
**/
LINPHONE_PUBLIC int linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params);
/**
* Performs a simple call transfer to the specified destination.
* 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 #LinphoneCallConnected.
* @param[in] call The call to be transfered
* @param[in] refer_to The destination the call is to be refered to
* @return 0 on success, -1 on failure
**/
LINPHONE_PUBLIC int linphone_call_transfer(LinphoneCall *call, const char *refer_to);
/**
* Transfers a call to destination of another running call. This is used for "attended transfer" scenarios.
* The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately.
* The destination call is a call previously established to introduce the transfered person.
* 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 #LinphoneCallConnected.
* @param[in] call A running call you want to transfer
* @param[in] dest A running call whose remote person will receive the transfer
* @return 0 on success, -1 on failure
**/
LINPHONE_PUBLIC int linphone_call_transfer_to_another(LinphoneCall *call, LinphoneCall *dest);
/**
* @}
*/

View file

@ -1146,8 +1146,9 @@ LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address_with_params(Linphone
* @param[in] refer_to The destination the call is to be refered to
* @return 0 on success, -1 on failure
* @ingroup call_control
* @deprecated Use linphone_call_transfer() instead
**/
LINPHONE_PUBLIC int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to);
/**
* Transfers a call to destination of another running call. This is used for "attended transfer" scenarios.
@ -1164,8 +1165,9 @@ LINPHONE_PUBLIC int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *
* @param[in] dest A running call whose remote person will receive the transfer
* @return 0 on success, -1 on failure
* @ingroup call_control
* @deprecated Use linphone_call_transfer_to_another() instead
**/
LINPHONE_PUBLIC int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest);
/**
* Start a new call as a consequence of a transfer request received from a call.
@ -1217,8 +1219,9 @@ LINPHONE_PUBLIC LinphoneCall *linphone_core_get_current_call(const LinphoneCore
* @param[in] call The LinphoneCall object representing the call to be answered
* @return 0 on success, -1 on failure
* @ingroup call_control
* @deprecated Use linphone_call_accept() instead
**/
LINPHONE_PUBLIC int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call);
/**
* Accept an incoming call, with parameters.
@ -1233,8 +1236,9 @@ LINPHONE_PUBLIC int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *ca
* @param[in] params The specific parameters for this call, for example whether video is accepted or not. Use NULL to use default parameters
* @return 0 on success, -1 on failure
* @ingroup call_control
* @deprecated Use linphone_call_accept_with_params() instead
**/
LINPHONE_PUBLIC int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params);
/**
* When receiving an incoming, accept to start a media session as early-media.
@ -1246,8 +1250,9 @@ LINPHONE_PUBLIC int linphone_core_accept_call_with_params(LinphoneCore *lc, Linp
* @param[in] params The call parameters to use (can be NULL)
* @return 0 if successful, -1 otherwise
* @ingroup call_control
* @deprecated Use linphone_call_accept_early_media_with_params() instead
**/
LINPHONE_PUBLIC int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, const LinphoneCallParams* params);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, const LinphoneCallParams* params);
/**
* Accept an early media session for an incoming call.
@ -1257,8 +1262,9 @@ LINPHONE_PUBLIC int linphone_core_accept_early_media_with_params(LinphoneCore* l
* @return 0 if successful, -1 otherwise
* @ingroup call_control
* @see linphone_core_accept_early_media_with_params()
* @deprecated Use linphone_call_accept_early_media() instead
**/
LINPHONE_PUBLIC int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call);
/**
* Terminates a call.
@ -1266,8 +1272,9 @@ LINPHONE_PUBLIC int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneC
* @param[in] call The LinphoneCall object representing the call to be terminated
* @return 0 on success, -1 on failure
* @ingroup call_control
* @deprecated Use linphone_call_terminate() instead
**/
LINPHONE_PUBLIC int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call);
/**
* Redirect the specified call to the given redirect URI.
@ -1276,8 +1283,9 @@ LINPHONE_PUBLIC int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall
* @param[in] redirect_uri The URI to redirect the call to
* @return 0 if successful, -1 on error.
* @ingroup call_control
* @deprecated Use linphone_call_redirect() instead
*/
LINPHONE_PUBLIC int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri);
/**
* Decline a pending incoming call, with a reason.
@ -1286,8 +1294,9 @@ LINPHONE_PUBLIC int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *
* @param[in] reason The reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy
* @return 0 on success, -1 on failure
* @ingroup call_control
* @deprecated Use linphone_call_decline() instead
**/
LINPHONE_PUBLIC int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason);
/**
* Terminates all the calls.
@ -1306,8 +1315,9 @@ LINPHONE_PUBLIC int linphone_core_terminate_all_calls(LinphoneCore *lc);
* @return 0 on success, -1 on failure
* @ingroup call_control
* @see linphone_core_resume_call()
* @deprecated Use linphone_call_pause() instead
**/
LINPHONE_PUBLIC int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
/**
* Pause all currently running calls.
@ -1325,8 +1335,9 @@ LINPHONE_PUBLIC int linphone_core_pause_all_calls(LinphoneCore *lc);
* @return 0 on success, -1 on failure
* @ingroup call_control
* @see linphone_core_pause_call()
* @deprecated Use linphone_call_resume() instead
**/
LINPHONE_PUBLIC int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call);
/**
* Updates a running call according to supplied call parameters or parameters changed in the LinphoneCore.
@ -1341,8 +1352,9 @@ LINPHONE_PUBLIC int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *ca
* @param[in] params The new call parameters to use (may be NULL)
* @return 0 if successful, -1 otherwise.
* @ingroup call_control
* @deprecated Use linphone_call_update() instead
**/
LINPHONE_PUBLIC int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params);
/**
* When receiving a #LinphoneCallUpdatedByRemote state notification, prevent LinphoneCore from performing an automatic answer.
@ -1364,8 +1376,9 @@ LINPHONE_PUBLIC int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *ca
* @param[in] call The call for which to defer the update
* @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a valid #LinphoneCallUpdatedByRemote notification
* @ingroup call_control
* @deprecated Use linphone_call_defer_update() instead
**/
LINPHONE_PUBLIC int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call);
/**
* Accept call modifications initiated by other end.
@ -1385,8 +1398,9 @@ LINPHONE_PUBLIC int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCa
* @param[in] params A LinphoneCallParams object describing the call parameters to accept
* @return 0 if successful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state)
* @ingroup call_control
* @deprecated Use linphone_call_accept_update() instead
**/
LINPHONE_PUBLIC int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params);
/**
* Create a LinphoneCallParams suitable for linphone_core_invite_with_params(), linphone_core_accept_call_with_params(), linphone_core_accept_early_media_with_params(),
@ -1781,8 +1795,9 @@ LINPHONE_PUBLIC bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, cons
* @param[in] pt The #LinphonePayloadType we want to know
* @return TRUE if the payload type represents a VBR codec, FALSE if disabled.
* @ingroup media_parameters
* @deprecated Use linphone_payload_type_is_vbr() instead
*/
LINPHONE_PUBLIC bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const LinphonePayloadType *pt);
LINPHONE_PUBLIC LINPHONE_DEPRECATED bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const LinphonePayloadType *pt);
/**
* Set an explicit bitrate (IP bitrate, not codec bitrate) for a given codec, in kbit/s.
@ -1839,15 +1854,17 @@ LINPHONE_PUBLIC LinphonePayloadType* linphone_core_find_payload_type(LinphoneCor
/**
* Returns the payload type number assigned for this codec.
* @ingroup media_parameters
* @deprecated Use linphone_payload_type_get_number() instead
**/
LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt);
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt);
/**
* Force a number for a payload type. The LinphoneCore does payload type number assignment automatically. THis function is to be used mainly for tests, in order
* to override the automatic assignment mechanism.
* @ingroup media_parameters
* @deprecated Use linphone_payload_type_set_number() instead
**/
LINPHONE_PUBLIC void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, int number);
LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, int number);
LINPHONE_PUBLIC const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt);

View file

@ -62,6 +62,28 @@ LINPHONE_PUBLIC const char * linphone_payload_type_get_mime_type(const LinphoneP
*/
LINPHONE_PUBLIC int linphone_payload_type_get_channels(const LinphonePayloadType *pt);
/**
* Returns the payload type number assigned for this codec.
* @param[in] pt LinphonePayloadType object
* @return The number of the payload type
**/
LINPHONE_PUBLIC int linphone_payload_type_get_number(const PayloadType *pt);
/**
* Force a number for a payload type. The LinphoneCore does payload type number assignment automatically. THis function is to be used mainly for tests, in order
* to override the automatic assignment mechanism.
* @param[in] pt LinphonePayloadType object
* @param[in] number The number to assign to the payload type
**/
LINPHONE_PUBLIC void linphone_payload_type_set_number(PayloadType *pt, int number);
/**
* Tells whether the specified payload type represents a variable bitrate codec.
* @param[in] pt LinphonePayloadType object
* @return TRUE if the payload type represents a VBR codec, FALSE if disabled.
*/
LINPHONE_PUBLIC bool_t linphone_payload_type_is_vbr(const LinphonePayloadType *pt);
/**
* @}
**/