Index: /pjproject/trunk/pjmedia/include/pjmedia/transport.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 538)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 539)
@@ -67,26 +67,35 @@
      * about remote RTP address to send the packet and some callbacks to be 
      * called for incoming packets.
+     *
+     * Application should call #pjmedia_transport_attach() instead of 
+     * calling this function directly.
      */
     pj_status_t (*attach)(pjmedia_transport *tp,
-			  pjmedia_stream *strm,
+			  void *user_data,
 			  const pj_sockaddr_t *rem_addr,
 			  unsigned addr_len,
-			  void (*rtp_cb)(pjmedia_stream*,
-					 const void*,
-					 pj_ssize_t),
-			  void (*rtcp_cb)(pjmedia_stream*,
-					  const void*,
-					  pj_ssize_t));
+			  void (*rtp_cb)(void *user_data,
+					 const void *pkt,
+					 pj_ssize_t size),
+			  void (*rtcp_cb)(void *user_data,
+					  const void *pkt,
+					  pj_ssize_t size));
 
     /**
      * This function is called by the stream when the stream is no longer
      * need the transport (normally when the stream is about to be closed).
+     *
+     * Application should call #pjmedia_transport_detach() instead of 
+     * calling this function directly.
      */
     void (*detach)(pjmedia_transport *tp,
-		   pjmedia_stream *strm);
+		   void *user_data);
 
     /**
      * This function is called by the stream to send RTP packet using the 
      * transport.
+     *
+     * Application should call #pjmedia_transport_send_rtp() instead of 
+     * calling this function directly.
      */
     pj_status_t (*send_rtp)(pjmedia_transport *tp,
@@ -97,4 +106,7 @@
      * This function is called by the stream to send RTCP packet using the
      * transport.
+     *
+     * Application should call #pjmedia_transport_send_rtcp() instead of 
+     * calling this function directly.
      */
     pj_status_t (*send_rtcp)(pjmedia_transport *tp,
@@ -104,4 +116,7 @@
     /**
      * This function can be called to destroy this transport.
+     *
+     * Application should call #pjmedia_transport_close() instead of 
+     * calling this function directly.
      */
     pj_status_t (*destroy)(pjmedia_transport *tp);
@@ -130,4 +145,106 @@
 
 
+
+/**
+ * Attach callbacks to be called on receipt of incoming RTP/RTCP packets.
+ * This is just a simple wrapper which calls <tt>attach()</tt> member of 
+ * the transport.
+ *
+ * @param tp	    The media transport.
+ * @param user_data Arbitrary user data to be set when the callbacks are 
+ *		    called.
+ * @param rem_addr  Remote RTP address to send RTP packet to.
+ * @param addr_len  Length of the remote address.
+ * @param rtp_cb    Callback to be called when RTP packet is received on
+ *		    the transport.
+ * @param rtcp_cb   Callback to be called when RTCP packet is received on
+ *		    the transport.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_INLINE(pj_status_t) pjmedia_transport_attach(pjmedia_transport *tp,
+					        void *user_data,
+					        const pj_sockaddr_t *rem_addr,
+					        unsigned addr_len,
+					        void (*rtp_cb)(void *user_data,
+							       const void *pkt,
+							       pj_ssize_t),
+					        void (*rtcp_cb)(void *usr_data,
+							        const void*pkt,
+							        pj_ssize_t))
+{
+    return tp->op->attach(tp, user_data, rem_addr, addr_len, rtp_cb, rtcp_cb);
+}
+
+
+/**
+ * Detach callbacks from the transport.
+ * This is just a simple wrapper which calls <tt>attach()</tt> member of 
+ * the transport.
+ *
+ * @param tp	    The media transport.
+ * @param user_data User data which must match the previously set value
+ *		    on attachment.
+ */
+PJ_INLINE(void) pjmedia_transport_detach(pjmedia_transport *tp,
+					 void *user_data)
+{
+    tp->op->detach(tp, user_data);
+}
+
+
+/**
+ * Send RTP packet with the specified media transport. This is just a simple
+ * wrapper which calls <tt>send_rtp()</tt> member of the transport.
+ *
+ * @param tp	    The media transport.
+ * @param pkt	    The packet to send.
+ * @param size	    Size of the packet.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_INLINE(pj_status_t) pjmedia_transport_send_rtp(pjmedia_transport *tp,
+						  const void *pkt,
+						  pj_size_t size)
+{
+    return (*tp->op->send_rtp)(tp, pkt, size);
+}
+
+
+/**
+ * Send RTCP packet with the specified media transport. This is just a simple
+ * wrapper which calls <tt>send_rtcp()</tt> member of the transport.
+ *
+ * @param tp	    The media transport.
+ * @param pkt	    The packet to send.
+ * @param size	    Size of the packet.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_INLINE(pj_status_t) pjmedia_transport_send_rtcp(pjmedia_transport *tp,
+						  const void *pkt,
+						  pj_size_t size)
+{
+    return (*tp->op->send_rtcp)(tp, pkt, size);
+}
+
+
+/**
+ * Close media transport. This is just a simple wrapper which calls 
+ * <tt>destroy()</tt> member of the transport.
+ *
+ * @param tp	    The media transport.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_INLINE(pj_status_t) pjmedia_transport_close(pjmedia_transport *tp)
+{
+    if (tp->op->destroy)
+	return (*tp->op->destroy)(tp);
+    else
+	return PJ_SUCCESS;
+}
+
+
 PJ_END_DECL
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport_udp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport_udp.h	(revision 538)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport_udp.h	(revision 539)
@@ -57,5 +57,18 @@
 
 /**
- * Create an RTP and RTCP sockets and bind RTP the socket to the specified
+ * UDP transport info.
+ */
+typedef struct pjmedia_transport_udp_info
+{
+    /**
+     * Media socket info.
+     */
+    pjmedia_sock_info	skinfo;
+
+} pjmedia_transport_udp_info;
+
+
+/**
+ * Create an RTP and RTCP sockets and bind the sockets to the specified
  * port to create media transport.
  *
@@ -77,13 +90,37 @@
 
 /**
+ * Create an RTP and RTCP sockets and bind the sockets to the specified
+ * address and port to create media transport.
+ *
+ * @param endpt	    The media endpoint instance.
+ * @param name	    Optional name to be assigned to the transport.
+ * @param addr	    Optional local address to bind the sockets to. If this
+ *		    argument is NULL or empty, the sockets will be bound
+ *		    to all interface.
+ * @param port	    UDP port number for the RTP socket. The RTCP port number
+ *		    will be set to one above RTP port.
+ * @param options   Options, bitmask of #pjmedia_transport_udp_options.
+ * @param p_tp	    Pointer to receive the transport instance.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_udp_create2(pjmedia_endpt *endpt,
+						   const char *name,
+						   const pj_str_t *addr,
+						   int port,
+						   unsigned options,
+						   pjmedia_transport **p_tp);
+
+/**
  * Get media socket info from the specified UDP transport.
  *
  * @param tp	    The UDP transport interface.
- * @param i	    Media socket info to be initialized.
+ * @param info	    Media socket info to be initialized.
  *
  * @return	    PJ_SUCCESS on success.
  */
-PJ_DECL(pj_status_t) pjmedia_transport_udp_get_sock_info(pjmedia_transport *tp,
-							 pjmedia_sock_info *i);
+PJ_DECL(pj_status_t) 
+pjmedia_transport_udp_get_info( pjmedia_transport *tp,
+				pjmedia_transport_udp_info *info);
 
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 538)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 539)
@@ -31,4 +31,14 @@
 #define RTCP_LEN    600
 
