Index: pjproject/trunk/pjmedia/include/pjmedia.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia.h	(revision 161)
+++ pjproject/trunk/pjmedia/include/pjmedia.h	(revision 162)
@@ -24,8 +24,8 @@
 #include <pjmedia/codec.h>
 #include <pjmedia/jbuf.h>
-#include <pjmedia/mediamgr.h>
+#include <pjmedia/endpoint.h>
 #include <pjmedia/rtcp.h>
 #include <pjmedia/rtp.h>
-//#include <pjmedia/session.h>
+#include <pjmedia/session.h>
 #include <pjmedia/sound.h>
 #include <pjmedia/sdp.h>
Index: pjproject/trunk/pjmedia/include/pjmedia/errno.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 161)
+++ pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 162)
@@ -26,23 +26,4 @@
 
 /**
- * Guidelines on error message length.
- */
-#define PJMEDIA_ERR_MSG_SIZE  64
-
-/**
- * Get error message for the specified error code.
- *
- * @param status    The error code.
- * @param buffer    The buffer where to put the error message.
- * @param bufsize   Size of the buffer.
- *
- * @return	    The error message as NULL terminated string,
- *                  wrapped with pj_str_t.
- */
-PJ_DECL(pj_str_t) pjmedia_strerror( pj_status_t status, char *buffer,
-				    pj_size_t bufsize);
-
-
-/**
  * Start of error code relative to PJ_ERRNO_START_USER.
  */
Index: pjproject/trunk/pjmedia/include/pjmedia/session.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/session.h	(revision 161)
+++ pjproject/trunk/pjmedia/include/pjmedia/session.h	(revision 162)
@@ -41,5 +41,5 @@
 /**
  * Create new session offering based on the local and remote SDP.
- * The session initially will be inactive.
+ * The session will start immediately.
  *
  * @param endpt		The PJMEDIA endpoint instance.
Index: pjproject/trunk/pjmedia/include/pjmedia/types.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/types.h	(revision 161)
+++ pjproject/trunk/pjmedia/include/pjmedia/types.h	(revision 162)
@@ -134,6 +134,7 @@
 
     pj_sock_t	    rtp_sock;
+    pj_sockaddr_in  rtp_addr_name;
     pj_sock_t	    rtcp_sock;
-    pj_sockaddr_in  rtp_addr_name;
+    pj_sockaddr_in  rtcp_addr_name;
 
 } pjmedia_sock_info;
Index: pjproject/trunk/pjmedia/src/pjmedia/endpoint.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/endpoint.c	(revision 161)
+++ pjproject/trunk/pjmedia/src/pjmedia/endpoint.c	(revision 162)
@@ -41,4 +41,30 @@
 PJ_DECL(pj_status_t) g711_deinit_factory (pjmedia_codec_factory *factory);
 
+/* Flag to indicate whether pjmedia error subsystem has been registered
+ * to pjlib.
+ */
+static int error_subsys_registered;
+
+
+/**
+ * Defined in pjmedia/errno.c
+ * 
+ * Get error message for the specified error code. Note that this
+ * function is only able to decode PJMEDIA specific error code.
+ * Application should use pj_strerror(), which should be able to
+ * decode all error codes belonging to all subsystems (e.g. pjlib,
+ * pjmedia, pjsip, etc).
+ *
+ * @param status    The error code.
+ * @param buffer    The buffer where to put the error message.
+ * @param bufsize   Size of the buffer.
+ *
+ * @return	    The error message as NULL terminated string,
+ *                  wrapped with pj_str_t.
+ */
+PJ_DECL(pj_str_t) pjmedia_strerror( pj_status_t status, char *buffer,
+				    pj_size_t bufsize);
+
+
 
 /** Concrete declaration of media endpoint. */
@@ -65,4 +91,10 @@
     pjmedia_codec_factory *factory;
     pj_status_t status;
+
+    if (!error_subsys_registered) {
+	pj_register_strerror(PJMEDIA_ERRNO_START, PJ_ERRNO_SPACE_SIZE, 
+			     &pjmedia_strerror);
+	error_subsys_registered = 1;
+    }
 
     PJ_ASSERT_RETURN(pf && p_endpt, PJ_EINVAL);
