Index: pjproject/branches/projects/sipit24/pjnath/include/pjnath/config.h
===================================================================
--- pjproject/branches/projects/sipit24/pjnath/include/pjnath/config.h	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjnath/include/pjnath/config.h	(revision 2705)
@@ -325,4 +325,37 @@
 
 /**
+ * For a controlled agent, specify how long it wants to wait (in milliseconds)
+ * for the controlling agent to complete sending connectivity check with
+ * nominated flag set to true for all components after the controlled agent
+ * has found that all connectivity checks in its checklist have been completed
+ * and there is at least one successful (but not nominated) check for every
+ * component.
+ *
+ * When selecting the value, bear in mind that the connectivity check from
+ * controlling agent may be delayed because of delay in receiving SDP answer
+ * from the controlled agent.
+ *
+ * Application may set this value to -1 to disable this timer.
+ *
+ * Default: 10000 (milliseconds)
+ */
+#ifndef ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT
+#   define ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT	10000
+#endif
+
+
+/**
+ * For controlling agent if it uses regular nomination, specify the delay to
+ * perform nominated check (connectivity check with USE-CANDIDATE attribute)
+ * after all components have a valid pair.
+ *
+ * Default: 4*PJ_STUN_RTO_VALUE (milliseconds)
+ */
+#ifndef PJ_ICE_NOMINATED_CHECK_DELAY
+#   define PJ_ICE_NOMINATED_CHECK_DELAY		    (4*PJ_STUN_RTO_VALUE)
+#endif
+
+
+/**
  * Minimum interval value to be used for sending STUN keep-alive on the ICE
  * stream transport, in seconds. This minimum interval, plus a random value
Index: pjproject/branches/projects/sipit24/pjnath/include/pjnath/errno.h
===================================================================
--- pjproject/branches/projects/sipit24/pjnath/include/pjnath/errno.h	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjnath/include/pjnath/errno.h	(revision 2705)
@@ -197,5 +197,10 @@
  */
 #define PJNATH_EICENOHOSTCAND	    (PJNATH_ERRNO_START+92) /* 370092 */
-
+/**
+ * @hideinitializer
+ * Controlled agent timed-out in waiting for the controlling agent to 
+ * send nominated check after all connectivity checks have completed.
+ */
+#define PJNATH_EICENOMTIMEOUT	    (PJNATH_ERRNO_START+93) /* 370093 */
 
 /************************************************************
Index: pjproject/branches/projects/sipit24/pjnath/include/pjnath/ice_session.h
===================================================================
--- pjproject/branches/projects/sipit24/pjnath/include/pjnath/ice_session.h	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjnath/include/pjnath/ice_session.h	(revision 2705)
@@ -177,9 +177,16 @@
 {
     /**
-     * The pointer to ICE check which was nominated for this component.
-     * The value will be NULL if a nominated check has not been found
-     * for this component.
+     * Pointer to ICE check with highest priority which connectivity check
+     * has been successful. The value will be NULL if a no successful check
+     * has not been found for this component.
      */
     pj_ice_sess_check	*valid_check;
+
+    /**
+     * Pointer to ICE check with highest priority which connectivity check
+     * has been successful and it has been nominated. The value may be NULL
+     * if there is no such check yet.
+     */
+    pj_ice_sess_check	*nominated_check;
 
     /**
@@ -554,4 +561,42 @@
 
 /**
+ * This structure describes various ICE session options. Application
+ * configure the ICE session with these options by calling 
+ * #pj_ice_sess_set_options().
+ */
+typedef struct pj_ice_sess_options
+{
+    /**
+     * Specify whether to use aggressive nomination.
+     */
+    pj_bool_t		aggressive;
+
+    /**
+     * For controlling agent if it uses regular nomination, specify the delay
+     * to perform nominated check (connectivity check with USE-CANDIDATE 
+     * attribute) after all components have a valid pair.
+     *
+     * Default value is PJ_ICE_NOMINATED_CHECK_DELAY.
+     */
+    unsigned		nominated_check_delay;
+
+    /**
+     * For a controlled agent, specify how long it wants to wait (in 
+     * milliseconds) for the controlling agent to complete sending 
+     * connectivity check with nominated flag set to true for all components
+     * after the controlled agent has found that all connectivity checks in
+     * its checklist have been completed and there is at least one successful
+     * (but not nominated) check for every component.
+     *
+     * Default value for this option is 
+     * ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT. Specify -1 to disable
+     * this timer.
+     */
+    int			controlled_agent_want_nom_timeout;
+
+} pj_ice_sess_options;
+
+
+/**
  * This structure describes the ICE session. For this version of PJNATH,
  * an ICE session corresponds to a single media stream (unlike the ICE
@@ -570,9 +615,11 @@
     pj_mutex_t		*mutex;			    /**< Mutex.		    */
     pj_ice_sess_role	 role;			    /**< ICE role.	    */
