Index: pjproject/trunk/pjmedia/src/pjmedia/transport_loop.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/transport_loop.c	(revision 3553)
+++ pjproject/trunk/pjmedia/src/pjmedia/transport_loop.c	(revision 5989)
@@ -36,4 +36,5 @@
 			void*,
 			pj_ssize_t);
+    void  (*rtp_cb2)(	pjmedia_tp_cb_param*);
     void  (*rtcp_cb)(	void*,		/**< To report incoming RTCP.	    */
 			void*,
@@ -48,4 +49,7 @@
     unsigned		user_cnt;	/**< Number of attachments	    */
     struct user		users[4];	/**< Array of users.		    */
+    pj_bool_t		disable_rx;	/**< Disable RX.		    */
+
+    pjmedia_loop_tp_setting setting;	/**< Setting.			    */
 
     unsigned		tx_drop_pct;	/**< Percent of tx pkts to drop.    */
@@ -72,4 +76,7 @@
 						       void*,
 						       pj_ssize_t));
+static pj_status_t transport_attach2  (pjmedia_transport *tp,
+				       pjmedia_transport_attach_param
+				           *att_param);
 static void	   transport_detach   (pjmedia_transport *tp,
 				       void *strm);
@@ -120,6 +127,18 @@
     &transport_media_stop,
     &transport_simulate_lost,
-    &transport_destroy
+    &transport_destroy,
+    &transport_attach2
 };