Index: pjproject/trunk/pjmedia/src/pjmedia/errno.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 161)
+++ pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 162)
@@ -133,19 +133,14 @@
 	    return errstr;
 
-	} else {
-	    /* Error not found. */
-	    errstr.ptr = buf;
-	    errstr.slen = pj_snprintf(buf, bufsize, 
-				      "Unknown error %d",
-				      statcode);
-
-	    return errstr;
-	}
-    }
-    else {
-	/* Not our code. Give it to PJLIB. */
-	return pj_strerror(statcode, buf, bufsize);
+	} 
     }
 
+    /* Error not found. */
+    errstr.ptr = buf;
+    errstr.slen = pj_snprintf(buf, bufsize, 
+			      "Unknown error %d",
+			      statcode);
+
+    return errstr;
 }
 
Index: pjproject/trunk/pjmedia/src/pjmedia/sdp.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/sdp.c	(revision 161)
+++ pjproject/trunk/pjmedia/src/pjmedia/sdp.c	(revision 162)
@@ -990,6 +990,6 @@
     PJ_CATCH(SYNTAX_ERROR) {
 	
-	char errmsg[PJMEDIA_ERR_MSG_SIZE];
-	pjmedia_strerror(ctx.last_error, errmsg, sizeof(errmsg));
+	char errmsg[PJ_ERR_MSG_SIZE];
+	pj_strerror(ctx.last_error, errmsg, sizeof(errmsg));
 
 	PJ_LOG(4, (THIS_FILE, "Error parsing SDP in line %d col %d: %s",
Index: pjproject/trunk/pjsip/include/pjsip/sip_errno.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_errno.h	(revision 161)
+++ pjproject/trunk/pjsip/include/pjsip/sip_errno.h	(revision 162)
@@ -24,9 +24,4 @@
 PJ_BEGIN_DECL
 
-/**
- * Guidelines on error message length.
- */
-#define PJSIP_ERR_MSG_SIZE  64
-
 /*
  * PJSIP error codes occupies 170000 - 219000, and mapped as follows:
@@ -34,17 +29,4 @@
  *  - 171000 - 171999: mapped to errors generated from PJSIP core.
  */
-
-/**
- * Get error message for the specified error code.
- *
- * @param status    The error code.
- * @param buffer    The buffer where to put the error message.
- * @param bufsize   Size of the buffer.
- *
- * @return	    The error message as NULL terminated string,
- *                  wrapped with pj_str_t.
- */
-PJ_DECL(pj_str_t) pjsip_strerror( pj_status_t status, char *buffer,
-				  pj_size_t bufsize);
 
 /**
Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 161)
+++ pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 162)
@@ -24,4 +24,5 @@
 #include <pjmedia/sdp.h>
 #include <pjmedia/sdp_neg.h>
+#include <pjmedia/errno.h>
 #include <pj/string.h>
 #include <pj/pool.h>
@@ -761,7 +762,5 @@
 						      &inv->neg);
     } else {
-	pj_assert(!"UAS dialog without remote and local offer is not supported!");
-	PJ_TODO(IMPLEMENT_DELAYED_UAS_OFFER);
-	status = PJ_ENOTSUP;
+	status = PJ_SUCCESS;
     }
 
@@ -874,4 +873,23 @@
 }
 
+
+/*
+ * Negotiate SDP.
+ */
+static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
+{
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
+		     PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, 
+		     PJMEDIA_SDPNEG_EINSTATE);
+
+    status = pjmedia_sdp_neg_negotiate(inv->pool, inv->neg, 0);
+
+    if (mod_inv.cb.on_media_update)
+	(*mod_inv.cb.on_media_update)(inv, status);
+
+    return status;
+}
 
 /*
@@ -899,10 +917,21 @@
      * offer before. 
      */
-    PJ_ASSERT_RETURN(!local_sdp ||
-		     (pjmedia_sdp_neg_get_state(inv->neg)==PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER),
-		     PJ_EINVALIDOP);
     if (local_sdp) {
-	status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
-						  local_sdp);
+
+	if (inv->neg == NULL) {
+	    status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
+							  &inv->neg);
+	} else if (pjmedia_sdp_neg_get_state(inv->neg)==
+		   PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
+	{
+	    status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
+						      local_sdp);
+	} else {
+
+	    /* Can not specify local SDP at this state. */
+	    pj_assert(0);
+	    status = PJMEDIA_SDPNEG_EINSTATE;
+	}
+
 	if (status != PJ_SUCCESS)
 	    return status;
@@ -916,5 +945,7 @@
 	return status;
 
-    /* Include SDP for 18x and 2xx response. */
+    /* Include SDP for 18x and 2xx response. 
+     * Also if SDP negotiator is ready, start negotiation.
+     */
     if (st_code/10 == 18 || st_code/10 == 20) {
 	const pjmedia_sdp_session *local;
@@ -923,9 +954,15 @@
 	if (status == PJ_SUCCESS)
 	    last_res->msg->body = create_sdp_body(last_res->pool, local);
-					      ;
-    }
-
-    /* Do we need to increment tdata'inv reference counter? */
-    PJ_TODO(INV_ANSWER_MAY_HAVE_TO_INCREMENT_REF_COUNTER);
+
+	/* Start negotiation, if ready. */
+	if (pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
+	    status = inv_negotiate_sdp(inv);
+	    if (status != PJ_SUCCESS) {
+		pjsip_tx_data_dec_ref(last_res);
+		return status;
+	    }
+	}
+    }
+
 
     *p_tdata = last_res;
