Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5746)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5747)
@@ -57,4 +57,5 @@
     void	       *user_data;	/**< Only valid when attached	    */
     //pj_bool_t		attached;	/**< Has attachment?		    */
+    pj_bool_t		started;	/**< Has started?		    */
     pj_sockaddr		rem_rtp_addr;	/**< Remote RTP address		    */
     unsigned		rem_rtp_cnt;	/**< How many pkt from this addr.   */
@@ -282,5 +283,4 @@
     pj_ioqueue_t *ioqueue;
     pj_ioqueue_callback rtp_cb, rtcp_cb;
-    pj_ssize_t size;
     unsigned i;
     pj_status_t status;
@@ -355,4 +355,5 @@
 			       sizeof(tp->rtp_pending_write[i].op_key));
 
+#if 0 // See #2097: move read op kick-off to media_start()
     /* Kick of pending RTP read from the ioqueue */
     tp->rtp_addrlen = sizeof(tp->rtp_src_addr);
@@ -363,4 +364,5 @@
     if (status != PJ_EPENDING)
 	goto on_error;
+#endif
 
 
@@ -382,4 +384,5 @@
 
 
+#if 0 // See #2097: move read op kick-off to media_start()
     /* Kick of pending RTCP read from the ioqueue */
     size = sizeof(tp->rtcp_pkt);
@@ -390,4 +393,5 @@
     if (status != PJ_EPENDING)
 	goto on_error;
+#endif    
 
     tp->ioqueue = ioqueue;
@@ -571,5 +575,6 @@
 	    bytes_read = -status;
 
-    } while (status != PJ_EPENDING && status != PJ_ECANCELLED);
+    } while (status != PJ_EPENDING && status != PJ_ECANCELLED &&
+	     udp->started);
 }
 
@@ -581,5 +586,5 @@
 {
     struct transport_udp *udp;
-    pj_status_t status;
+    pj_status_t status = PJ_SUCCESS;
 
     PJ_UNUSED_ARG(op_key);
@@ -651,5 +656,6 @@
 	    bytes_read = -status;
 
-    } while (status != PJ_EPENDING && status != PJ_ECANCELLED);
+    } while (status != PJ_EPENDING && status != PJ_ECANCELLED &&
+	     udp->started);
 }
 
@@ -998,7 +1004,10 @@
 				  unsigned media_index)
 {
-    PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL);
-
-    PJ_UNUSED_ARG(tp);
+    struct transport_udp *udp = (struct transport_udp*)tp;
+    pj_ssize_t size;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
     PJ_UNUSED_ARG(pool);
     PJ_UNUSED_ARG(sdp_local);
@@ -1006,4 +1015,29 @@
     PJ_UNUSED_ARG(media_index);
 
+    /* Just return success if there is already pending read */
+    if (udp->started)
+	return PJ_SUCCESS;
+
+    /* Kick off pending RTP read from the ioqueue */
+    udp->rtp_addrlen = sizeof(udp->rtp_src_addr);
+    size = sizeof(udp->rtp_pkt);
+    status = pj_ioqueue_recvfrom(udp->rtp_key, &udp->rtp_read_op,
+			         udp->rtp_pkt, &size, PJ_IOQUEUE_ALWAYS_ASYNC,
+				 &udp->rtp_src_addr, &udp->rtp_addrlen);
+    if (status != PJ_EPENDING)
+	return status;
+
+    /* Kick off pending RTCP read from the ioqueue */
+    udp->rtcp_addr_len = sizeof(udp->rtcp_src_addr);
+    size = sizeof(udp->rtcp_pkt);
+    status = pj_ioqueue_recvfrom(udp->rtcp_key, &udp->rtcp_read_op,
+				 udp->rtcp_pkt, &size,
+				 PJ_IOQUEUE_ALWAYS_ASYNC,
+				 &udp->rtcp_src_addr, &udp->rtcp_addr_len);
+    if (status != PJ_EPENDING)
+	return status;
+
+    udp->started = PJ_TRUE;
+
     return PJ_SUCCESS;
 }
@@ -1011,5 +1045,19 @@
 static pj_status_t transport_media_stop(pjmedia_transport *tp)
 {
-    PJ_UNUSED_ARG(tp);
+    struct transport_udp *udp = (struct transport_udp*)tp;
+
+    PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+
+    /* Just return success if there is no pending read */
+    if (!udp->started)
+	return PJ_SUCCESS;
+
+    pj_ioqueue_post_completion(udp->rtp_key, &udp->rtp_read_op,
+			       -PJ_ECANCELLED);
+
+    pj_ioqueue_post_completion(udp->rtcp_key, &udp->rtcp_read_op,
+			       -PJ_ECANCELLED);
+
+    udp->started = PJ_FALSE;
 
     return PJ_SUCCESS;
Index: /pjproject/trunk/pjsip-apps/src/samples/simpleua.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/simpleua.c	(revision 5746)
+++ /pjproject/trunk/pjsip-apps/src/samples/simpleua.c	(revision 5747)
@@ -871,4 +871,7 @@
     }
 
+    /* Start the UDP media transport */
+    pjmedia_transport_media_start(g_med_transport[0], 0, 0, 0, 0);
+
     /* Get the media port interface of the audio stream. 
      * Media port interface is basicly a struct containing get_frame() and
@@ -947,4 +950,7 @@
 	}
 
+	/* Start the UDP media transport */
+	pjmedia_transport_media_start(g_med_transport[1], 0, 0, 0, 0);
+
 	if (vstream_info.dir & PJMEDIA_DIR_DECODING) {
 	    status = pjmedia_vid_dev_default_param(
Index: /pjproject/trunk/pjsip-apps/src/samples/siprtp.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 5746)
+++ /pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 5747)
@@ -1471,4 +1471,7 @@
     }
 
+    /* Start media transport */
+    pjmedia_transport_media_start(audio->transport, 0, 0, 0, 0);
+
     /* Start media thread. */
     audio->thread_quit_flag = 0;
Index: /pjproject/trunk/pjsip-apps/src/samples/streamutil.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/streamutil.c	(revision 5746)
+++ /pjproject/trunk/pjsip-apps/src/samples/streamutil.c	(revision 5747)
@@ -345,4 +345,7 @@
 	return status;
     }
+
+    /* Start media transport */
+    pjmedia_transport_media_start(transport, 0, 0, 0, 0);
 
 
Index: /pjproject/trunk/pjsip-apps/src/samples/vid_streamutil.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/vid_streamutil.c	(revision 5746)
+++ /pjproject/trunk/pjsip-apps/src/samples/vid_streamutil.c	(revision 5747)
@@ -286,4 +286,6 @@
     }
 
+    /* Start media transport */
+    pjmedia_transport_media_start(transport, 0, 0, 0, 0);
 
     return PJ_SUCCESS;