+/* Maximum pending write operations */
+#define MAX_PENDING 4
+
+/* Pending write buffer */
+typedef struct pending_write
+{
+    char		buffer[RTP_LEN];
+    pj_ioqueue_op_key_t	op_key;
+} pending_write;
+
 
 struct transport_udp
@@ -38,5 +48,6 @@
     pj_pool_t	       *pool;		/**< Memory pool		    */
     unsigned		options;	/**< Transport options.		    */
-    pjmedia_stream     *stream;		/**< Stream user (may be NULL)	    */
+    void	       *user_data;	/**< Only valid when attached	    */
+    pj_bool_t		attached;	/**< Has attachment?		    */
     pj_sockaddr_in	rem_rtp_addr;	/**< Remote RTP address		    */
     pj_sockaddr_in	rem_rtcp_addr;	/**< Remote RTCP address	    */
@@ -52,5 +63,6 @@
     pj_ioqueue_key_t   *rtp_key;	/**< RTP socket key in ioqueue	    */
     pj_ioqueue_op_key_t	rtp_read_op;	/**< Pending read operation	    */
-    pj_ioqueue_op_key_t	rtp_write_op;	/**< Pending write operation	    */
+    unsigned		rtp_write_op_id;/**< Next write_op to use	    */
+    pending_write	rtp_pending_write[MAX_PENDING];  /**< Pending write */
     pj_sockaddr_in	rtp_src_addr;	/**< Actual packet src addr.	    */
     unsigned		rtp_src_cnt;	/**< How many pkt from this addr.   */