+    pj_ice_sess_options	 opt;			    /**< Options	    */
     pj_timestamp	 tie_breaker;		    /**< Tie breaker value  */
     pj_uint8_t		*prefs;			    /**< Type preference.   */
+    pj_bool_t		 is_nominating;		    /**< Nominating stage   */
     pj_bool_t		 is_complete;		    /**< Complete?	    */
     pj_status_t		 ice_status;		    /**< Error status.	    */
-    pj_timer_entry	 completion_timer;	    /**< To call callback.  */
+    pj_timer_entry	 timer;			    /**< ICE timer.	    */
     pj_ice_sess_cb	 cb;			    /**< Callback.	    */
 
@@ -655,4 +702,10 @@
 				     const pj_sockaddr *base_addr);
 
+/**
+ * Initialize ICE session options with library default values.
+ *
+ * @param opt		ICE session options.
+ */
+PJ_DECL(void) pj_ice_sess_options_default(pj_ice_sess_options *opt);
 
 /**
@@ -690,4 +743,32 @@
 
 /**
+ * Get the value of various options of the ICE session.
+ *
+ * @param ice		The ICE session.
+ * @param opt		The options to be initialized with the values
+ *			from the ICE session.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_get_options(pj_ice_sess *ice,
+					     pj_ice_sess_options *opt);
+
+/**
+ * Specify various options for this ICE session. Application MUST only
+ * call this function after the ICE session has been created but before
+ * any connectivity check is started.
+ *
+ * Application should call #pj_ice_sess_get_options() to initialize the
+ * options with their default values.
+ *
+ * @param ice		The ICE session.
+ * @param opt		Options to be applied to the ICE session.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_set_options(pj_ice_sess *ice,
+					     const pj_ice_sess_options *opt);
+
+/**
  * Destroy ICE session. This will cancel any connectivity checks currently
  * running, if any, and any other events scheduled by this session, as well
Index: pjproject/branches/projects/sipit24/pjnath/include/pjnath/ice_strans.h
===================================================================
--- pjproject/branches/projects/sipit24/pjnath/include/pjnath/ice_strans.h	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjnath/include/pjnath/ice_strans.h	(revision 2705)
@@ -210,10 +210,10 @@
 
 	/**
-	 * Disable host candidates. When this option is set, no
-	 * host candidates will be added.
-	 *
-	 * Default: PJ_FALSE
-	 */
-	pj_bool_t	     no_host_cands;
+	 * Maximum number of host candidates to be added. If the
+	 * value is zero, no host candidates will be added.
+	 *
+	 * Default: 64
+	 */
+	unsigned	     max_host_cands;
 
 	/**
@@ -384,4 +384,30 @@
  */
 PJ_DECL(void*) pj_ice_strans_get_user_data(pj_ice_strans *ice_st);
+
+
+/**
+ * Get the value of various options of the ICE stream transport.
+ *
+ * @param ice_st	The ICE stream transport.
+ * @param opt		The options to be initialized with the values
+ *			from the ICE stream transport.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pj_ice_strans_get_options(pj_ice_strans *ice_st,
+					       pj_ice_sess_options *opt);
+
+/**
+ * Specify various options for this ICE stream transport. Application 
+ * should call #pj_ice_strans_get_options() to initialize the options 
+ * with their default values.
+ *
+ * @param ice_st	The ICE stream transport.
+ * @param opt		Options to be applied to this ICE stream transport.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pj_ice_strans_set_options(pj_ice_strans *ice_st,
+					       const pj_ice_sess_options *opt);
 
 
Index: pjproject/branches/projects/sipit24/pjnath/src/pjnath-test/ice_test.c
===================================================================
--- pjproject/branches/projects/sipit24/pjnath/src/pjnath-test/ice_test.c	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjnath/src/pjnath-test/ice_test.c	(revision 2705)
@@ -142,7 +142,7 @@
 
     if (ept->cfg.enable_host == 0) {
-	ice_cfg.stun.no_host_cands = PJ_TRUE;
+	ice_cfg.stun.max_host_cands = 0;
     } else {
-	ice_cfg.stun.no_host_cands = PJ_FALSE;
+	//ice_cfg.stun.no_host_cands = PJ_FALSE;
 	ice_cfg.stun.loop_addr = PJ_TRUE;
     }
Index: pjproject/branches/projects/sipit24/pjnath/src/pjnath/errno.c
===================================================================
--- pjproject/branches/projects/sipit24/pjnath/src/pjnath/errno.c	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjnath/src/pjnath/errno.c	(revision 2705)
@@ -68,4 +68,5 @@
     PJ_BUILD_ERR( PJNATH_EICEINCANDSDP,	    "Invalid SDP \"candidate\" attribute"),
     PJ_BUILD_ERR( PJNATH_EICENOHOSTCAND,    "No host candidate associated with srflx"),
+    PJ_BUILD_ERR( PJNATH_EICENOMTIMEOUT,    "Controlled agent timed out waiting for nomination"),
 
     /* TURN related errors */
