Handle conversion between media description and ice session.

This commit is contained in:
Ghislain MARY 2012-08-03 14:45:09 +02:00
parent 6f2853c8a0
commit 5742b453cd
6 changed files with 151 additions and 10 deletions

View file

@ -261,10 +261,9 @@ static void call_accepted(SalOp *op){
return ;
}
if (call->ice_session == NULL) {
/* Ensure the ICE check list pointers for the call streams are resetted to prevent crashes */
if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL;
if (call->videostream != NULL) call->videostream->ice_check_list = NULL;
/* Handle remote ICE attributes if any. */
if (call->ice_session != NULL) {
linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
}
md=sal_call_get_final_media_description(op);

View file

@ -247,8 +247,7 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
md->streams[i].crypto[1].algo = 0;
md->streams[i].crypto[2].algo = 0;
}
if ((call->dir == LinphoneCallOutgoing) && (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce)
&& (call->ice_session != NULL) && (ice_session_check_list(call->ice_session, i) == NULL)) {
if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL) && (ice_session_check_list(call->ice_session, i) == NULL)) {
ice_session_add_check_list(call->ice_session, ice_check_list_new());
}
}
@ -390,6 +389,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
call->camera_active=call->params.has_video;
switch (linphone_core_get_firewall_policy(call->core)) {
case LinphonePolicyUseIce:
call->ice_session = ice_session_new();
ice_session_set_role(call->ice_session, IR_Controlled);
linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
linphone_call_init_media_streams(call);
linphone_call_start_media_streams_for_ice_gathering(call);
if (linphone_core_gather_ice_candidates(call->core,call)<0) {
@ -402,7 +404,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
linphone_core_run_stun_tests(call->core,call);
/* No break to also destroy ice session in this case. */
default:
linphone_call_delete_ice_session(call);
break;
}
discover_mtu(lc,linphone_address_get_domain(from));

View file

@ -2123,6 +2123,8 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro
audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
if (!lc->sip_conf.sdp_200_ack){
call->media_pending=TRUE;
if (call->ice_session != NULL)
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
sal_call_set_local_media_description(call->op,call->localdesc);
}
real_url=linphone_address_as_string(call->log->to);
@ -2379,9 +2381,9 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE);
const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc);
/* Regenerate final media description to include all ICE candidates. */
if (call->ice_session != NULL)
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
md=sal_call_get_final_media_description(call->op);
if (md && sal_media_description_empty(md)){
sal_call_decline(call->op,SalReasonMedia,NULL);
linphone_call_unref(call);
@ -2464,7 +2466,9 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
call->params=*params;
call->camera_active=call->params.has_video;
update_local_media_description(lc,call);
if (call->ice_session != NULL)
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
if (params->in_conference){
subject="Conference";
}else{
@ -2548,6 +2552,10 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const
}
call->camera_active=call->params.has_video;
update_local_media_description(lc,call);
if (call->ice_session != NULL) {
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op));
}
sal_call_set_local_media_description(call->op,call->localdesc);
sal_call_accept(call->op);
md=sal_call_get_final_media_description(call->op);

View file

@ -605,6 +605,128 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
return 0;
}
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
{
IceSessionState session_state = ice_session_state(session);
int i, j;
if (session_state == IS_Completed) desc->ice_completed = TRUE;
else desc->ice_completed = FALSE;
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 < desc->nstreams; i++) {
SalStreamDescription *stream = &desc->streams[i];
IceCheckList *cl = ice_session_check_list(session, i);
if (cl == NULL) continue;
if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd)))
strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd));
else
memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag)))
strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag));
else
memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
if ((cl->state == ICL_Running) || (cl->state == ICL_Completed)) {
memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates));
for (j = 0; j < ms_list_size(cl->local_candidates); j++) {
SalIceCandidate *sal_candidate = &stream->ice_candidates[j];
IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j);
const char *default_addr = NULL;
int default_port = 0;
if (ice_candidate->componentID == 1) {
default_addr = stream->rtp_addr;
default_port = stream->rtp_port;
} else if (ice_candidate->componentID == 2) {
default_addr = stream->rtcp_addr;
default_port = stream->rtcp_port;
} else continue;
if (default_addr[0] == '\0') default_addr = desc->addr;
/* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */
if ((cl->state == ICL_Completed)
&& !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0)))
continue;
strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation));
sal_candidate->componentID = ice_candidate->componentID;
sal_candidate->priority = ice_candidate->priority;
strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type));
strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr));
sal_candidate->port = ice_candidate->taddr.port;
if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) {
strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr));
sal_candidate->rport = ice_candidate->base->taddr.port;
}
}
}
if ((cl->state == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
const char *rtp_addr, *rtcp_addr;
int rtp_port, rtcp_port;
memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
ice_check_list_nominated_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
stream->ice_remote_candidates[0].port = rtp_port;
strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
stream->ice_remote_candidates[1].port = rtcp_port;
}
}
}
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
{
if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) {
int i, j;
ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
for (i = 0; i < md->nstreams; i++) {
const SalStreamDescription *stream = &md->streams[i];
IceCheckList *cl = ice_session_check_list(call->ice_session, i);
if (cl == NULL) {
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->ice_check_list = cl;
break;
case SalVideo:
if (call->videostream != NULL) call->videostream->ice_check_list = cl;
break;
default:
break;
}
}
if (stream->ice_mismatch == TRUE) {
ice_check_list_set_state(cl, ICL_Failed);
} else {
if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
const SalIceCandidate *candidate = &stream->ice_candidates[j];
bool_t default_candidate = FALSE;
const char *addr = NULL;
int port = 0;
if (candidate->addr[0] == '\0') break;
if (candidate->componentID == 1) {
addr = stream->rtp_addr;
port = stream->rtp_port;
}
else if (candidate->componentID == 2) {
addr = stream->rtcp_addr;
port = stream->rtcp_port;
}
if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0))
default_candidate = TRUE;
ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID,
candidate->priority, candidate->foundation, default_candidate);
}
}
}
for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) {
ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
}
}
if ((ice_session_state(call->ice_session) == IS_Failed) || (ice_session_nb_check_lists(call->ice_session) == 0)) {
linphone_call_delete_ice_session(call);
}
}
LinphoneCall * is_a_linphone_call(void *user_pointer){
LinphoneCall *call=(LinphoneCall*)user_pointer;
if (call==NULL) return NULL;

View file

@ -253,6 +253,11 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
result->rtp_port = 0;
}
strcpy(result->ice_pwd, local_cap->ice_pwd);
strcpy(result->ice_ufrag, local_cap->ice_ufrag);
result->ice_mismatch = local_cap->ice_mismatch;
memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates));
memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates));
}
/**
@ -321,5 +326,9 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
result->bandwidth=local_capabilities->bandwidth;
result->session_ver=local_capabilities->session_ver;
result->session_id=local_capabilities->session_id;
strcpy(result->ice_pwd, local_capabilities->ice_pwd);
strcpy(result->ice_ufrag, local_capabilities->ice_ufrag);
result->ice_lite = local_capabilities->ice_lite;
result->ice_completed = local_capabilities->ice_lite;
return 0;
}

View file

@ -221,6 +221,8 @@ void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt);
void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
void linphone_core_send_initial_subscribes(LinphoneCore *lc);
void linphone_core_write_friends_config(LinphoneCore* lc);