@@ -76,15 +88,15 @@
 
 static pj_status_t transport_attach(   pjmedia_transport *tp,
-				       pjmedia_stream *strm,
+				       void *user_data,
 				       const pj_sockaddr_t *rem_addr,
 				       unsigned addr_len,
-				       void (*rtp_cb)(pjmedia_stream*,
+				       void (*rtp_cb)(void*,
 						      const void*,
 						      pj_ssize_t),
-				       void (*rtcp_cb)(pjmedia_stream*,
+				       void (*rtcp_cb)(void*,
 						       const void*,
 						       pj_ssize_t));
 static void	   transport_detach(   pjmedia_transport *tp,
-				       pjmedia_stream *strm);
+				       void *strm);
 static pj_status_t transport_send_rtp( pjmedia_transport *tp,
 				       const void *pkt,
@@ -114,4 +126,18 @@
 						  pjmedia_transport **p_tp)
 {
+    return pjmedia_transport_udp_create2(endpt, name, NULL, port, options, 
+					p_tp);
+}
+
+/**
+ * Create UDP stream transport.
+ */
+PJ_DEF(pj_status_t) pjmedia_transport_udp_create2(pjmedia_endpt *endpt,
+						  const char *name,
+						  const pj_str_t *addr,
+						  int port,
+						  unsigned options,
+						  pjmedia_transport **p_tp)
+{
     pjmedia_sock_info si;
     pj_status_t status;
@@ -131,7 +157,5 @@
 
     /* Bind RTP socket */
-    si.rtp_addr_name.sin_family = PJ_AF_INET;
-    si.rtp_addr_name.sin_port = pj_htons((pj_uint16_t)port);
-
+    pj_sockaddr_in_init(&si.rtp_addr_name, addr, (pj_uint16_t)port);
     status = pj_sock_bind(si.rtp_sock, &si.rtp_addr_name, 
 			  sizeof(si.rtp_addr_name));
@@ -146,7 +170,5 @@
 
     /* Bind RTCP socket */
-    si.rtcp_addr_name.sin_family = PJ_AF_INET;
-    si.rtcp_addr_name.sin_port = pj_htons((pj_uint16_t)(port+1));
-
+    pj_sockaddr_in_init(&si.rtcp_addr_name, addr, (pj_uint16_t)(port+1));
     status = pj_sock_bind(si.rtcp_sock, &si.rtcp_addr_name,
 			  sizeof(si.rtcp_addr_name));
@@ -182,4 +204,5 @@
     pj_ioqueue_callback rtp_cb, rtcp_cb;
     pj_ssize_t size;
+    unsigned i;
     pj_status_t status;
 
@@ -224,5 +247,7 @@
     
     pj_ioqueue_op_key_init(&tp->rtp_read_op, sizeof(tp->rtp_read_op));
-    pj_ioqueue_op_key_init(&tp->rtcp_write_op, sizeof(tp->rtcp_write_op));
+    for (i=0; i<PJ_ARRAY_SIZE(tp->rtp_pending_write); ++i)
+	pj_ioqueue_op_key_init(&tp->rtp_pending_write[i].op_key, 
+			       sizeof(tp->rtp_pending_write[i].op_key));
 
     /* Kick of pending RTP read from the ioqueue */
@@ -271,14 +296,15 @@
  * Get media socket info.
  */
-PJ_DEF(pj_status_t) pjmedia_transport_udp_get_sock_info(pjmedia_transport *tp,
-							pjmedia_sock_info *inf)
+PJ_DEF(pj_status_t) 
+pjmedia_transport_udp_get_info( pjmedia_transport *tp,
+				pjmedia_transport_udp_info *inf)
 {
     struct transport_udp *udp = (struct transport_udp*)tp;
     PJ_ASSERT_RETURN(tp && inf, PJ_EINVAL);
 
-    inf->rtp_sock = udp->rtp_sock;
-    inf->rtp_addr_name = udp->rtp_addr_name;
-    inf->rtcp_sock = udp->rtcp_sock;
-    inf->rtcp_addr_name = udp->rtcp_addr_name;
+    inf->skinfo.rtp_sock = udp->rtp_sock;
+    inf->skinfo.rtp_addr_name = udp->rtp_addr_name;
+    inf->skinfo.rtcp_sock = udp->rtcp_sock;
+    inf->skinfo.rtcp_addr_name = udp->rtcp_addr_name;
 
     return PJ_SUCCESS;
@@ -297,5 +323,5 @@
 
     /* Must not close while stream is using this */
-    PJ_ASSERT_RETURN(udp->stream == NULL, PJ_EINVALIDOP);
+    PJ_ASSERT_RETURN(!udp->attached, PJ_EINVALIDOP);
     
 
@@ -335,12 +361,12 @@
 
     do {
-	void (*cb)(pjmedia_stream*,const void*,pj_ssize_t);
-	pjmedia_stream *stream;
+	void (*cb)(void*,const void*,pj_ssize_t);
+	void *user_data;
 
 	cb = udp->rtp_cb;
-	stream = udp->stream;
-
-	if (bytes_read > 0 && cb && stream)
-	    (*cb)(stream, udp->rtp_pkt, bytes_read);
+	user_data = udp->user_data;
+
+	if (udp->attached && cb)
+	    (*cb)(user_data, udp->rtp_pkt, bytes_read);
 
 	/* See if source address of RTP packet is different than the 
@@ -406,12 +432,12 @@
 
     do {
-	void (*cb)(pjmedia_stream*,const void*,pj_ssize_t);
-	pjmedia_stream *stream;
+	void (*cb)(void*,const void*,pj_ssize_t);
+	void *user_data;
 
 	cb = udp->rtcp_cb;
-	stream = udp->stream;
-
-	if (bytes_read > 0 && cb && stream)
-	    (*cb)(stream, udp->rtcp_pkt, bytes_read);
+	user_data = udp->user_data;
+
+	if (udp->attached && cb)
+	    (*cb)(user_data, udp->rtcp_pkt, bytes_read);
 
 	bytes_read = sizeof(udp->rtcp_pkt);
@@ -425,11 +451,11 @@
 /* Called by stream to initialize the transport */
 static pj_status_t transport_attach(   pjmedia_transport *tp,
-				       pjmedia_stream *strm,
+				       void *user_data,
 				       const pj_sockaddr_t *rem_addr,
 				       unsigned addr_len,
-				       void (*rtp_cb)(pjmedia_stream*,
+				       void (*rtp_cb)(void*,
 						      const void*,
 						      pj_ssize_t),
-				       void (*rtcp_cb)(pjmedia_stream*,
+				       void (*rtcp_cb)(void*,
 						       const void*,
 						       pj_ssize_t))
@@ -438,8 +464,8 @@
 
     /* Validate arguments */
-    PJ_ASSERT_RETURN(tp && strm && rem_addr && addr_len, PJ_EINVAL);
+    PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL);
 
     /* Must not be "attached" to existing stream */
-    PJ_ASSERT_RETURN(udp->stream == NULL, PJ_EINVALIDOP);
+    PJ_ASSERT_RETURN(!udp->attached, PJ_EINVALIDOP);
 
     /* "Attach" the stream: */
@@ -456,7 +482,8 @@
     udp->rtp_cb = rtp_cb;
     udp->rtcp_cb = rtcp_cb;
-
-    /* Last, save the stream to mark that we have a "client" */
-    udp->stream = strm;
+    udp->user_data = user_data;
+
+    /* Last, mark transport as attached */
+    udp->attached = PJ_TRUE;
 
     return PJ_SUCCESS;
@@ -466,16 +493,23 @@
 /* Called by stream when it no longer needs the transport */
 static void transport_detach( pjmedia_transport *tp,
-			      pjmedia_stream *strm)
+			      void *user_data)
 {
     struct transport_udp *udp = (struct transport_udp*) tp;
 
-    pj_assert(tp && strm);
-
-    PJ_UNUSED_ARG(strm);
+    pj_assert(tp);
+
+    /* User data is unreferenced on Release build */
+    PJ_UNUSED_ARG(user_data);
+
+    /* As additional checking, check if the same user data is specified */
+    pj_assert(user_data == udp->user_data);
+
+    /* First, mark stream as unattached */
+    udp->attached = PJ_FALSE;
 
     /* Clear up stream infos from transport */
-    udp->stream = NULL;
     udp->rtp_cb = NULL;
     udp->rtcp_cb = NULL;
+    udp->user_data = NULL;
 }
 
@@ -488,12 +522,32 @@
     struct transport_udp *udp = (struct transport_udp*)tp;
     pj_ssize_t sent;
+    unsigned id;
+    struct pending_write *pw;
     pj_status_t status;
 
-    PJ_ASSERT_RETURN(udp->stream, PJ_EINVALIDOP);
+    /* Must be attached */
+    PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP);
+
+    /* Check that the size is supported */
+    PJ_ASSERT_RETURN(size <= RTP_LEN, PJ_ETOOBIG);
+
+    id = udp->rtp_write_op_id;
+    pw = &udp->rtp_pending_write[id];
+
+    /* We need to copy packet to our buffer because when the
+     * operation is pending, caller might write something else
+     * to the original buffer.
+     */
+    pj_memcpy(pw->buffer, pkt, size);
 
     sent = size;
-    status = pj_ioqueue_sendto( udp->rtp_key, &udp->rtp_write_op,
-				pkt, &sent, 0,
-				&udp->rem_rtp_addr, sizeof(pj_sockaddr_in));
+    status = pj_ioqueue_sendto( udp->rtp_key, 
+				&udp->rtp_pending_write[id].op_key,
+				pw->buffer, &sent, 0,
+				&udp->rem_rtp_addr, 
+				sizeof(pj_sockaddr_in));
+
+    udp->rtp_write_op_id = (udp->rtp_write_op_id + 1) %
+			   PJ_ARRAY_SIZE(udp->rtp_pending_write);
 
     if (status==PJ_SUCCESS || status==PJ_EPENDING)
@@ -512,5 +566,5 @@
     pj_status_t status;
 
-    PJ_ASSERT_RETURN(udp->stream, PJ_EINVALIDOP);
+    PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP);
 
     sent = size;