Index: pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 161)
+++ pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 162)
@@ -107,4 +107,26 @@
 extern pjsip_module mod_stateful_util;
 
+
+/* Specifies whether error subsystem has been registered to pjlib. */
+static int error_subsys_initialized;
+
+/**
+ * Defined in sip_errno.c
+ *
+ * Get error message for the specified error code. This can only get
+ * PJSIP specific error message. To get all types of error message,
+ * use pj_strerror() instead.
+ *
+ * @param status    The error code.
+ * @param buffer    The buffer where to put the error message.
+ * @param bufsize   Size of the buffer.
+ *
+ * @return	    The error message as NULL terminated string,
+ *                  wrapped with pj_str_t.
+ */
+PJ_DECL(pj_str_t) pjsip_strerror( pj_status_t status, char *buffer,
+				  pj_size_t bufsize);
+
+
 /*
  * This is the global handler for memory allocation failure, for pools that
@@ -394,4 +416,11 @@
     pjsip_max_fwd_hdr *mf_hdr;
     pj_lock_t *lock = NULL;
+
+
+    if (!error_subsys_initialized) {
+	pj_register_strerror(PJSIP_ERRNO_START, PJ_ERRNO_SPACE_SIZE,
+			     &pjsip_strerror);
+	error_subsys_initialized = 1;
+    }
 
     PJ_LOG(5, (THIS_FILE, "Creating endpoint instance..."));
Index: pjproject/trunk/pjsip/src/pjsip/sip_resolve.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_resolve.c	(revision 161)
+++ pjproject/trunk/pjsip/src/pjsip/sip_resolve.c	(revision 162)
@@ -130,10 +130,10 @@
 
     if (status != PJ_SUCCESS) {
-	char errmsg[PJSIP_ERR_MSG_SIZE];
+	char errmsg[PJ_ERR_MSG_SIZE];
 	PJ_LOG(4,(THIS_FILE, "Failed to resolve '%.*s'. Err=%d (%s)",
 			     target->addr.host.slen,
 			     target->addr.host.ptr,
 			     status,
-			     pjsip_strerror(status,errmsg,sizeof(errmsg)).ptr));
+			     pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
 	(*cb)(status, token, &svr_addr);
 	return;
Index: pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 161)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 162)
@@ -1443,10 +1443,10 @@
 
 	if (!*cont) {
-	    char errmsg[PJSIP_ERR_MSG_SIZE];
+	    char errmsg[PJ_ERR_MSG_SIZE];
 
 	    PJ_LOG(4,(tsx->obj_name, 
 		      "Failed to send %s! err=%d (%s)",
 		      pjsip_tx_data_get_info(send_state->tdata), -sent,
-		      pjsip_strerror(-sent, errmsg, sizeof(errmsg)).ptr));
+		      pj_strerror(-sent, errmsg, sizeof(errmsg)).ptr));
 
 	    /* Clear pending transport flag. */