Index: pjproject/branches/projects/sipit24/pjnath/src/pjnath/ice_session.c
===================================================================
--- pjproject/branches/projects/sipit24/pjnath/src/pjnath/ice_session.c	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjnath/src/pjnath/ice_session.c	(revision 2705)
@@ -67,4 +67,18 @@
 };
 
+typedef enum timer_type
+{
+    TIMER_NONE,			/**< Timer not active			*/
+    TIMER_COMPLETION_CALLBACK,	/**< Call on_ice_complete() callback    */
+    TIMER_CONTROLLED_WAIT_NOM,	/**< Controlled agent is waiting for 
+				     controlling agent to send connectivity
+				     check with nominated flag after it has
+				     valid check for every components.	*/
+    TIMER_START_NOMINATED_CHECK,/**< Controlling agent start connectivity
+				     checks with USE-CANDIDATE flag.	*/
+					
+
+};
+
 /* Candidate type preference */
 static pj_uint8_t cand_type_prefs[4] =
@@ -119,8 +133,11 @@
 
 /* Forward declarations */
+static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te);
+static void on_ice_complete(pj_ice_sess *ice, pj_status_t status);
 static void destroy_ice(pj_ice_sess *ice,
 			pj_status_t reason);
 static pj_status_t start_periodic_check(pj_timer_heap_t *th, 
 					pj_timer_entry *te);
+static void start_nominated_check(pj_ice_sess *ice);
 static void periodic_timer(pj_timer_heap_t *th, 
 			  pj_timer_entry *te);
@@ -297,4 +314,13 @@
 
 
+/* Init options with default values */
+PJ_DEF(void) pj_ice_sess_options_default(pj_ice_sess_options *opt)
+{
+    opt->aggressive = PJ_TRUE;
+    opt->nominated_check_delay = PJ_ICE_NOMINATED_CHECK_DELAY;
+    opt->controlled_agent_want_nom_timeout = 
+	ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT;
+}
+
 /*
  * Create ICE session.
@@ -327,4 +353,7 @@
     ice->tie_breaker.u32.lo = pj_rand();
     ice->prefs = cand_type_prefs;
+    pj_ice_sess_options_default(&ice->opt);
+
+    pj_timer_entry_init(&ice->timer, TIMER_NONE, (void*)ice, &on_timer);
 
     pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
@@ -346,4 +375,5 @@
 	comp = &ice->comp[i];
 	comp->valid_check = NULL;
+	comp->nominated_check = NULL;
 
 	status = init_comp(ice, i+1, comp);
@@ -390,4 +420,27 @@
 
 /*
+ * Get the value of various options of the ICE session.
+ */
+PJ_DEF(pj_status_t) pj_ice_sess_get_options(pj_ice_sess *ice,
+					    pj_ice_sess_options *opt)
+{
+    PJ_ASSERT_RETURN(ice, PJ_EINVAL);
+    pj_memcpy(opt, &ice->opt, sizeof(*opt));
+    return PJ_SUCCESS;
+}
+
+/*
+ * Specify various options for this ICE session.
+ */
+PJ_DEF(pj_status_t) pj_ice_sess_set_options(pj_ice_sess *ice,
+					    const pj_ice_sess_options *opt)
+{
+    PJ_ASSERT_RETURN(ice && opt, PJ_EINVAL);
+    pj_memcpy(&ice->opt, opt, sizeof(*opt));
+    return PJ_SUCCESS;
+}
+
+
+/*
  * Destroy
  */
@@ -407,8 +460,8 @@
     }
 
-    if (ice->completion_timer.id) {
+    if (ice->timer.id) {
 	pj_timer_heap_cancel(ice->stun_cfg.timer_heap, 
-			     &ice->completion_timer);
-	ice->completion_timer.id = PJ_FALSE;
+			     &ice->timer);
+	ice->timer.id = PJ_FALSE;
     }
 
@@ -1040,16 +1093,29 @@
 }
 
