Index: pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 533)
+++ 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;