@@ -1466,5 +1466,5 @@
 
 	} else {
-	    char errmsg[PJSIP_ERR_MSG_SIZE];
+	    char errmsg[PJ_ERR_MSG_SIZE];
 
 	    PJ_LOG(4,(tsx->obj_name, 
@@ -1472,5 +1472,5 @@
 		      "will try next server. Err=%d (%s)",
 		      pjsip_tx_data_get_info(send_state->tdata), -sent,
-		      pjsip_strerror(-sent, errmsg, sizeof(errmsg)).ptr));
+		      pj_strerror(-sent, errmsg, sizeof(errmsg)).ptr));
 	}
     }
@@ -1487,9 +1487,9 @@
 	pjsip_transaction *tsx = token;
 	struct tsx_lock_data lck;
-	char errmsg[PJSIP_ERR_MSG_SIZE];
+	char errmsg[PJ_ERR_MSG_SIZE];
 
 	PJ_LOG(4,(tsx->obj_name, "Transport failed to send %s! Err=%d (%s)",
 		  pjsip_tx_data_get_info(tdata), -sent,
-		  pjsip_strerror(-sent, errmsg, sizeof(errmsg)).ptr));
+		  pj_strerror(-sent, errmsg, sizeof(errmsg)).ptr));
 
 	lock_tsx(tsx, &lck);
@@ -1535,10 +1535,10 @@
 
 	if (status != PJ_SUCCESS) {
-	    char errmsg[PJSIP_ERR_MSG_SIZE];
+	    char errmsg[PJ_ERR_MSG_SIZE];
 
 	    PJ_LOG(4,(tsx->obj_name, 
 		      "Error sending %s: Err=%d (%s)",
 		      pjsip_tx_data_get_info(tdata), status, 
-		      pjsip_strerror(status, errmsg, sizeof(errmsg)).ptr));
+		      pj_strerror(status, errmsg, sizeof(errmsg)).ptr));
 
 	    /* On error, release transport to force using full transport
@@ -1569,5 +1569,5 @@
     if (tsx->transport_flag & TSX_HAS_RESOLVED_SERVER) {
 	
-	char errmsg[PJSIP_ERR_MSG_SIZE];
+	char errmsg[PJ_ERR_MSG_SIZE];
 
 	if (status == PJ_SUCCESS) {
@@ -1583,5 +1583,5 @@
 		  "Err=%d (%s)",
 		  status, 
-		  pjsip_strerror(status, errmsg, sizeof(errmsg)).ptr));
+		  pj_strerror(status, errmsg, sizeof(errmsg)).ptr));
 
 	tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;
Index: pjproject/trunk/pjsip/src/pjsua/pjsua.h
===================================================================
--- pjproject/trunk/pjsip/src/pjsua/pjsua.h	(revision 161)
+++ pjproject/trunk/pjsip/src/pjsua/pjsua.h	(revision 162)
@@ -39,13 +39,19 @@
 
 /* PJSUA application variables. */
