Commit 0f1cf8b1 authored by Simon Morlat's avatar Simon Morlat

fix various recent problems with SDP offer/answer and ICE.

Most problematic was that declined streams were not put in SDP answers.
parent 275e6b61
......@@ -416,8 +416,7 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr));
}
for ( i=0; i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++ ) {
if (!sal_stream_description_active(&desc->streams[i])) continue;
for ( i=0; i<desc->nb_streams; i++ ) {
stream_description_to_sdp(session_desc, desc, &desc->streams[i]);
}
return session_desc;
......
......@@ -129,18 +129,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
ms_error("linphone_core_update_streams() called with null media description");
return;
}
if (call->biggestdesc==NULL || new_md->nb_streams>call->biggestdesc->nb_streams){
/*we have been offered and now are ready to proceed, or we added a new stream*/
/*store the media description to remember the mapping of calls*/
if (call->biggestdesc){
sal_media_description_unref(call->biggestdesc);
call->biggestdesc=NULL;
}
if (sal_call_is_offerer(call->op))
call->biggestdesc=sal_media_description_ref(call->localdesc);
else
call->biggestdesc=sal_media_description_ref(sal_call_get_remote_media_description(call->op));
}
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)){
......@@ -438,6 +427,8 @@ static void call_ringing(SalOp *h){
linphone_core_notify_display_status(lc,_("Remote ringing..."));
linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
}else{
/*initialize the remote call params by invoking linphone_call_get_remote_params(). This is useful as the SDP may not be present in the 200Ok*/
linphone_call_get_remote_params(call);
/*accept early media */
if ((call->audiostream && audio_stream_started(call->audiostream))
#ifdef VIDEO_ENABLED
......@@ -565,7 +556,7 @@ static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *o
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_fix_call_parameters(call);
linphone_call_fix_call_parameters(call, rmd);
linphone_call_set_state(call, next_state, next_state_str);
}else{
ms_error("BUG: next_state is not set in call_accepted(), current state is %s", linphone_call_state_to_string(call->state));
......@@ -706,7 +697,7 @@ static void call_updating(SalOp *op, bool_t is_update){
ms_error("call_updating(): call doesn't exist anymore");
return ;
}
linphone_call_fix_call_parameters(call);
linphone_call_fix_call_parameters(call, rmd);
if (call->state!=LinphoneCallPaused){
/*Refresh the local description, but in paused state, we don't change anything.*/
linphone_call_make_local_media_description(call);
......
......@@ -589,6 +589,18 @@ static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, in
return public_ip;
}
void linphone_call_update_biggest_desc(LinphoneCall *call, SalMediaDescription *md){
if (call->biggestdesc==NULL || md->nb_streams>call->biggestdesc->nb_streams){
/*we have been offered and now are ready to proceed, or we added a new stream*/
/*store the media description to remember the mapping of calls*/
if (call->biggestdesc){
sal_media_description_unref(call->biggestdesc);
call->biggestdesc=NULL;
}
call->biggestdesc=sal_media_description_ref(md);
}
}
static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDescription *md){
int i;
......@@ -862,6 +874,9 @@ static void port_config_set(LinphoneCall *call, int stream_index, int min_port,
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
int min_port, max_port;
ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version());
call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO;
call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO;
call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT;
call->state=LinphoneCallIdle;
call->transfer_state = LinphoneCallIdle;
call->log=linphone_call_log_new(call->dir, from, to);
......@@ -1018,10 +1033,6 @@ void linphone_call_fill_media_multicast_addr(LinphoneCall *call) {
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
LinphoneCall *call = belle_sip_object_new(LinphoneCall);
call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO;
call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO;
call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT;
call->dir=LinphoneCallOutgoing;
call->core=lc;
linphone_call_outgoing_select_ip_version(call,to,cfg);
......@@ -1066,7 +1077,7 @@ static void linphone_call_incoming_select_ip_version(LinphoneCall *call){
/**
* Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally.
*/
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md) {
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, SalMediaDescription *md) {
/* Handle AVPF, SRTP and DTLS. */
call->params->avpf_enabled = sal_media_description_has_avpf(md);
if (call->params->avpf_enabled == TRUE) {
......@@ -1083,15 +1094,14 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c
}else if (call->params->media_encryption != LinphoneMediaEncryptionZRTP){
call->params->media_encryption = LinphoneMediaEncryptionNone;
}
linphone_call_fix_call_parameters(call);
linphone_call_fix_call_parameters(call, md);
}
static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDescription *md) {
static void linphone_call_compute_streams_indexes(LinphoneCall *call, const SalMediaDescription *md) {
int i, j;
bool_t audio_found = FALSE, video_found = FALSE, text_found = FALSE;
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
for (i = 0; i < md->nb_streams; i++) {
if (md->streams[i].type == SalAudio) {
if (!audio_found) {
call->main_audio_stream_index = i;
......@@ -1191,10 +1201,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
SalMediaDescription *md;
LinphoneFirewallPolicy fpol;
int i;
call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO;
call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO;
call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT;
call->dir=LinphoneCallIncoming;
sal_op_set_user_pointer(op,call);
......@@ -1206,9 +1212,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0));
md = sal_call_get_remote_media_description(op);
if (md) {
linphone_call_compute_streams_indexes(call, md);
}
if (lc->sip_conf.ping_with_options){
#ifdef BUILD_UPNP
......@@ -1385,10 +1388,19 @@ static void linphone_call_set_terminated(LinphoneCall *call){
}
}
/*function to be called at each incoming reINVITE, in order to adjust the video enablement parameter according to what is offered
* and our local policy. Fixing the call->params to proper values avoid request video by accident during internal call updates, pauses and resumes*/
void linphone_call_fix_call_parameters(LinphoneCall *call){
const LinphoneCallParams* rcp = linphone_call_get_remote_params(call);
/*function to be called at each incoming reINVITE, in order to adjust various local parameters to what is being offered by remote:
* - the video enablement parameter according to what is offered and our local policy.
* Fixing the call->params to proper values avoid request video by accident during internal call updates, pauses and resumes
* - the stream indexes.
*/
void linphone_call_fix_call_parameters(LinphoneCall *call, SalMediaDescription *rmd){
const LinphoneCallParams* rcp;
if (rmd) {
linphone_call_compute_streams_indexes(call, rmd);
linphone_call_update_biggest_desc(call, rmd);
}
rcp = linphone_call_get_remote_params(call);
if (rcp){
if (call->params->has_video && !rcp->has_video){
ms_message("Call [%p]: disabling video in our call params because the remote doesn't want it.", call);
......
......@@ -3478,7 +3478,6 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call,
md=sal_call_get_final_media_description(call->op);
if (md && !sal_media_description_empty(md)){
linphone_core_update_streams(lc, call, md, next_state);
linphone_call_fix_call_parameters(call);
}
linphone_call_set_state(call,next_state,state_info);
return 0;
......@@ -3678,7 +3677,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
/*try to be best-effort in giving real local or routable contact address */
linphone_call_set_contact_op(call);
if (params){
const SalMediaDescription *md = sal_call_get_remote_media_description(call->op);
SalMediaDescription *md = sal_call_get_remote_media_description(call->op);
linphone_call_set_new_params(call,params);
// There might not be a md if the INVITE was lacking an SDP
// In this case we use the parameters as is.
......@@ -3713,7 +3712,6 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
new_md=sal_call_get_final_media_description(call->op);
if (new_md){
linphone_core_update_streams(lc, call, new_md, LinphoneCallStreamsRunning);
linphone_call_fix_call_parameters(call);
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
}else call->expect_media_in_ack=TRUE;
......
......@@ -630,9 +630,9 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
const char *server = linphone_core_get_stun_server(lc);
if ((server == NULL) || (call->ice_session == NULL)) return -1;
audio_check_list = ice_session_check_list(call->ice_session, 0);
video_check_list = ice_session_check_list(call->ice_session, 1);
text_check_list = ice_session_check_list(call->ice_session, 2);
audio_check_list = ice_session_check_list(call->ice_session, call->main_audio_stream_index);
video_check_list = ice_session_check_list(call->ice_session, call->main_video_stream_index);
text_check_list = ice_session_check_list(call->ice_session, call->main_text_stream_index);
if (audio_check_list == NULL) return -1;
if (call->af==AF_INET6){
......@@ -700,8 +700,8 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
IceSessionState session_state;
if (call->ice_session == NULL) return;
audio_check_list = ice_session_check_list(call->ice_session, 0);
video_check_list = ice_session_check_list(call->ice_session, 1);
audio_check_list = ice_session_check_list(call->ice_session, call->main_audio_stream_index);
video_check_list = ice_session_check_list(call->ice_session, call->main_video_stream_index);
if (audio_check_list == NULL) return;
session_state = ice_session_state(call->ice_session);
......@@ -763,7 +763,8 @@ void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call) {
if (session == NULL) return;
if (ice_session_state(session) == IS_Completed) return;
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
ms_message("linphone_call_stop_ice_for_inactive_streams: nb_streams = %i", desc->nb_streams);
for (i = 0; i < desc->nb_streams; i++) {
IceCheckList *cl = ice_session_check_list(session, i);
if (!sal_stream_description_active(&desc->streams[i]) && cl) {
ice_session_remove_check_list(session, cl);
......@@ -795,7 +796,7 @@ void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSess
}
strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
for (i = 0; i < desc->nb_streams; i++) {
SalStreamDescription *stream = &desc->streams[i];
IceCheckList *cl = ice_session_check_list(session, i);
nb_candidates = 0;
......@@ -902,10 +903,9 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
ice_params_found=TRUE;
} else {
int i;
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
for (i = 0; i < md->nb_streams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (!sal_stream_description_active(stream)) continue;
if (cl) {
if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
ice_params_found=TRUE;
......@@ -924,10 +924,9 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
ice_session_restart(call->ice_session);
ice_restarted = TRUE;
} else {
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
for (i = 0; i < md->nb_streams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (!sal_stream_description_active(stream)) continue;
if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) {
ice_session_restart(call->ice_session);
ice_restarted = TRUE;
......@@ -944,10 +943,9 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
}
ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
}
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
for (i = 0; i < md->nb_streams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (!sal_stream_description_active(stream)) continue;
if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) {
if (ice_restarted == FALSE
......@@ -964,26 +962,10 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
}
/* Create ICE check lists if needed and parse ICE attributes. */
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
for (i = 0; i < md->nb_streams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (!sal_stream_description_active(stream)) continue;
/*
if ((cl == NULL) && (i < md->n_active_streams)) {
cl = ice_check_list_new();
ice_session_add_check_list(call->ice_session, cl);
switch (stream->type) {
case SalAudio:
if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = cl;
break;
case SalVideo:
if (call->videostream != NULL) call->videostream->ms.ice_check_list = cl;
break;
default:
break;
}
}
*/
if (cl==NULL) continue;
if (stream->ice_mismatch == TRUE) {
ice_check_list_set_state(cl, ICL_Failed);
......@@ -1008,7 +990,7 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
}
if (ice_restarted == FALSE) {
bool_t losing_pairs_added = FALSE;
for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j];
const char *addr = NULL;
int port = 0;
......@@ -1026,7 +1008,7 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
}
}
}
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
for (i = 0; i < md->nb_streams; i++) {
IceCheckList * cl = ice_session_check_list(call->ice_session, i);
if (!sal_stream_description_active(&md->streams[i]) && (cl != NULL)) {
ice_session_remove_check_list_from_idx(call->ice_session, i);
......@@ -1047,7 +1029,7 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md){
int i;
for (i = 0; md && i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
for (i = 0; md && i < md->nb_streams; i++) {
if (md->streams[i].type == SalVideo && md->streams[i].rtp_port!=0)
return TRUE;
}
......
......@@ -490,23 +490,21 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
const SalMediaDescription *remote_answer,
SalMediaDescription *result){
int i,j;
int i;
const SalStreamDescription *ls,*rs;
for(i=0,j=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
ls=&local_offer->streams[i];
if (!sal_stream_description_active(ls)) continue;
for(i=0;i<local_offer->nb_streams;++i){
ms_message("Processing for stream %i",i);
rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type);
if (rs) {
initiate_outgoing(ls,rs,&result->streams[j]);
ls=&local_offer->streams[i];
rs=&remote_answer->streams[i];
if (rs && ls->proto == rs->proto && rs->type == ls->type) {
initiate_outgoing(ls,rs,&result->streams[i]);
memcpy(&result->streams[i].rtcp_xr, &ls->rtcp_xr, sizeof(result->streams[i].rtcp_xr));
if ((ls->rtcp_xr.enabled == TRUE) && (rs->rtcp_xr.enabled == FALSE)) {
result->streams[i].rtcp_xr.enabled = FALSE;
}
result->streams[i].rtcp_fb.generic_nack_enabled = ls->rtcp_fb.generic_nack_enabled & rs->rtcp_fb.generic_nack_enabled;
result->streams[i].rtcp_fb.tmmbr_enabled = ls->rtcp_fb.tmmbr_enabled & rs->rtcp_fb.tmmbr_enabled;
++j;
}
else ms_warning("No matching stream for %i",i);
}
......@@ -521,39 +519,6 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
return 0;
}
static bool_t local_stream_not_already_used(const SalMediaDescription *result, const SalStreamDescription *stream){
int i;
for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
const SalStreamDescription *ss=&result->streams[i];
if (strcmp(ss->name,stream->name)==0){
ms_message("video stream already used in answer");
return FALSE;
}
}
return TRUE;
}
/*in answering mode, we consider that if we are able to make AVPF/SAVP/SAVPF, then we can do AVP as well*/
static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) {
if (local == remote) return TRUE;
if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpSavpf))) return TRUE;
if ((remote == SalProtoRtpAvp) && ((local == SalProtoUdpTlsRtpSavp) || (local == SalProtoUdpTlsRtpSavpf))) return TRUE;
if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) return TRUE;
if ((remote == SalProtoRtpAvpf) && (local == SalProtoUdpTlsRtpSavpf)) return TRUE;
return FALSE;
}
static const SalStreamDescription *find_local_matching_stream(const SalMediaDescription *result, const SalMediaDescription *local_capabilities, const SalStreamDescription *remote_stream){
int i;
for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
const SalStreamDescription *ss=&local_capabilities->streams[i];
if (!sal_stream_description_active(ss)) continue;
if (ss->type==remote_stream->type && proto_compatible(ss->proto,remote_stream->proto)
&& local_stream_not_already_used(result,ss)) return ss;
}
return NULL;
}
/**
* Returns a media description to run the streams with, based on the local capabilities and
* and the received offer.
......@@ -564,15 +529,11 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
SalMediaDescription *result, bool_t one_matching_codec){
int i;
const SalStreamDescription *ls=NULL,*rs;
result->nb_streams = 0;
for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
rs=&remote_offer->streams[i];
if (!sal_stream_description_active(rs)) continue;
if (rs->proto!=SalProtoOther){
ls=find_local_matching_stream(result,local_capabilities,rs);
}else ms_warning("Unknown protocol for mline %i, declining",i);
if (ls){
for(i=0;i<remote_offer->nb_streams;++i){
rs = &remote_offer->streams[i];
ls = &local_capabilities->streams[i];
if (ls && rs->type == ls->type && rs->proto == ls->proto){
initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
// Handle global RTCP FB attributes
result->streams[i].rtcp_fb.generic_nack_enabled = rs->rtcp_fb.generic_nack_enabled;
......@@ -589,7 +550,6 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
result->streams[i].rtcp_xr.enabled = TRUE;
}
}
result->nb_streams++;
}else {
ms_message("Declining mline %i, no corresponding stream in local capabilities description.",i);
/* create an inactive stream for the answer, as there where no matching stream in local capabilities */
......@@ -605,7 +565,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
}
}
}
result->nb_streams=i;
strcpy(result->username, local_capabilities->username);
strcpy(result->addr,local_capabilities->addr);
result->bandwidth=local_capabilities->bandwidth;
......
......@@ -331,7 +331,7 @@ LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddr
void linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params);
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message);
void linphone_call_set_contact_op(LinphoneCall* call);
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md);
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, SalMediaDescription *md);
/* private: */
LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *local, LinphoneAddress * remote);
void linphone_call_log_completed(LinphoneCall *call);
......@@ -460,7 +460,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing);
void linphone_call_init_stats(LinphoneCallStats *stats, int type);
void linphone_call_fix_call_parameters(LinphoneCall *call);
void linphone_call_fix_call_parameters(LinphoneCall *call, SalMediaDescription *rmd);
void linphone_call_init_audio_stream(LinphoneCall *call);
void linphone_call_init_video_stream(LinphoneCall *call);
void linphone_call_init_text_stream(LinphoneCall *call);
......@@ -933,6 +933,7 @@ int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_get_calls_nb(const LinphoneCore *lc);
void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
void linphone_call_update_biggest_desc(LinphoneCall *call, SalMediaDescription *md);
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);
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment