void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call) { IceCheckList *audio_check_list; IceCheckList *video_check_list; 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); if (audio_check_list == NULL) return; session_state = ice_session_state(call->ice_session); if ((session_state == IS_Completed) || ((session_state == IS_Failed) && (ice_session_has_completed_check_list(call->ice_session) == TRUE))) { if (ice_check_list_state(audio_check_list) == ICL_Completed) { switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) { case ICT_HostCandidate: call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateHostConnection; break; case ICT_ServerReflexiveCandidate: case ICT_PeerReflexiveCandidate: call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateReflexiveConnection; break; case ICT_RelayedCandidate: call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection; break; } } else { call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed; } if (call->params.has_video && (video_check_list != NULL)) { if (ice_check_list_state(video_check_list) == ICL_Completed) { switch (ice_check_list_selected_valid_candidate_type(video_check_list)) { case ICT_HostCandidate: call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateHostConnection; break; case ICT_ServerReflexiveCandidate: case ICT_PeerReflexiveCandidate: call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateReflexiveConnection; break; case ICT_RelayedCandidate: call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection; break; } } else { call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed; } } } else if (session_state == IS_Running) { call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; if (call->params.has_video && (video_check_list != NULL)) { call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; } } else { call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed; if (call->params.has_video && (video_check_list != NULL)) { call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed; } } }
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) { char local_addr[64]; sockaddr_x ss; socklen_t ss_len; IceCheckList *audio_check_list; IceCheckList *video_check_list; 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); if (audio_check_list == NULL) return -1; if (lc->sip_conf.ipv6_enabled){ ms_warning("stun support is not implemented for ipv6"); return -1; } if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) { ms_error("Fail to parser stun server address: %s", server); return -1; } if (lc->vtable.display_status != NULL) lc->vtable.display_status(lc, _("ICE local candidates gathering in progress...")); /* Gather local host candidates. */ if (linphone_core_get_local_ip_for(AF_INET, server, local_addr) < 0) { ms_error("Fail to get local ip"); return -1; } if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) { ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL); ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; } if (call->params.has_video && (video_check_list != NULL) && (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) { ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL); ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL); call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; } ms_message("ICE: gathering candidate from [%s]",server); /* Gather local srflx candidates. */ /* ice_session_gather_candidates(call->ice_session, ss, ss_len); */ return 0; }
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) { char local_addr[64]; const struct addrinfo *ai; IceCheckList *audio_check_list; IceCheckList *video_check_list; 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); if (audio_check_list == NULL) return -1; if (call->af==AF_INET6){ ms_warning("Ice gathering is not implemented for ipv6"); return -1; } ai=linphone_core_get_stun_server_addrinfo(lc); if (ai==NULL){ ms_warning("Fail to resolve STUN server for ICE gathering."); return -1; } if (lc->vtable.display_status != NULL) lc->vtable.display_status(lc, _("ICE local candidates gathering in progress...")); /* Gather local host candidates. */ if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) { ms_error("Fail to get local ip"); return -1; } if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) { ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL); ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; } if (call->params.has_video && (video_check_list != NULL) && (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) { ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL); ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL); call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; } ms_message("ICE: gathering candidate from [%s]",server); /* Gather local srflx candidates. */ ice_session_gather_candidates(call->ice_session, ai->ai_addr, ai->ai_addrlen); return 0; }
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session) { const char *rtp_addr, *rtcp_addr; IceSessionState session_state = ice_session_state(session); int nb_candidates; int i, j; bool_t result; if (session_state == IS_Completed) { desc->ice_completed = TRUE; result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL); if (result == TRUE) { strncpy(desc->addr, rtp_addr, sizeof(desc->addr)); } else { ms_warning("If ICE has completed successfully, rtp_addr should be set!"); } } 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->n_active_streams; i++) { SalStreamDescription *stream = &desc->streams[i]; IceCheckList *cl = ice_session_check_list(session, i); nb_candidates = 0; if (cl == NULL) continue; if (ice_check_list_state(cl) == ICL_Completed) { stream->ice_completed = TRUE; result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); } else { stream->ice_completed = FALSE; result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); } if (result == TRUE) { strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr)); strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr)); } else { memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr)); memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr)); } 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)); stream->ice_mismatch = ice_check_list_is_mismatch(cl); if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) { memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); for (j = 0; j < MIN(ms_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) { SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates]; 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 ((ice_check_list_state(cl) == 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; } nb_candidates++; } } if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) { int rtp_port, rtcp_port; memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates)); if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port) == TRUE) { 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; } else { ms_error("ice: Selected valid remote candidates should be present if the check list is in the Completed state"); } } else { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { stream->ice_remote_candidates[j].addr[0] = '\0'; stream->ice_remote_candidates[j].port = 0; } } } }