diff options
-rw-r--r-- | pjmedia/include/pjmedia/transport.h | 2 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/transport_ice.h | 46 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/transport_ice.c | 32 | ||||
-rw-r--r-- | pjnath/include/pjnath/ice_strans.h | 65 | ||||
-rw-r--r-- | pjnath/src/pjnath/ice_strans.c | 36 | ||||
-rw-r--r-- | pjsip/include/pjsua-lib/pjsua_internal.h | 3 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_call.c | 22 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_media.c | 33 |
8 files changed, 234 insertions, 5 deletions
diff --git a/pjmedia/include/pjmedia/transport.h b/pjmedia/include/pjmedia/transport.h index 02105a7c..a6a6ff47 100644 --- a/pjmedia/include/pjmedia/transport.h +++ b/pjmedia/include/pjmedia/transport.h @@ -503,7 +503,7 @@ struct pjmedia_transport_info /** * Specifies number of transport specific info included. */ - int specific_info_cnt; + unsigned specific_info_cnt; /** * Buffer storage of transport specific info. diff --git a/pjmedia/include/pjmedia/transport_ice.h b/pjmedia/include/pjmedia/transport_ice.h index 349bddd9..0e7816fc 100644 --- a/pjmedia/include/pjmedia/transport_ice.h +++ b/pjmedia/include/pjmedia/transport_ice.h @@ -63,6 +63,52 @@ typedef struct pjmedia_ice_cb /** + * This structure specifies ICE transport specific info. This structure + * will be filled in media transport specific info. + */ +typedef struct pjmedia_ice_transport_info +{ + /** + * ICE sesion state. + */ + pj_ice_strans_state sess_state; + + /** + * Session role. + */ + pj_ice_sess_role role; + + /** + * Number of components in the component array. Before ICE negotiation + * is complete, the number represents the number of components of the + * local agent. After ICE negotiation has been completed successfully, + * the number represents the number of common components between local + * and remote agents. + */ + unsigned comp_cnt; + + /** + * Array of ICE components. Typically the first element denotes RTP and + * second element denotes RTCP. + */ + struct + { + /** + * Local candidate type. + */ + pj_ice_cand_type lcand_type; + + /** + * Remote candidate type. + */ + pj_ice_cand_type rcand_type; + + } comp[2]; + +} pjmedia_ice_transport_info; + + +/** * Options that can be specified when creating ICE transport. */ enum pjmedia_transport_ice_options diff --git a/pjmedia/src/pjmedia/transport_ice.c b/pjmedia/src/pjmedia/transport_ice.c index 7c36787c..7fd0133e 100644 --- a/pjmedia/src/pjmedia/transport_ice.c +++ b/pjmedia/src/pjmedia/transport_ice.c @@ -1473,6 +1473,38 @@ static pj_status_t transport_get_info(pjmedia_transport *tp, info->src_rtcp_name = tp_ice->rtcp_src_addr; } + /* Fill up transport specific info */ + if (info->specific_info_cnt < PJ_ARRAY_SIZE(info->spc_info)) { + pjmedia_transport_specific_info *tsi; + pjmedia_ice_transport_info *ii; + unsigned i; + + pj_assert(sizeof(*ii) <= sizeof(tsi->buffer)); + tsi = &info->spc_info[info->specific_info_cnt++]; + tsi->type = PJMEDIA_TRANSPORT_TYPE_ICE; + tsi->cbsize = sizeof(*ii); + + ii = (pjmedia_ice_transport_info*) tsi->buffer; + pj_bzero(ii, sizeof(*ii)); + + if (pj_ice_strans_has_sess(tp_ice->ice_st)) + ii->role = pj_ice_strans_get_role(tp_ice->ice_st); + else + ii->role = PJ_ICE_SESS_ROLE_UNKNOWN; + ii->sess_state = pj_ice_strans_get_state(tp_ice->ice_st); + ii->comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st); + + for (i=1; i<=ii->comp_cnt && i<=PJ_ARRAY_SIZE(ii->comp); ++i) { + const pj_ice_sess_check *chk; + + chk = pj_ice_strans_get_valid_pair(tp_ice->ice_st, i); + if (chk) { + ii->comp[i-1].lcand_type = chk->lcand->type; + ii->comp[i-1].rcand_type = chk->rcand->type; + } + } + } + return PJ_SUCCESS; } diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h index 28487870..c021dde7 100644 --- a/pjnath/include/pjnath/ice_strans.h +++ b/pjnath/include/pjnath/ice_strans.h @@ -327,6 +327,51 @@ typedef struct pj_ice_strans_cfg } pj_ice_strans_cfg; +/** + * ICE stream transport's state. + */ +typedef enum pj_ice_strans_state +{ + /** + * ICE stream transport is not created. + */ + PJ_ICE_STRANS_STATE_NULL, + + /** + * ICE candidate gathering process is in progress. + */ + PJ_ICE_STRANS_STATE_INIT, + + /** + * ICE stream transport initialization/candidate gathering process is + * complete, ICE session may be created on this stream transport. + */ + PJ_ICE_STRANS_STATE_READY, + + /** + * New session has been created and the session is ready. + */ + PJ_ICE_STRANS_STATE_SESS_READY, + + /** + * ICE negotiation is in progress. + */ + PJ_ICE_STRANS_STATE_NEGO, + + /** + * ICE negotiation has completed successfully and media is ready + * to be used. + */ + PJ_ICE_STRANS_STATE_RUNNING, + + /** + * ICE negotiation has completed with failure. + */ + PJ_ICE_STRANS_STATE_FAILED + +} pj_ice_strans_state; + + /** * Initialize ICE transport configuration with default values. * @@ -371,6 +416,26 @@ PJ_DECL(pj_status_t) pj_ice_strans_create(const char *name, pj_ice_strans **p_ice_st); /** + * Get ICE session state. + * + * @param ice_st The ICE stream transport. + * + * @return ICE session state. + */ +PJ_DECL(pj_ice_strans_state) pj_ice_strans_get_state(pj_ice_strans *ice_st); + + +/** + * Get string representation of ICE state. + * + * @param state ICE stream transport state. + * + * @return String. + */ +PJ_DECL(const char*) pj_ice_strans_state_name(pj_ice_strans_state state); + + +/** * Destroy the ICE stream transport. This will destroy the ICE session * inside the ICE stream transport, close all sockets and release all * other resources. diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c index 92f550d0..cf79ad9d 100644 --- a/pjnath/src/pjnath/ice_strans.c +++ b/pjnath/src/pjnath/ice_strans.c @@ -173,6 +173,7 @@ struct pj_ice_strans pj_ice_strans_cb cb; /**< Application callback. */ pj_lock_t *init_lock; /**< Initialization mutex. */ + pj_ice_strans_state state; /**< Session state. */ pj_ice_sess *ice; /**< ICE session. */ pj_time_val start_time;/**< Time when ICE was started */ @@ -488,6 +489,9 @@ PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name, ice_st->comp = (pj_ice_strans_comp**) pj_pool_calloc(pool, comp_cnt, sizeof(pj_ice_strans_comp*)); + /* Move state to candidate gathering */ + ice_st->state = PJ_ICE_STRANS_STATE_INIT; + /* Acquire initialization mutex to prevent callback to be * called before we finish initialization. */ @@ -561,6 +565,29 @@ static void destroy_ice_st(pj_ice_strans *ice_st) pj_pool_release(ice_st->pool); } +/* Get ICE session state. */ +PJ_DEF(pj_ice_strans_state) pj_ice_strans_get_state(pj_ice_strans *ice_st) +{ + return ice_st->state; +} + +/* State string */ +PJ_DEF(const char*) pj_ice_strans_state_name(pj_ice_strans_state state) +{ + const char *names[] = { + "Null", + "Candidate Gathering", + "Candidate Gathering Complete", + "Session Initialized", + "Negotiation In Progress", + "Negotiation Success", + "Negotiation Failed" + }; + + PJ_ASSERT_RETURN(state <= PJ_ICE_STRANS_STATE_FAILED, "???"); + return names[state]; +} + /* Notification about failure */ static void sess_fail(pj_ice_strans *ice_st, pj_ice_strans_op op, const char *title, pj_status_t status) @@ -603,6 +630,7 @@ static void sess_init_update(pj_ice_strans *ice_st) /* All candidates have been gathered */ ice_st->cb_called = PJ_TRUE; + ice_st->state = PJ_ICE_STRANS_STATE_READY; if (ice_st->cb.on_ice_complete) (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_INIT, PJ_SUCCESS); @@ -782,6 +810,9 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st, } } + /* ICE session is ready for negotiation */ + ice_st->state = PJ_ICE_STRANS_STATE_SESS_READY; + return PJ_SUCCESS; on_error: @@ -982,6 +1013,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_start_ice( pj_ice_strans *ice_st, return status; } + ice_st->state = PJ_ICE_STRANS_STATE_NEGO; return status; } @@ -1011,6 +1043,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st) ice_st->ice = NULL; } + ice_st->state = PJ_ICE_STRANS_STATE_INIT; return PJ_SUCCESS; } @@ -1169,6 +1202,9 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status) } } + ice_st->state = (status==PJ_SUCCESS) ? PJ_ICE_STRANS_STATE_RUNNING : + PJ_ICE_STRANS_STATE_FAILED; + (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION, status); diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index d165bf3c..e4691868 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -82,6 +82,9 @@ typedef struct pjsua_call pjmedia_transport *med_orig; /**< Original media transport */ pj_bool_t med_tp_auto_del; /**< May delete media transport */ pjsua_med_tp_st med_tp_st; /**< Media transport state */ + pj_sockaddr med_rtp_addr; /**< Current RTP source address + (used to update ICE default + address) */ pj_stun_nat_type rem_nat_type; /**< NAT type of remote endpoint. */ pjmedia_srtp_use rem_srtp_use; /**< Remote's SRTP usage policy. */ diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index a845940c..06cddb5b 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -2829,11 +2829,11 @@ PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id, *p = '\0'; } - /* Get SRTP status */ + /* Get and ICE SRTP status */ pjmedia_transport_info_init(&tp_info); pjmedia_transport_get_info(call->med_tp, &tp_info); if (tp_info.specific_info_cnt > 0) { - int i; + unsigned i; for (i = 0; i < tp_info.specific_info_cnt; ++i) { if (tp_info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP) { @@ -2850,7 +2850,23 @@ PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id, *p++ = '\n'; *p = '\0'; } - break; + } else if (tp_info.spc_info[i].type==PJMEDIA_TRANSPORT_TYPE_ICE) { + const pjmedia_ice_transport_info *ii; + + ii = (const pjmedia_ice_transport_info*) + tp_info.spc_info[i].buffer; + + len = pj_ansi_snprintf(p, end-p, + "%s ICE role: %s, state: %s, comp_cnt: %u", + indent, + pj_ice_sess_role_name(ii->role), + pj_ice_strans_state_name(ii->sess_state), + ii->comp_cnt); + if (len > 0 && len < end-p) { + p += len; + *p++ = '\n'; + *p = '\0'; + } } } } diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 01f33a1c..fff917ba 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -821,6 +821,33 @@ static void on_ice_complete(pjmedia_transport *tp, if (pjsua_var.ua_cfg.cb.on_call_media_state) { pjsua_var.ua_cfg.cb.on_call_media_state(id); } + } else { + /* Send UPDATE if default transport address is different than + * what was advertised (ticket #881) + */ + pjmedia_transport_info tpinfo; + pjmedia_ice_transport_info *ii = NULL; + unsigned i; + + pjmedia_transport_info_init(&tpinfo); + pjmedia_transport_get_info(tp, &tpinfo); + for (i=0; i<tpinfo.specific_info_cnt; ++i) { + if (tpinfo.spc_info[i].type==PJMEDIA_TRANSPORT_TYPE_ICE) { + ii = (pjmedia_ice_transport_info*) + tpinfo.spc_info[i].buffer; + break; + } + } + + if (ii && ii->role==PJ_ICE_SESS_ROLE_CONTROLLING && + pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name, + &pjsua_var.calls[id].med_rtp_addr)) + { + PJ_LOG(4,(THIS_FILE, + "ICE default transport address has changed for " + "call %d, sending UPDATE", id)); + pjsua_call_update(id, 0, NULL); + } } break; } @@ -1320,6 +1347,10 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, return status; } + /* Update currently advertised RTP source address */ + pj_memcpy(&call->med_rtp_addr, &tpinfo.sock_info.rtp_addr_name, + sizeof(pj_sockaddr)); + *p_sdp = sdp; return PJ_SUCCESS; } @@ -1482,7 +1513,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, pjmedia_transport_info_init(&tp_info); pjmedia_transport_get_info(call->med_tp, &tp_info); if (tp_info.specific_info_cnt > 0) { - int i; + unsigned i; for (i = 0; i < tp_info.specific_info_cnt; ++i) { if (tp_info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP) { |