-/* Timer callback to call on_ice_complete() callback */
-static void on_completion_timer(pj_timer_heap_t *th, 
-			        pj_timer_entry *te)
+/* Timer callback */
+static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te)
 {
     pj_ice_sess *ice = (pj_ice_sess*) te->user_data;
+    enum timer_time type = (enum timer_type)te->id;
 
     PJ_UNUSED_ARG(th);
 
-    te->id = PJ_FALSE;
-
-    if (ice->cb.on_ice_complete)
-	(*ice->cb.on_ice_complete)(ice, ice->ice_status);
+    te->id = TIMER_NONE;
+
+    switch (type) {
+    case TIMER_CONTROLLED_WAIT_NOM:
+	LOG4((ice->obj_name, 
+	      "Controlled agent timed-out in waiting for the controlling "
+	      "agent to send nominated check. Setting state to fail now.."));
+	on_ice_complete(ice, PJNATH_EICENOMTIMEOUT);
+	break;
+    case TIMER_COMPLETION_CALLBACK:
+	if (ice->cb.on_ice_complete)
+	    (*ice->cb.on_ice_complete)(ice, ice->ice_status);
+	break;
+    case TIMER_START_NOMINATED_CHECK:
+	start_nominated_check(ice);
+	break;
+    }
 }
 
@@ -1061,4 +1127,9 @@
 	ice->ice_status = status;
     
+	if (ice->timer.id != TIMER_NONE) {
+	    pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
+	    ice->timer.id = TIMER_NONE;
+	}
+
 	/* Log message */
 	LOG4((ice->obj_name, "ICE process complete, status=%s", 
@@ -1072,11 +1143,7 @@
 	    pj_time_val delay = {0, 0};
 
-	    ice->completion_timer.cb = &on_completion_timer;
-	    ice->completion_timer.user_data = (void*) ice;
-	    ice->completion_timer.id = PJ_TRUE;
-
+	    ice->timer.id = TIMER_COMPLETION_CALLBACK;
 	    pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
-				   &ice->completion_timer,
-				   &delay);
+				   &ice->timer, &delay);
 	}
     }