-struct pjsua_t
+struct pjsua
 {
     /* Control: */
 
-    pj_caching_pool   cp;	    /**< Global pool factory.		*/
-    pjsip_endpoint   *endpt;	    /**< Global endpoint.		*/
-    pj_pool_t	     *pool;	    /**< pjsua's private pool.		*/
-    pjsip_module      mod;	    /**< pjsua's PJSIP module.		*/
+    pj_caching_pool  cp;	    /**< Global pool factory.		*/
+    pjsip_endpoint  *endpt;	    /**< Global endpoint.		*/
+    pj_pool_t	    *pool;	    /**< pjsua's private pool.		*/
+    pjsip_module     mod;	    /**< pjsua's PJSIP module.		*/
     
+
+    /* Media:  */
+
+    pjmedia_endpt   *med_endpt;    /**< Media endpoint.		*/
+    pj_bool_t	     null_audio;
+    pjmedia_sock_info med_skinfo;
 
     /* User info: */
@@ -58,4 +64,6 @@
     pj_str_t	     proxy;
     pj_str_t	     outbound_proxy;
+    pjsip_route_hdr  route_set;
+
 
     /* Registration: */
@@ -84,8 +92,4 @@
     pj_sock_t	     sip_sock;	    /**< SIP UDP socket.		*/
     pj_sockaddr_in   sip_sock_name; /**< Public/STUN UDP socket addr.	*/
-    pj_sock_t	     rtp_sock;	    /**< RTP socket.			*/
-    pj_sockaddr_in   rtp_sock_name; /**< Public/STUN UDP socket addr.	*/
-    pj_sock_t	     rtcp_sock;	    /**< RTCP socket.			*/
-    pj_sockaddr_in   rtcp_sock_name;/**< Public/STUN UDP socket addr.	*/
 
 
@@ -97,10 +101,4 @@
     pj_str_t	     stun_srv2;
     int		     stun_port2;
-
-
-    /* Media stack: */
-
-    pj_bool_t	     null_audio;
-    pj_med_mgr_t    *mmgr;
 
 
@@ -114,5 +112,19 @@
 };
 
-extern struct pjsua_t pjsua;
+
+/** PJSUA instance. */
+extern struct pjsua pjsua;
+
+
+/** 
+ * Structure to be attached to all dialog. 
+ * Given a dialog "dlg", application can retrieve this structure
+ * by accessing dlg->mod_data[pjsua.mod.id].
+ */
+struct pjsua_inv_data
+{
+    pjmedia_session *session;
+};
+
 
 /*****************************************************************************
Index: pjproject/trunk/pjsip/src/pjsua/pjsua_core.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua/pjsua_core.c	(revision 161)
+++ pjproject/trunk/pjsip/src/pjsua/pjsua_core.c	(revision 162)
@@ -22,25 +22,12 @@
 #define THIS_FILE   "pjsua.c"
 
-struct pjsua_t pjsua;
-
+struct pjsua pjsua;
+
+/* 
+ * Default local URI, if not specified in cmd-line 
+ */
 #define PJSUA_LOCAL_URI	    "<sip:user@127.0.0.1>"
 
-static char *PJSUA_DUMMY_SDP_OFFER = 
-	    "v=0\r\n"
-	    "o=offer 2890844526 2890844526 IN IP4 127.0.0.1\r\n"
-	    "s= \r\n"
-	    "c=IN IP4 127.0.0.1\r\n"
-	    "t=0 0\r\n"
-	    "m=audio 49170 RTP/AVP 0\r\n"
-	    "a=rtpmap:0 PCMU/8000\r\n";
-
-static char *PJSUA_DUMMY_SDP_ANSWER = 
-	    "v=0\r\n"
-	    "o=answer 2890844730 2890844730 IN IP4 127.0.0.1\r\n"
-	    "s= \r\n"
-	    "c=IN IP4 127.0.0.1\r\n"
-	    "t=0 0\r\n"
-	    "m=audio 49920 RTP/AVP 0\r\n"
-	    "a=rtpmap:0 PCMU/8000\r\n";
+
 
 /*
@@ -75,4 +62,8 @@
 
     pjsua.local_uri = pj_str(PJSUA_LOCAL_URI);
+
+    /* Init route set list: */
+
+    pj_list_init(&pjsua.route_set);
 }
 
@@ -144,12 +135,12 @@
 	     */
 	    pjsip_inv_session *inv;
+	    struct pjsua_inv_data *inv_data;
 	    pjmedia_sdp_session *answer;
 
