Index: pjproject/trunk/pjnath/include/pjnath/errno.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/errno.h	(revision 1500)
+++ pjproject/trunk/pjnath/include/pjnath/errno.h	(revision 1501)
@@ -111,4 +111,9 @@
 #define PJNATH_ESTUNIPV6NOTSUPP	    (PJNATH_ERRNO_START+41) /* 370041 */
 
+/**
+ * @hideinitializer
+ * Invalid STUN server or server not configured.
+ */
+#define PJNATH_ESTUNINSERVER	    (PJNATH_ERRNO_START+42) /* 370042 */
 
 
Index: pjproject/trunk/pjnath/include/pjnath/nat_detect.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/nat_detect.h	(revision 1500)
+++ pjproject/trunk/pjnath/include/pjnath/nat_detect.h	(revision 1501)
@@ -49,7 +49,13 @@
 {
     /**
-     * NAT type is unknown, because the detection has failed.
+     * NAT type is unknown because the detection has not been performed.
      */
     PJ_STUN_NAT_TYPE_UNKNOWN,
+
+    /**
+     * NAT type is unknown because there is failure in the detection
+     * process, possibly because server does not support RFC 3489.
+     */
+    PJ_STUN_NAT_TYPE_ERR_UNKNOWN,
 
     /**
@@ -150,4 +156,14 @@
 typedef void pj_stun_nat_detect_cb(void *user_data,
 				   const pj_stun_nat_detect_result *res);
+
+
+/**
+ * Get the NAT name from the specified NAT type.
+ *
+ * @param type		NAT type.
+ *
+ * @return		NAT name.
+ */
+PJ_DECL(const char*) pj_stun_get_nat_name(pj_stun_nat_type type);
 
 
Index: pjproject/trunk/pjnath/src/pjnath/errno.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1500)
+++ pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1501)
@@ -50,4 +50,5 @@
     PJ_BUILD_ERR( PJNATH_ESTUNNOMAPPEDADDR, "STUN (XOR-)MAPPED-ADDRESS attribute not found"),
     PJ_BUILD_ERR( PJNATH_ESTUNIPV6NOTSUPP,  "STUN IPv6 attribute not supported"),
+    PJ_BUILD_ERR( PJNATH_ESTUNINSERVER,	    "Invalid STUN server or server not configured"),
 
     /* ICE related errors */
Index: pjproject/trunk/pjnath/src/pjnath/nat_detect.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/nat_detect.c	(revision 1500)
+++ pjproject/trunk/pjnath/src/pjnath/nat_detect.c	(revision 1501)
@@ -33,5 +33,6 @@
 {
     "Unknown",
-    "Open Internet",
+    "ErrUnknown",
+    "Open",
     "Blocked",
     "Symmetric UDP",
@@ -130,4 +131,15 @@
 
 
+/*
+ * Get the NAT name from the specified NAT type.
+ */
+PJ_DEF(const char*) pj_stun_get_nat_name(pj_stun_nat_type type)
+{
+    PJ_ASSERT_RETURN(type >= 0 && type <= PJ_STUN_NAT_TYPE_PORT_RESTRICTED,
+		     "*Invalid*");
+
+    return nat_type_names[type];
+}
+
 static int test_executed(nat_detect_session *sess)
 {
@@ -388,5 +400,5 @@
 	{
 	    /* Permanent error */
-	    end_session(sess, -bytes_read, PJ_STUN_NAT_TYPE_UNKNOWN);
+	    end_session(sess, -bytes_read, PJ_STUN_NAT_TYPE_ERR_UNKNOWN);
 	    goto on_return;
 	}
@@ -407,5 +419,5 @@
     if (status != PJ_EPENDING) {
 	pj_assert(status != PJ_SUCCESS);
-	end_session(sess, status, PJ_STUN_NAT_TYPE_UNKNOWN);
+	end_session(sess, status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN);
     }
 
@@ -628,5 +640,5 @@
 		 */
 		end_session(sess, sess->result[ST_TEST_2].status, 
-			    PJ_STUN_NAT_TYPE_UNKNOWN);
+			    PJ_STUN_NAT_TYPE_ERR_UNKNOWN);
 		break;
 	    }
@@ -691,5 +703,5 @@
 			     */
 			    end_session(sess, sess->result[ST_TEST_3].status,
-					PJ_STUN_NAT_TYPE_UNKNOWN);
+					PJ_STUN_NAT_TYPE_ERR_UNKNOWN);
 			    break;
 			}
@@ -708,5 +720,5 @@
 		     */
 		    end_session(sess, sess->result[ST_TEST_1B].status,
-				PJ_STUN_NAT_TYPE_UNKNOWN);
+				PJ_STUN_NAT_TYPE_ERR_UNKNOWN);
 		    break;
 		}
@@ -717,5 +729,5 @@
 		 */
 		end_session(sess, sess->result[ST_TEST_2].status, 
-			    PJ_STUN_NAT_TYPE_UNKNOWN);
+			    PJ_STUN_NAT_TYPE_ERR_UNKNOWN);
 		break;
 	    }