@@ -1088,7 +1155,10 @@
 				   pj_ice_sess_check *check)
 {
+    pj_ice_sess_comp *comp;
     unsigned i;
 
     pj_assert(check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
+
+    comp = find_comp(ice, check->lcand->comp_id);
 
     /* 7.1.2.2.2.  Updating Pair States
@@ -1105,4 +1175,5 @@
      */
     if (check->err_code==PJ_SUCCESS) {
+
 	for (i=0; i<ice->clist.count; ++i) {
 	    pj_ice_sess_check *c = &ice->clist.checks[i];
@@ -1113,4 +1184,17 @@
 	    }
 	}
+
+	/* Update valid check */
+	if (comp->valid_check == NULL) {
+	    comp->valid_check = check;
+	} else {
+	    if (CMP_CHECK_PRIO(comp->valid_check, check) < 0)
+		comp->valid_check = check;
+	}
+
+	LOG5((ice->obj_name, "Check %d is successful%s",
+	     GET_CHECK_ID(&ice->clist, check),
+	     (check->nominated ? "  and nominated" : "")));
+
     }
 
@@ -1137,10 +1221,4 @@
      */
     if (check->err_code==PJ_SUCCESS && check->nominated) {
-	pj_ice_sess_comp *comp;
-
-	LOG5((ice->obj_name, "Check %d is successful and nominated",
-	     GET_CHECK_ID(&ice->clist, check)));
-
-	comp = find_comp(ice, check->lcand->comp_id);
 
 	for (i=0; i<ice->clist.count; ++i) {
@@ -1182,9 +1260,9 @@
 
 	/* Update the nominated check for the component */
-	if (comp->valid_check == NULL) {
-	    comp->valid_check = check;
+	if (comp->nominated_check == NULL) {
+	    comp->nominated_check = check;
 	} else {
-	    if (CMP_CHECK_PRIO(comp->valid_check, check) < 0)
-		comp->valid_check = check;
+	    if (CMP_CHECK_PRIO(comp->nominated_check, check) < 0)
+		comp->nominated_check = check;
 	}
     }
@@ -1212,5 +1290,5 @@
      */
     for (i=0; i<ice->comp_cnt; ++i) {
-	if (ice->comp[i].valid_check == NULL)
+	if (ice->comp[i].nominated_check == NULL)
 	    break;
     }
@@ -1259,21 +1337,14 @@
 	 * If agent's role is controlled, check if all components have
 	 * valid pair. If it does, this means the controlled agent has
-	 * finished the check list early and it's waiting for controlling
-	 * agent to send a check with USE-CANDIDATE flag set.
+	 * finished the check list and it's waiting for controlling
+	 * agent to send checks with USE-CANDIDATE flag set.
 	 */
 	if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED) {
-	    unsigned comp_id;
-	    for (comp_id=1; comp_id <= ice->comp_cnt; ++comp_id) {
-		unsigned j;
-		for (j=0; j<ice->valid_list.count; ++j) {
-		    pj_ice_sess_check *vc = &ice->valid_list.checks[j];
-		    if (vc->lcand->comp_id == comp_id)
-			break;
-		}
-		if (j == ice->valid_list.count)
+	    for (i=0; i < ice->comp_cnt; ++i) {
+		if (ice->comp[i].valid_check == NULL)
 		    break;
 	    }
 
-	    if (comp_id <= ice->comp_cnt) {
+	    if (i < ice->comp_cnt) {
 		/* This component ID doesn't have valid pair.
 		 * Mark ICE as failed. 
@@ -1285,10 +1356,102 @@
 		 * We should wait until we receive nominated checks.
 		 */
+		if (ice->timer.id == TIMER_NONE &&
+		    ice->opt.controlled_agent_want_nom_timeout >= 0) 
+		{
+		    pj_time_val delay;
+
+		    delay.sec = 0;
+		    delay.msec = ice->opt.controlled_agent_want_nom_timeout;
+		    pj_time_val_normalize(&delay);
+
+		    ice->timer.id = TIMER_CONTROLLED_WAIT_NOM;
+		    pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
+					   &ice->timer,
+					   &delay);
+
+		    LOG5((ice->obj_name, 
+			  "All checks have completed. Controlled agent now "
+			  "waits for nomination from controlling agent "
+			  "(timeout=%d msec)",
+			  ice->opt.controlled_agent_want_nom_timeout));
+		}
 		return PJ_FALSE;
 	    }
-	}
-
-	on_ice_complete(ice, PJNATH_EICEFAILED);
-	return PJ_TRUE;
+
+	    /* Unreached */
+
+	} else if (ice->is_nominating) {
+	    /* We are controlling agent and all checks have completed but
+	     * there's at least one component without nominated pair (or
+	     * more likely we don't have any nominated pairs at all).
+	     */
+	    on_ice_complete(ice, PJNATH_EICEFAILED);
+	    return PJ_TRUE;
+
+	} else {
+	    /* We are controlling agent and all checks have completed. If
+	     * we have valid list for every component, then move on to
+	     * sending nominated check, otherwise we have failed.
+	     */
+	    for (i=0; i<ice->comp_cnt; ++i) {
+		if (ice->comp[i].valid_check == NULL)
+		    break;
+	    }
+
+	    if (i < ice->comp_cnt) {
+		/* At least one component doesn't have a valid check. Mark
+		 * ICE as failed.
+		 */
+		on_ice_complete(ice, PJNATH_EICEFAILED);
+		return PJ_TRUE;
+	    }
+
+	    /* Now it's time to send connectivity check with nomination 
+	     * flag set.
+	     */
+	    LOG5((ice->obj_name, 
+		  "All checks have completed, starting nominated checks now"));
+	    start_nominated_check(ice);
+	    return PJ_FALSE;
+	}
+    }
+
+    /* If this connectivity check has been successful, scan all components
+     * and see if they have a valid pair, if we are controlling and we haven't
+     * started our nominated check yet.
+     */
+    if (check->err_code == PJ_SUCCESS && 
+	ice->role==PJ_ICE_SESS_ROLE_CONTROLLING &&
+	!ice->is_nominating &&
+	ice->timer.id == TIMER_NONE) 
+    {
+	pj_time_val delay;
+
+	for (i=0; i<ice->comp_cnt; ++i) {
+	    if (ice->comp[i].valid_check == NULL)
+		break;
+	}
+
+	if (i < ice->comp_cnt) {
+	    /* Some components still don't have valid pair, continue
+	     * processing.
+	     */
+	    return PJ_FALSE;
+	}
+
+	LOG5((ice->obj_name, 
+	      "Scheduling nominated check in %d ms",
+	      ice->opt.nominated_check_delay));
+
+	/* All components have valid pair. Let connectivity checks run for
+	 * a little bit more time, then start our nominated check.
+	 */
+	delay.sec = 0;
+	delay.msec = ice->opt.nominated_check_delay;
+	pj_time_val_normalize(&delay);
+
+	ice->timer.id = TIMER_START_NOMINATED_CHECK;
+	pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay);
+	return PJ_FALSE;
     }
 
@@ -1296,5 +1459,4 @@
     return PJ_FALSE;
 }
-
 
 
@@ -1431,8 +1593,9 @@
 }
 