-	    /* Create dummy SDP answer: */
-
-
-	    status = pjmedia_sdp_parse(pjsua.pool, PJSUA_DUMMY_SDP_ANSWER,
-				       pj_native_strlen(PJSUA_DUMMY_SDP_ANSWER),
-				       &answer);
+
+	    /* Get media capability from media endpoint: */
+
+	    status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool,
+					       1, &pjsua.med_skinfo, &answer );
 	    if (status != PJ_SUCCESS) {
 
@@ -181,4 +172,11 @@
 
 	    }
+
+
+	    /* Create and attach pjsua data to the dialog: */
+
+	    inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data));
+	    dlg->mod_data[pjsua.mod.id] = inv_data;
+
 
 	    /* Answer with 100 (using the dialog, not invite): */
@@ -223,4 +221,17 @@
 static void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
 {
+
+    /* Destroy media session when invite session is disconnected. */
+    if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
+	struct pjsua_inv_data *inv_data;
+
+	inv_data = inv->dlg->mod_data[pjsua.mod.id];
+	if (inv_data && inv_data->session) {
+	    pjmedia_session_destroy(inv_data->session);
+	    inv_data->session = NULL;
+	}
+
+    }
+
     pjsua_ui_inv_on_state_changed(inv, e);
 }
@@ -237,4 +248,58 @@
 
     PJ_TODO(HANDLE_FORKED_DIALOG);
+}
+
+/*
+ *
+ */
+static void pjsua_inv_on_media_update(pjsip_inv_session *inv, 
+				      pj_status_t status)
+{
+    struct pjsua_inv_data *inv_data;
+    const pjmedia_sdp_session *local_sdp;
+    const pjmedia_sdp_session *remote_sdp;
+
+    if (status != PJ_SUCCESS) {
+
+	pjsua_perror("SDP negotiation has failed", status);
+	return;
+
+    }
+
+    /* Destroy existing media session, if any. */
+
+    inv_data = inv->dlg->mod_data[pjsua.mod.id];
+    if (inv_data && inv_data->session) {
+	pjmedia_session_destroy(inv_data->session);
+	inv_data->session = NULL;
+    }
+
+    /* Get local and remote SDP */
+
+    status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror("Unable to retrieve currently active local SDP", status);
+	return;
+    }
+
+
+    status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror("Unable to retrieve currently active remote SDP", status);
+	return;
+    }
+
+
+    /* Create new media session. 
+     * The media session is active immediately.
+     */
+
+    status = pjmedia_session_create( pjsua.med_endpt, 1, &pjsua.med_skinfo,
+				     local_sdp, remote_sdp, &inv_data->session );
+    if (status != PJ_SUCCESS) {
+	pjsua_perror("Unable to create media session", status);
+	return;
+    }
+
 }
 
@@ -364,8 +429,12 @@
     pjsua.sip_sock = sock[SIP_SOCK];
     pj_memcpy(&pjsua.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in));
-    pjsua.rtp_sock = sock[RTP_SOCK];
-    pj_memcpy(&pjsua.rtp_sock_name, &mapped_addr[RTP_SOCK], sizeof(pj_sockaddr_in));
-    pjsua.rtcp_sock = sock[RTCP_SOCK];
-    pj_memcpy(&pjsua.rtcp_sock_name, &mapped_addr[RTCP_SOCK], sizeof(pj_sockaddr_in));
+
+    pjsua.med_skinfo.rtp_sock = sock[RTP_SOCK];
+    pj_memcpy(&pjsua.med_skinfo.rtp_addr_name, 
+	      &mapped_addr[RTP_SOCK], sizeof(pj_sockaddr_in));
+
+    pjsua.med_skinfo.rtcp_sock = sock[RTCP_SOCK];
+    pj_memcpy(&pjsua.med_skinfo.rtcp_addr_name, 
+	      &mapped_addr[RTCP_SOCK], sizeof(pj_sockaddr_in));
 
     PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
@@ -373,9 +442,9 @@
 	      pj_ntohs(pjsua.sip_sock_name.sin_port)));
     PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d",
