Index: /pjproject/trunk/pjmedia/include/pjmedia/transport.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 2944)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 2945)
@@ -504,5 +504,5 @@
      * Specifies number of transport specific info included.
      */
-    int specific_info_cnt;
+    unsigned specific_info_cnt;
 
     /**
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h	(revision 2944)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h	(revision 2945)
@@ -61,4 +61,50 @@
 
 } 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;
 
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 2944)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 2945)
@@ -1474,4 +1474,36 @@
     }
 
+    /* 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;
 }
Index: /pjproject/trunk/pjnath/include/pjnath/ice_strans.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/ice_strans.h	(revision 2944)
+++ /pjproject/trunk/pjnath/include/pjnath/ice_strans.h	(revision 2945)
@@ -328,4 +328,49 @@
 
 
+/**
+ * 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.
@@ -370,4 +415,24 @@
 					  const pj_ice_strans_cb *cb,
 					  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);
+
 
 /**
Index: /pjproject/trunk/pjnath/src/pjnath/ice_strans.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 2944)
+++ /pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 2945)
@@ -174,4 +174,5 @@
     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,4 +489,7 @@
     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 
@@ -562,4 +566,27 @@
 }
 
+/* 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,
@@ -604,4 +631,5 @@
     /* 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, 
@@ -783,4 +811,7 @@
     }
 
+    /* ICE session is ready for negotiation */
+    ice_st->state = PJ_ICE_STRANS_STATE_SESS_READY;
+
     return PJ_SUCCESS;
 
@@ -983,4 +1014,5 @@
     }
 
+    ice_st->state = PJ_ICE_STRANS_STATE_NEGO;
     return status;
 }
@@ -1012,4 +1044,5 @@
     }
 
+    ice_st->state = PJ_ICE_STRANS_STATE_INIT;
     return PJ_SUCCESS;
 }
@@ -1170,4 +1203,7 @@
 	}
 
+	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);
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 2944)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 2945)
@@ -83,4 +83,7 @@
     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.	    */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 2944)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 2945)
@@ -2830,9 +2830,9 @@
     }
 
-    /* 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) 
@@ -2851,5 +2851,21 @@
 		    *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';
+		}
 	    }
 	}
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2944)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2945)
@@ -822,4 +822,31 @@
 		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;
@@ -1321,4 +1348,8 @@
     }
 
+    /* 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;
@@ -1483,5 +1514,5 @@
 	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) 