-/* Perform check on the specified candidate pair */
+/* Perform check on the specified candidate pair. */
 static pj_status_t perform_check(pj_ice_sess *ice, 
 				 pj_ice_sess_checklist *clist,
-				 unsigned check_id)
+				 unsigned check_id,
+				 pj_bool_t nominate)
 {
     pj_ice_sess_comp *comp;
@@ -1482,7 +1645,9 @@
      */
     if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
-	pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg, 
-				   PJ_STUN_ATTR_USE_CANDIDATE);
-	check->nominated = PJ_TRUE;
+	if (nominate) {
+	    pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg,
+				       PJ_STUN_ATTR_USE_CANDIDATE);
+	    check->nominated = PJ_TRUE;
+	}
 
 	pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, 
@@ -1550,5 +1715,5 @@
 
 	if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) {
-	    status = perform_check(ice, clist, i);
+	    status = perform_check(ice, clist, i, ice->is_nominating);
 	    if (status != PJ_SUCCESS) {
 		pj_mutex_unlock(ice->mutex);
@@ -1569,5 +1734,5 @@
 
 	    if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
-		status = perform_check(ice, clist, i);
+		status = perform_check(ice, clist, i, ice->is_nominating);
 		if (status != PJ_SUCCESS) {
 		    pj_mutex_unlock(ice->mutex);
@@ -1596,4 +1761,47 @@
 }
 
+
+/* Start sending connectivity check with USE-CANDIDATE */
+static void start_nominated_check(pj_ice_sess *ice)
+{
+    pj_time_val delay;
+    unsigned i;
+    pj_status_t status;
+
+    LOG4((ice->obj_name, "Starting nominated check.."));
+
+    pj_assert(ice->is_nominating == PJ_FALSE);
+
+    /* Stop our timer if it's active */
+    if (ice->timer.id == TIMER_START_NOMINATED_CHECK) {
+	pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
+	ice->timer.id = TIMER_NONE;
+    }
+
+    /* For each component, set the check state of valid check with
+     * highest priority to Waiting (it should have Success state now).
+     */
+    for (i=0; i<ice->comp_cnt; ++i) {
+	pj_assert(ice->comp[i].nominated_check == NULL);
+	pj_assert(ice->comp[i].valid_check->err_code == PJ_SUCCESS);
+
+	ice->comp[i].valid_check->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
+	check_set_state(ice, ice->comp[i].valid_check, 
+			PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
+    }
+
+    /* And (re)start the periodic check */
+    if (!ice->clist.timer.id) {
+	ice->clist.timer.id = PJ_TRUE;
+	delay.sec = delay.msec = 0;
+	status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
+					&ice->clist.timer, &delay);
+	if (status != PJ_SUCCESS) {
+	    ice->clist.timer.id = PJ_FALSE;
+	}
+    }
+
+    ice->is_nominating = PJ_TRUE;
+}
 
 /* Timer callback to perform periodic check */
@@ -1642,4 +1850,8 @@
 
     LOG4((ice->obj_name, "Starting ICE check.."));
+
+    /* If we are using aggressive nomination, set the is_nominating state */
+    if (ice->opt.aggressive)
+	ice->is_nominating = PJ_TRUE;
 
     /* The agent examines the check list for the first media stream (a
@@ -1827,5 +2039,6 @@
 	    LOG4((ice->obj_name, "Resending check because of role conflict"));
 	    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
-	    perform_check(ice, clist, msg_data->data.req.ckid);
+	    perform_check(ice, clist, msg_data->data.req.ckid, 
+			  check->nominated);
 	    pj_mutex_unlock(ice->mutex);
 	    return;
@@ -2313,6 +2526,9 @@
 	    c->state == PJ_ICE_SESS_CHECK_STATE_WAITING)
 	{
+	    /* See if we shall nominate this check */
+	    pj_bool_t nominate = (c->nominated || ice->is_nominating);
+
 	    LOG5((ice->obj_name, "Performing triggered check for check %d",i));
-	    perform_check(ice, &ice->clist, i);
+	    perform_check(ice, &ice->clist, i, nominate);
 
 	} else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
@@ -2362,4 +2578,5 @@
 
 	pj_ice_sess_check *c = &ice->clist.checks[ice->clist.count];
+	pj_bool_t nominate;
 
 	c->lcand = lcand;
@@ -2370,7 +2587,9 @@
 	c->err_code = PJ_SUCCESS;
 
+	nominate = (c->nominated || ice->is_nominating);
+
 	LOG4((ice->obj_name, "New triggered check added: %d", 
 	     ice->clist.count));
-	perform_check(ice, &ice->clist, ice->clist.count++);
+	perform_check(ice, &ice->clist, ice->clist.count++, nominate);
 
     } else {
Index: pjproject/branches/projects/sipit24/pjnath/src/pjnath/ice_strans.c
===================================================================
--- pjproject/branches/projects/sipit24/pjnath/src/pjnath/ice_strans.c	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjnath/src/pjnath/ice_strans.c	(revision 2705)
@@ -159,4 +159,5 @@
     pj_ice_strans_cb	     cb;	/**< Application callback.	*/
     pj_lock_t		    *init_lock; /**< Initialization mutex.	*/
+    pj_ice_sess_options	     opt;	/**< ICE session options	*/
 
     pj_ice_sess		    *ice;	/**< ICE session.		*/
@@ -201,4 +202,6 @@
     cfg->stun.port = PJ_STUN_PORT;
     cfg->turn.conn_type = PJ_TURN_TP_UDP;
+
+    cfg->stun.max_host_cands = 64;
 }
 
