]> sjero.net Git - linphone/commitdiff
Handle conversion between media description and ice session.
authorGhislain MARY <ghislain.mary@belledonne-communications.com>
Fri, 3 Aug 2012 12:45:09 +0000 (14:45 +0200)
committerGhislain MARY <ghislain.mary@belledonne-communications.com>
Mon, 6 Aug 2012 09:41:29 +0000 (11:41 +0200)
coreapi/callbacks.c
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/misc.c
coreapi/offeranswer.c
coreapi/private.h

index 63327de66dad777ab968f49f98c3db9f54bc13cc..ba2789235fef620d05ea3679f3e91b4a4ca11eee 100644 (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);
index 4a06a7873be51378bd3e8c1adea65f5dc5e11d51..7a178169657997749cdfab3297a6e146f16eb0c9 100644 (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));
index 6f08e92600c8a2c6d9211a7453979dcaa434af9c..1a0a857529474b66fe3015216220e4b1663881c5 100644 (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);
index a59aca8862238c10a18344559031bfa889c8397c..81db63ad0274485ae70f54b4140ccbc350ca06b4 100644 (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;
index 118f2420a165ce6cd0b01365f5d3912c98913f88..1d4ce1b9fcee0f7c2ff53398ae44c5a609ecfa17 100644 (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;
 }
index bc65e946e8ca7598799f0803b2e97503b70039bf..f68725473534da3b70e8f75d2c95a005f7a78148 100644 (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);