@@ -727,5 +739,5 @@
 	 */
 	end_session(sess, sess->result[ST_TEST_1].status, 
-		    PJ_STUN_NAT_TYPE_UNKNOWN);
+		    PJ_STUN_NAT_TYPE_ERR_UNKNOWN);
 	break;
     }
Index: pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 1500)
+++ pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 1501)
@@ -1886,4 +1886,17 @@
 
 /*
+ * NAT type detection callback.
+ */
+static void on_nat_detect(const pj_stun_nat_detect_result *res)
+{
+    if (res->status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "NAT detection failed", res->status);
+    } else {
+	PJ_LOG(3, (THIS_FILE, "NAT detected as %s", res->nat_type_name));
+    }
+}
+
+
+/*
  * Print buddy list.
  */
@@ -2313,31 +2326,4 @@
 
 
-/* Callback upon NAT detection completion */
-static void nat_detect_cb(void *user_data,
-			  const pj_stun_nat_detect_result *res)
-{
-    PJ_UNUSED_ARG(user_data);
-
-    if (res->status != PJ_SUCCESS) {
-	pjsua_perror(THIS_FILE, "NAT detection failed", res->status);
-    } else {
-	PJ_LOG(3, (THIS_FILE, "NAT detected as %s", res->nat_type_name));
-    }
-}
-
-
-/*
- * Detect NAT type.
- */
-static void detect_nat_type(void)
-{
-    pj_status_t status;
-
-    status = pjsua_detect_nat_type(NULL, &nat_detect_cb);
-    if (status != PJ_SUCCESS)
-	pjsua_perror(THIS_FILE, "Error", status);
-}
-
-
 /*
  * Main "user interface" loop.
@@ -2454,5 +2440,5 @@
 
 	case 'n':
-	    detect_nat_type();
+	    pjsua_detect_nat_type();
 	    break;
 
@@ -3308,4 +3294,5 @@
     app_config.cfg.cb.on_call_transfer_status = &on_call_transfer_status;
     app_config.cfg.cb.on_call_replaced = &on_call_replaced;
+    app_config.cfg.cb.on_nat_detect = &on_nat_detect;
 
     /* Initialize pjsua */
@@ -3509,7 +3496,4 @@
 	return status;
     }
-
-    if (app_config.cfg.stun_domain.slen || app_config.cfg.stun_host.slen)
-	detect_nat_type();
 
     console_app_main(&uri_arg);
Index: pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 1500)
+++ pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 1501)
@@ -566,5 +566,7 @@
      * Notify application when media state in the call has changed.
      * Normal application would need to implement this callback, e.g.
-     * to connect the call's media to sound device.
+     * to connect the call's media to sound device. When ICE is used,
+     * this callback will also be called to report ICE negotiation
+     * failure.
      *
      * @param call_id	The call index.
@@ -892,4 +894,12 @@
 		      pj_bool_t is_typing);
 
+    /**
+     * Callback when the library has finished performing NAT type
+     * detection.
+     *
+     * @param res	    NAT detection result.
+     */
+    void (*on_nat_detect)(const pj_stun_nat_detect_result *res);
+
 } pjsua_callback;
 
@@ -978,4 +988,15 @@
      */
     pj_str_t	    stun_relay_host;
+
+    /**
+     * Include local endpoint's NAT type in the SDP to assist troubleshooting.
+     * The valid values are:
+     *	- 0: no information will be added in SDP.
+     *	- 1: only the NAT type number is added.
+     *	- 2: add both NAT type number and name.
+     *
+     * Default: 2
+     */
+    int		    nat_type_in_sdp;
 
     /**
@@ -1316,17 +1337,35 @@
  * This is a utility function to detect NAT type in front of this
  * endpoint. Once invoked successfully, this function will complete 
- * asynchronously and report the result in the callback.
- *
- * @param srv_port	Optional STUN server and port, in "SERVER[:PORT]"
- *			format. If this option is NULL, the function will use
- *			the STUN server that has been set in the pjsua
- *			configuration.
- * @param user_data	User data to be returned back in the callback.
- * @param cb		Optional callback to report the detection result.
- *
- * @return		PJ_SUCCESS if detection is started successfully.
- */
-PJ_DECL(pj_status_t) pjsua_detect_nat_type(void *user_data,
-					   pj_stun_nat_detect_cb *cb);
+ * asynchronously and report the result in \a on_nat_detect() callback
+ * of pjsua_callback.
+ *
+ * After NAT has been detected and the callback is called, application can
+ * get the detected NAT type by calling #pjsua_get_nat_type(). Application
+ * can also perform NAT detection by calling #pjsua_detect_nat_type()
+ * again at later time.
+ *
+ * Note that STUN must be enabled to run this function successfully.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_detect_nat_type(void);
+
+
+/**
+ * Get the NAT type as detected by #pjsua_detect_nat_type() function.
+ * This function will only return useful NAT type after #pjsua_detect_nat_type()
+ * has completed successfully and \a on_nat_detect() callback has been called.
+ *
+ * @param type		NAT type.
+ *
+ * @return		When detection is in progress, this function will 
+ *			return PJ_EPENDING and \a type will be set to 
+ *			PJ_STUN_NAT_TYPE_UNKNOWN. After NAT type has been
+ *			detected successfully, this function will return
+ *			PJ_SUCCESS and \a type will be set to the correct
+ *			value. Other return values indicate error and
+ *			\a type will be set to PJ_STUN_NAT_TYPE_ERR_UNKNOWN.
+ */
+PJ_DECL(pj_status_t) pjsua_get_nat_type(pj_stun_nat_type *type);
 
 
Index: pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 1500)
+++ pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 1501)
@@ -195,4 +195,9 @@
     pj_dns_resolver	*resolver;  /**< DNS resolver.			*/
 