@@ -246,5 +249,5 @@
 
     /* Create STUN transport if configured */
-    if (ice_st->cfg.stun.server.slen || !ice_st->cfg.stun.no_host_cands) {
+    if (ice_st->cfg.stun.server.slen || ice_st->cfg.stun.max_host_cands) {
 	pj_stun_sock_cb stun_sock_cb;
 	pj_ice_sess_cand *cand;
@@ -310,8 +313,8 @@
 	}
 
-	/* Add local addresses to host candidates, unless no_host_cands
-	 * flag is set.
+	/* Add local addresses to host candidates, unless max_host_cands
+	 * is set to zero.
 	 */
-	if (ice_st->cfg.stun.no_host_cands == PJ_FALSE) {
+	if (ice_st->cfg.stun.max_host_cands) {
 	    pj_stun_sock_info stun_sock_info;
 	    unsigned i;
@@ -322,5 +325,7 @@
 		return status;
 
-	    for (i=0; i<stun_sock_info.alias_cnt; ++i) {
+	    for (i=0; i<stun_sock_info.alias_cnt && 
+		      i<ice_st->cfg.stun.max_host_cands; ++i) 
+	    {
 		char addrinfo[PJ_INET6_ADDRSTRLEN+10];
 		const pj_sockaddr *addr = &stun_sock_info.aliases[i];
@@ -444,4 +449,6 @@
     ice_st->obj_name = pool->obj_name;
     ice_st->user_data = user_data;
+
+    pj_ice_sess_options_default(&ice_st->opt);
 
     PJ_LOG(4,(ice_st->obj_name, 
@@ -648,4 +655,28 @@
 
 /*
+ * Get the value of various options of the ICE stream transport.
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_get_options( pj_ice_strans *ice_st,
+					       pj_ice_sess_options *opt)
+{
+    PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
+    pj_memcpy(opt, &ice_st->opt, sizeof(*opt));
+    return PJ_SUCCESS;
+}
+
+/*
+ * Specify various options for this ICE stream transport. 
+ */
+PJ_DEF(pj_status_t) pj_ice_strans_set_options(pj_ice_strans *ice_st,
+					      const pj_ice_sess_options *opt)
+{
+    PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
+    pj_memcpy(&ice_st->opt, opt, sizeof(*opt));
+    if (ice_st->ice)
+	pj_ice_sess_set_options(ice_st->ice, &ice_st->opt);
+    return PJ_SUCCESS;
+}
+
+/*
  * Create ICE!
  */
@@ -682,4 +713,7 @@
     /* Associate user data */
     ice_st->ice->user_data = (void*)ice_st;
+
+    /* Set options */
+    pj_ice_sess_set_options(ice_st->ice, &ice_st->opt);
 
     /* If default candidate for components are SRFLX one, upload a custom
Index: pjproject/branches/projects/sipit24/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- pjproject/branches/projects/sipit24/pjsip-apps/src/pjsua/pjsua_app.c	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjsip-apps/src/pjsua/pjsua_app.c	(revision 2705)
@@ -4729,5 +4729,5 @@
 	    status = pjmedia_transport_udp_create3(pjsua_get_pjmedia_endpt(), 
 						   pj_AF_INET6(),
-						   NULL, 
+						   app_config.rtp_cfg.public_addr.ptr, 
 						   &app_config.rtp_cfg.bound_addr,
 						   port, 
Index: pjproject/branches/projects/sipit24/pjsip-apps/src/samples/icedemo.c
===================================================================
--- pjproject/branches/projects/sipit24/pjsip-apps/src/samples/icedemo.c	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjsip-apps/src/samples/icedemo.c	(revision 2705)
@@ -40,5 +40,6 @@
 	unsigned    comp_cnt;
 	pj_str_t    ns;
-	pj_bool_t   no_host;
+	int	    max_host;
+	pj_bool_t   regular;
 	pj_str_t    stun_srv;
 	pj_str_t    turn_srv;
@@ -307,6 +308,7 @@
     /* -= Start initializing ICE stream transport config =- */
 
-    /* Disable host candidates? */
-    icedemo.ice_cfg.stun.no_host_cands = icedemo.opt.no_host;
+    /* Maximum number of host candidates */
+    if (icedemo.opt.max_host != -1)
+	icedemo.ice_cfg.stun.max_host_cands = icedemo.opt.max_host;
 
     /* Configure STUN/srflx candidate resolution */
@@ -375,4 +377,5 @@
 {
     pj_ice_strans_cb icecb;
+    pj_ice_sess_options opt;
     pj_status_t status;
 
@@ -399,4 +402,15 @@
     else
 	PJ_LOG(3,(THIS_FILE, "ICE instance successfully created"));
+
+    status = pj_ice_strans_get_options(icedemo.icest, &opt);
+    pj_assert(status == PJ_SUCCESS);
+
+    if (icedemo.opt.regular)
+	opt.aggressive = PJ_FALSE;
+    else
+	opt.aggressive = PJ_TRUE;
+
+    status = pj_ice_strans_set_options(icedemo.icest, &opt);
+    pj_assert(status == PJ_SUCCESS);
 }
 
@@ -961,5 +975,5 @@
     */
 
-    if (comp_id > pj_ice_strans_get_running_comp_cnt(icedemo.icest)) {
+    if (comp_id<1||comp_id>pj_ice_strans_get_running_comp_cnt(icedemo.icest)) {
 	PJ_LOG(1,(THIS_FILE, "Error: invalid component ID"));
 	return;
@@ -1138,5 +1152,6 @@
     puts(" --nameserver, -n IP       Configure nameserver to activate DNS SRV");
     puts("                           resolution");
-    puts(" --no-host, -H             Disable host candidates");
+    puts(" --max-host, -H N          Set max number of host candidates to N");
+    puts(" --regular, -R             Use regular nomination (default aggressive)");
     puts(" --help, -h                Display this screen.");
     puts("");
@@ -1166,5 +1181,5 @@
 	{ "comp-cnt",           1, 0, 'c'},
 	{ "nameserver",		1, 0, 'n'},
-	{ "no-host",		0, 0, 'H'},
+	{ "max-host",		1, 0, 'H'},
 	{ "help",		0, 0, 'h'},
 	{ "stun-srv",		1, 0, 's'},
@@ -1173,5 +1188,6 @@
 	{ "turn-username",	1, 0, 'u'},
 	{ "turn-password",	1, 0, 'p'},
-	{ "turn-fingerprint",	0, 0, 'F'}
+	{ "turn-fingerprint",	0, 0, 'F'},
+	{ "regular",		0, 0, 'R'}
     };
     int c, opt_id;
@@ -1179,6 +1195,7 @@
 
     icedemo.opt.comp_cnt = 1;
-
-    while((c=pj_getopt_long(argc,argv, "n:s:t:u:p:HhTF", long_options, &opt_id))!=-1) {
+    icedemo.opt.max_host = -1;
+
+    while((c=pj_getopt_long(argc,argv, "c:n:s:t:u:p:H:hTFR", long_options, &opt_id))!=-1) {
 	switch (c) {
 	case 'c':
@@ -1193,5 +1210,5 @@
 	    break;
 	case 'H':
-	    icedemo.opt.no_host = PJ_TRUE;
+	    icedemo.opt.max_host = atoi(pj_optarg);
 	    break;
 	case 'h':
@@ -1216,4 +1233,7 @@
 	    icedemo.opt.turn_fingerprint = PJ_TRUE;
 	    break;
+	case 'R':
+	    icedemo.opt.regular = PJ_TRUE;
+	    break;
 	default:
 	    printf("Argument \"%s\" is not valid. Use -h to see help",
Index: pjproject/branches/projects/sipit24/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- pjproject/branches/projects/sipit24/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2704)
+++ pjproject/branches/projects/sipit24/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2705)
@@ -811,5 +811,6 @@
 	ice_cfg.stun.port = pj_sockaddr_get_port(&pjsua_var.stun_srv);
     }
-    ice_cfg.stun.no_host_cands = pjsua_var.media_cfg.ice_no_host_cands;
+    if (pjsua_var.media_cfg.ice_no_host_cands)
+	ice_cfg.stun.max_host_cands = 0;
 
     /* Configure TURN settings */
