summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjmedia/include/pjmedia/transport.h2
-rw-r--r--pjmedia/include/pjmedia/transport_ice.h46
-rw-r--r--pjmedia/src/pjmedia/transport_ice.c32
-rw-r--r--pjnath/include/pjnath/ice_strans.h65
-rw-r--r--pjnath/src/pjnath/ice_strans.c36
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h3
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c22
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c33
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)
{