+
+
+/**
+ * Initialize loopback media transport setting with its default values.
+ */
+PJ_DEF(void) pjmedia_loop_tp_setting_default(pjmedia_loop_tp_setting *opt)
+{
+    pj_bzero(opt, sizeof(pjmedia_loop_tp_setting));
+    
+    opt->af = pj_AF_INET();
+}
 
 
@@ -130,4 +149,18 @@
 						  pjmedia_transport **p_tp)
 {
+    pjmedia_loop_tp_setting opt;
+    
+    pj_bzero(&opt, sizeof(opt));
+    opt.af = pj_AF_INET();
+
+    return pjmedia_transport_loop_create2(endpt, &opt, p_tp);
+}
+
+
+PJ_DEF(pj_status_t)
+pjmedia_transport_loop_create2(pjmedia_endpt *endpt,
+			       const pjmedia_loop_tp_setting *opt,
+			       pjmedia_transport **p_tp)
+{
     struct transport_loop *tp;
     pj_pool_t *pool;
@@ -147,4 +180,18 @@
     tp->base.type = PJMEDIA_TRANSPORT_TYPE_UDP;
 
+    if (opt) {
+    	tp->setting = *opt;
+    } else {
+    	pjmedia_loop_tp_setting_default(&tp->setting);
+    }
+    if (tp->setting.addr.slen) {
+    	pj_strdup(pool, &tp->setting.addr, &opt->addr);
+    } else {
+    	pj_strset2(&tp->setting.addr, (opt->af == pj_AF_INET())?
+    				       "127.0.0.1": "::1");
+    }
+    if (tp->setting.port == 0)
+    	tp->setting.port = 4000;
+
     /* Done */
     *p_tp = &tp->base;
@@ -190,10 +237,12 @@
 				      pjmedia_transport_info *info)
 {
-    PJ_ASSERT_RETURN(tp && info, PJ_EINVAL);
+    struct transport_loop *loop = (struct transport_loop*) tp;
 
     info->sock_info.rtp_sock = 1;
-    pj_sockaddr_in_init(&info->sock_info.rtp_addr_name.ipv4, 0, 0);
+    pj_sockaddr_init(loop->setting.af, &info->sock_info.rtp_addr_name, 
+		     &loop->setting.addr, loop->setting.port);
     info->sock_info.rtcp_sock = 2;
-    pj_sockaddr_in_init(&info->sock_info.rtcp_addr_name.ipv4, 0, 0);
+    pj_sockaddr_init(loop->setting.af, &info->sock_info.rtcp_addr_name,
+    		     &loop->setting.addr, loop->setting.port + 1);
 
     return PJ_SUCCESS;
@@ -202,4 +251,48 @@
 
 /* Called by application to initialize the transport */
+static pj_status_t tp_attach(   pjmedia_transport *tp,
+				       void *user_data,
+				       const pj_sockaddr_t *rem_addr,
+				       const pj_sockaddr_t *rem_rtcp,
+				       unsigned addr_len,
+				       void (*rtp_cb)(void*,
+						      void*,
+						      pj_ssize_t),
+				       void (*rtp_cb2)(pjmedia_tp_cb_param*),
+				       void (*rtcp_cb)(void*,
+						       void*,
+						       pj_ssize_t))
+{
+    struct transport_loop *loop = (struct transport_loop*) tp;
+    unsigned i;
+    const pj_sockaddr *rtcp_addr;
+
+    /* Validate arguments */
+    PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL);
+
+    /* Must not be "attached" to same user */
+    for (i=0; i<loop->user_cnt; ++i) {
+	PJ_ASSERT_RETURN(loop->users[i].user_data != user_data,
+			 PJ_EINVALIDOP);
+    }
+    PJ_ASSERT_RETURN(loop->user_cnt != PJ_ARRAY_SIZE(loop->users), 
+		     PJ_ETOOMANY);
+
+    PJ_UNUSED_ARG(rem_rtcp);
+    PJ_UNUSED_ARG(rtcp_addr);
+
+    /* "Attach" the application: */
+
+    /* Save the new user */
+    loop->users[loop->user_cnt].rtp_cb = rtp_cb;
+    loop->users[loop->user_cnt].rtp_cb2 = rtp_cb2;
+    loop->users[loop->user_cnt].rtcp_cb = rtcp_cb;
+    loop->users[loop->user_cnt].user_data = user_data;
+    loop->users[loop->user_cnt].rx_disabled = loop->disable_rx;
+    ++loop->user_cnt;
+
+    return PJ_SUCCESS;
+}
+
 static pj_status_t transport_attach(   pjmedia_transport *tp,
 				       void *user_data,
@@ -214,31 +307,17 @@
 						       pj_ssize_t))
 {
-    struct transport_loop *loop = (struct transport_loop*) tp;
-    unsigned i;
-    const pj_sockaddr *rtcp_addr;
-
-    /* Validate arguments */
-    PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL);
-
-    /* Must not be "attached" to same user */
-    for (i=0; i<loop->user_cnt; ++i) {
-	PJ_ASSERT_RETURN(loop->users[i].user_data != user_data,
-			 PJ_EINVALIDOP);
-    }
-    PJ_ASSERT_RETURN(loop->user_cnt != PJ_ARRAY_SIZE(loop->users), 
-		     PJ_ETOOMANY);
-
-    PJ_UNUSED_ARG(rem_rtcp);
-    PJ_UNUSED_ARG(rtcp_addr);
-
-    /* "Attach" the application: */
-
-    /* Save the new user */
-    loop->users[loop->user_cnt].rtp_cb = rtp_cb;
-    loop->users[loop->user_cnt].rtcp_cb = rtcp_cb;
-    loop->users[loop->user_cnt].user_data = user_data;
-    ++loop->user_cnt;
-
-    return PJ_SUCCESS;
+    return tp_attach(tp, user_data, rem_addr, rem_rtcp, addr_len,
+    		     rtp_cb, NULL, rtcp_cb);
+}
+
+static pj_status_t transport_attach2(pjmedia_transport *tp,
+				     pjmedia_transport_attach_param *att_param)
+{
+    return tp_attach(tp, att_param->user_data, 
+			    (pj_sockaddr_t*)&att_param->rem_addr, 
+			    (pj_sockaddr_t*)&att_param->rem_rtcp, 
+			    att_param->addr_len, att_param->rtp_cb,
+			    att_param->rtp_cb2, 
+			    att_param->rtcp_cb);
 }
 
@@ -297,7 +376,17 @@
     /* Distribute to users */
     for (i=0; i<loop->user_cnt; ++i) {
-	if (!loop->users[i].rx_disabled && loop->users[i].rtp_cb)
+	if (loop->users[i].rx_disabled) continue;
+	if (loop->users[i].rtp_cb2) {
+	    pjmedia_tp_cb_param param;
+
+	    pj_bzero(&param, sizeof(param));
+	    param.user_data = loop->users[i].user_data;
+	    param.pkt = (void *)pkt;
+	    param.size = size;
+	    (*loop->users[i].rtp_cb2)(&param);
+	} else if (loop->users[i].rtp_cb) {
 	    (*loop->users[i].rtp_cb)(loop->users[i].user_data, (void*)pkt, 
 				     size);
+	}
     }
 
