From: Ghislain MARY Date: Fri, 3 Aug 2012 12:45:09 +0000 (+0200) Subject: Handle conversion between media description and ice session. X-Git-Url: http://sjero.net/git/?a=commitdiff_plain;h=5742b453cd3c1c636a53c0106e3e282654597cc4;p=linphone Handle conversion between media description and ice session. --- diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 63327de6..ba278923 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -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); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4a06a787..7a178169 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -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)); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6f08e926..1a0a8575 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -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); diff --git a/coreapi/misc.c b/coreapi/misc.c index a59aca88..81db63ad 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -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; diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 118f2420..1d4ce1b9 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -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; } diff --git a/coreapi/private.h b/coreapi/private.h index bc65e946..f6872547 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -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);