-	      pj_inet_ntoa(pjsua.rtp_sock_name.sin_addr), 
-	      pj_ntohs(pjsua.rtp_sock_name.sin_port)));
+	      pj_inet_ntoa(pjsua.med_skinfo.rtp_addr_name.sin_addr), 
+	      pj_ntohs(pjsua.med_skinfo.rtp_addr_name.sin_port)));
     PJ_LOG(4,(THIS_FILE, "RTCP UDP socket reachable at %s:%d",
-	      pj_inet_ntoa(pjsua.rtcp_sock_name.sin_addr), 
-	      pj_ntohs(pjsua.rtcp_sock_name.sin_port)));
+	      pj_inet_ntoa(pjsua.med_skinfo.rtcp_addr_name.sin_addr), 
+	      pj_ntohs(pjsua.med_skinfo.rtcp_addr_name.sin_port)));
 
     return PJ_SUCCESS;
@@ -479,4 +548,5 @@
 	inv_cb.on_state_changed = &pjsua_inv_on_state_changed;
 	inv_cb.on_new_session = &pjsua_inv_on_new_session;
+	inv_cb.on_media_update = &pjsua_inv_on_media_update;
 
 	/* Initialize invite session module: */
@@ -552,4 +622,14 @@
 	pj_caching_pool_destroy(&pjsua.cp);
 	pjsua_perror("Stack initialization has returned error", status);
+	return status;
+    }
+
+
+    /* Init media endpoint: */
+
+    status = pjmedia_endpt_create(&pjsua.cp.factory, &pjsua.med_endpt);
+    if (status != PJ_SUCCESS) {
+	pj_caching_pool_destroy(&pjsua.cp);
+	pjsua_perror("Media stack initialization has returned error", status);
 	return status;
     }
@@ -677,7 +757,23 @@
     }
 
-    /* Initialize global route_set: */
-
-    PJ_TODO(INIT_GLOBAL_ROUTE_SET);
+    /* If outbound_proxy is specified, put it in the route_set: */
+
+    if (pjsua.outbound_proxy.slen) {
+
+	pjsip_route_hdr *route;
+	const pj_str_t hname = { "Route", 5 };
+	int parsed_len;
+
+	route = pjsip_parse_hdr( pjsua.pool, &hname, 
+				 pjsua.outbound_proxy.ptr, 
+				 pjsua.outbound_proxy.slen,
+				   &parsed_len);
+	if (route == NULL) {
+	    pjsua_perror("Invalid outbound proxy URL", PJSIP_EINVALIDURI);
+	    return PJSIP_EINVALIDURI;
+	}
+
+	pj_list_push_back(&pjsua.route_set, route);
+    }
 
 
@@ -770,4 +866,5 @@
     pjmedia_sdp_session *offer;
     pjsip_inv_session *inv;
+    struct pjsua_inv_data *inv_data;
     pjsip_tx_data *tdata;
     pj_status_t status;
@@ -787,11 +884,10 @@
     }
 
-    /* Create dummy SDP for offer: */
-
-    status = pjmedia_sdp_parse(dlg->pool, PJSUA_DUMMY_SDP_OFFER,
-			       pj_native_strlen(PJSUA_DUMMY_SDP_OFFER),
-			       &offer);
-    if (status != PJ_SUCCESS) {
-	pjsua_perror("Dummy SDP offer parsing failed", status);
+    /* Get media capability from media endpoint: */
+
+    status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool,
+				       1, &pjsua.med_skinfo, &offer);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror("pjmedia unable to create SDP", status);
 	goto on_error;
     }
@@ -806,7 +902,15 @@
 
 
+    /* Create and associate our data in the session. */
+
+    inv_data = pj_pool_zalloc( dlg->pool, sizeof(struct pjsua_inv_data));
+    dlg->mod_data[pjsua.mod.id] = inv_data;
+
+
     /* Set dialog Route-Set: */
 
-    PJ_TODO(INIT_DIALOG_ROUTE_SET);
+    if (!pj_list_empty(&pjsua.route_set))
+	pjsip_dlg_set_route_set(dlg, &pjsua.route_set);
+
 
     /* Set credentials: */
