diff --git a/daemon/call.c b/daemon/call.c index 52db49e0e..e8657b410 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -1023,8 +1023,17 @@ enum call_stream_state call_stream_state_machine(struct packet_stream *ps) { if (MEDIA_ISSET(media, PASSTHRU)) return CSS_RUNNING; - if (MEDIA_ISSET(media, ICE) && !ice_has_finished(media)) - return CSS_ICE; /* handled by ICE timer */ + enum call_stream_state ret = CSS_RUNNING; + + if (MEDIA_ISSET(media, ICE) && !ice_has_finished(media)) { + if (!MEDIA_ISSET(media, DTLS)) + return CSS_ICE; /* handled by ICE timer */ + if (!ice_is_usable(media)) + return CSS_ICE; /* handled by ICE timer */ + // special case: ICE was able to communicate and DTLS is in use. + // we can now start DTLS if necessary. + ret = CSS_ICE; + } if (MEDIA_ISSET(media, DTLS)) { mutex_lock(&ps->in_lock); @@ -1037,7 +1046,7 @@ enum call_stream_state call_stream_state_machine(struct packet_stream *ps) { mutex_unlock(&ps->in_lock); } - return CSS_RUNNING; + return ret; } void call_media_state_machine(struct call_media *m) { diff --git a/daemon/ice.c b/daemon/ice.c index b1b4d8dbc..e39bb5738 100644 --- a/daemon/ice.c +++ b/daemon/ice.c @@ -277,7 +277,7 @@ static int __copy_cand(struct call *call, struct ice_candidate *dst, const struc static void __ice_reset(struct ice_agent *ag) { __agent_deschedule(ag); - AGENT_CLEAR2(ag, COMPLETED, NOMINATING); + AGENT_CLEAR3(ag, COMPLETED, NOMINATING, USABLE); __ice_agent_free_components(ag); ZERO(ag->active_components); ZERO(ag->start_nominating); @@ -699,6 +699,7 @@ static void __do_ice_checks(struct ice_agent *ag) { /* triggered checks are preferred */ pair = g_queue_pop_head(&ag->triggered); if (pair) { + __DBG("running triggered check on " PAIR_FORMAT, PAIR_FMT(pair)); PAIR_CLEAR(pair, TRIGGERED); next_run = rtpe_now; goto check; @@ -708,6 +709,8 @@ static void __do_ice_checks(struct ice_agent *ag) { for (l = ag->all_pairs_list.head; l; l = l->next) { pair = l->data; + __DBG("considering checking " PAIR_FORMAT, PAIR_FMT(pair)); + /* skip dead streams */ sfd = pair->sfd; if (!sfd || !sfd->stream || !sfd->stream->selected_sfd) @@ -744,6 +747,7 @@ static void __do_ice_checks(struct ice_agent *ag) { /* remember the first frozen pair in case we find nothing else */ if (PAIR_ISSET(pair, FROZEN)) { + __DBG("pair " PAIR_FORMAT " is frozen", PAIR_FMT(pair)); if (!frozen) frozen = pair; continue; @@ -753,10 +757,14 @@ static void __do_ice_checks(struct ice_agent *ag) { highest = pair; } - if (highest) + if (highest) { pair = highest; - else if (frozen) + __DBG("checking highest priority pair " PAIR_FORMAT, PAIR_FMT(pair)); + } + else if (frozen) { pair = frozen; + __DBG("checking highest priority frozen pair " PAIR_FORMAT, PAIR_FMT(pair)); + } else pair = NULL; @@ -977,6 +985,7 @@ static int __check_valid(struct ice_agent *ag) { struct ice_candidate_pair *pair; // const struct local_intf *ifa; struct stream_fd *sfd; + int is_complete = 1; if (!ag) { ilog(LOG_ERR, "ice ag is NULL"); @@ -988,13 +997,23 @@ static int __check_valid(struct ice_agent *ag) { __get_complete_valid_pairs(&all_compos, ag); if (!all_compos.length) { - ilog(LOG_DEBUG, "ICE not completed yet"); - return 0; + is_complete = 0; + __get_complete_succeeded_pairs(&all_compos, ag); + if (!all_compos.length) { + ilog(LOG_DEBUG, "ICE not completed yet and no usable candidates"); + return 0; + } } pair = all_compos.head->data; - ilog(LOG_DEBUG, "ICE completed, using pair "PAIR_FORMAT, PAIR_FMT(pair)); - AGENT_SET(ag, COMPLETED); + if (is_complete) { + ilog(LOG_DEBUG, "ICE completed, using pair " PAIR_FORMAT, PAIR_FMT(pair)); + AGENT_SET(ag, COMPLETED); + } + else { + ilog(LOG_DEBUG, "ICE not completed yet, but can use pair " PAIR_FORMAT, PAIR_FMT(pair)); + AGENT_SET(ag, USABLE); + } for (l = media->streams.head, k = all_compos.head; l && k; l = l->next, k = k->next) { ps = l->data; @@ -1252,11 +1271,10 @@ int ice_response(struct stream_fd *sfd, const endpoint_t *src, if (PAIR_ISSET(pair, NOMINATED)) { PAIR_SET(pair, VALID); g_tree_insert(ag->valid_pairs, pair, pair); - - if (!AGENT_ISSET(ag, CONTROLLING)) - ret = __check_valid(ag); } + ret = __check_valid(ag); + out_unlock: mutex_unlock(&ag->lock); out: diff --git a/include/ice.h b/include/ice.h index 059b6af16..c96356806 100644 --- a/include/ice.h +++ b/include/ice.h @@ -29,6 +29,7 @@ #define ICE_AGENT_COMPLETED 0x0002 #define ICE_AGENT_CONTROLLING 0x0004 #define ICE_AGENT_NOMINATING 0x0008 +#define ICE_AGENT_USABLE 0x0010 #define ICE_PAIR_FROZEN 0x0001 #define ICE_PAIR_IN_PROGRESS 0x0002 @@ -51,7 +52,8 @@ #define AGENT_SET(p, f) bf_set(&(p)->agent_flags, ICE_AGENT_ ## f) #define AGENT_SET2(p, f, g) bf_set(&(p)->agent_flags, ICE_AGENT_ ## f | ICE_AGENT_ ## g) #define AGENT_CLEAR(p, f) bf_clear(&(p)->agent_flags, ICE_AGENT_ ## f) -#define AGENT_CLEAR2(p, f, g) bf_clear(&(p)->agent_flags, ICE_AGENT_ ## f | ICE_AGENT_ ## g) +#define AGENT_CLEAR3(p, f, g, h) \ + bf_clear(&(p)->agent_flags, ICE_AGENT_ ## f | ICE_AGENT_ ## g | ICE_AGENT_ ## h) @@ -178,6 +180,18 @@ INLINE int ice_has_finished(struct call_media *media) { return 1; return 0; } +/* returns 1 if media has connectivity */ +INLINE int ice_is_usable(struct call_media *media) { + if (!media) + return 1; + if (!MEDIA_ISSET(media, ICE)) + return 1; + if (!media->ice_agent) + return 1; + if (AGENT_ISSET(media->ice_agent, USABLE)) + return 1; + return 0; +} INLINE unsigned int ice_type_preference(enum ice_candidate_type type) { if (type >= __ICT_LAST) return 0;