+    /* Detected NAT type */
+    pj_stun_nat_type	 nat_type;	/**< NAT type.			*/
+    pj_status_t		 nat_status;	/**< Detection status.		*/
+    pj_bool_t		 nat_in_progress; /**< Detection in progress	*/
+
     /* Account: */
     unsigned		 acc_cnt;	     /**< Number of accounts.	*/
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 1500)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 1501)
@@ -52,4 +52,5 @@
 
     pjsua_var.stun_status = PJ_EUNKNOWN;
+    pjsua_var.nat_status = PJ_EPENDING;
 }
 
@@ -80,4 +81,5 @@
     cfg->max_calls = 4;
     cfg->thread_cnt = 1;
+    cfg->nat_type_in_sdp = 2;
 }
 
@@ -1859,15 +1861,35 @@
 
 
+/* Callback upon NAT detection completion */
+static void nat_detect_cb(void *user_data, 
+			  const pj_stun_nat_detect_result *res)
+{
+    PJ_UNUSED_ARG(user_data);
+
+    pjsua_var.nat_in_progress = PJ_FALSE;
+    pjsua_var.nat_status = res->status;
+    pjsua_var.nat_type = res->nat_type;
+
+    if (pjsua_var.ua_cfg.cb.on_nat_detect) {
+	(*pjsua_var.ua_cfg.cb.on_nat_detect)(res);
+    }
+}
+
+
 /*
  * Detect NAT type.
  */
-PJ_DEF(pj_status_t) pjsua_detect_nat_type( void *user_data,
-					   pj_stun_nat_detect_cb *cb)
+PJ_DEF(pj_status_t) pjsua_detect_nat_type()
 {
     pj_status_t status;
+
+    if (pjsua_var.nat_in_progress)
+	return PJ_SUCCESS;
 
     /* Make sure STUN server resolution has completed */
     status = pjsua_resolve_stun_server(PJ_TRUE);
     if (status != PJ_SUCCESS) {
+	pjsua_var.nat_status = status;
+	pjsua_var.nat_type = PJ_STUN_NAT_TYPE_ERR_UNKNOWN;
 	return status;
     }
@@ -1875,10 +1897,31 @@
     /* Make sure we have STUN */
     if (pjsua_var.stun_srv.ipv4.sin_family == 0) {
-	return PJ_EINVALIDOP;
-    }
-
-    return pj_stun_detect_nat_type(&pjsua_var.stun_srv.ipv4, 
-				   &pjsua_var.stun_cfg, 
-				   user_data, cb);
+	pjsua_var.nat_status = PJNATH_ESTUNINSERVER;
+	return PJNATH_ESTUNINSERVER;
+    }
+
+    status = pj_stun_detect_nat_type(&pjsua_var.stun_srv.ipv4, 
+				     &pjsua_var.stun_cfg, 
+				     NULL, &nat_detect_cb);
+
+    if (status != PJ_SUCCESS) {
+	pjsua_var.nat_status = status;
+	pjsua_var.nat_type = PJ_STUN_NAT_TYPE_ERR_UNKNOWN;
+	return status;
+    }
+
+    pjsua_var.nat_in_progress = PJ_TRUE;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get NAT type.
+ */
+PJ_DEF(pj_status_t) pjsua_get_nat_type(pj_stun_nat_type *type)
+{
+    *type = pjsua_var.nat_type;
+    return pjsua_var.nat_status;
 }
 
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1500)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1501)
@@ -195,4 +195,7 @@
     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
 
+    /* Perform NAT detection */
+    pjsua_detect_nat_type();
+
     return PJ_SUCCESS;
 }
@@ -759,4 +762,28 @@
     if (status != PJ_SUCCESS)
 	goto on_error;
+
+    /* Add NAT info in the SDP */
+    if (pjsua_var.ua_cfg.nat_type_in_sdp) {
+	pjmedia_sdp_attr *a;
+	pj_str_t value;
+	char nat_info[80];
+
+	value.ptr = nat_info;
+	if (pjsua_var.ua_cfg.nat_type_in_sdp == 1) {
+	    value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
+					  "%d", pjsua_var.nat_type);
+	} else {
+	    const char *type_name = pj_stun_get_nat_name(pjsua_var.nat_type);
+	    value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
+					  "%d %s",
+					  pjsua_var.nat_type,
+					  type_name);
+	}
+
+	a = pjmedia_sdp_attr_create(pool, "X-nat", &value);
+
+	pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a);
+
+    }
 
     if (pjsua_var.media_cfg.enable_ice) {
