Index: pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5907)
+++ pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 6005)
@@ -19,4 +19,5 @@
  */
 #include <pjmedia/transport_udp.h>
+#include <pj/compat/socket.h>
 #include <pj/addr_resolv.h>
 #include <pj/assert.h>
@@ -27,5 +28,4 @@
 #include <pj/rand.h>
 #include <pj/string.h>
-
 
 /* Maximum size of incoming RTP packet */
@@ -155,10 +155,6 @@
 				       unsigned pct_lost);
 static pj_status_t transport_destroy  (pjmedia_transport *tp);
-
-#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
-	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
 static pj_status_t transport_restart  (pj_bool_t is_rtp, 
 				       struct transport_udp *udp);
-#endif
 
 static pjmedia_transport_op transport_udp_op = 
@@ -454,4 +450,44 @@
 }
 
+/* Call RTP cb. */
+static void call_rtp_cb(struct transport_udp *udp, pj_ssize_t bytes_read, 
+			pj_bool_t *rem_switch)
+{
+    void (*cb)(void*,void*,pj_ssize_t);
+    void (*cb2)(pjmedia_tp_cb_param*);
+    void *user_data;
+
+    cb = udp->rtp_cb;
+    cb2 = udp->rtp_cb2;
+    user_data = udp->user_data;
+
+    if (cb2) {
+	pjmedia_tp_cb_param param;
+
+	param.user_data = user_data;
+	param.pkt = udp->rtp_pkt;
+	param.size = bytes_read;
+	param.src_addr = &udp->rtp_src_addr;
+	param.rem_switch = PJ_FALSE;
+	(*cb2)(&param);
+	if (rem_switch)
+	    *rem_switch = param.rem_switch;
+    } else if (cb) {
+	(*cb)(user_data, udp->rtp_pkt, bytes_read);
+    }
+}
+
+/* Call RTCP cb. */
+static void call_rtcp_cb(struct transport_udp *udp, pj_ssize_t bytes_read)
+{
+    void(*cb)(void*, void*, pj_ssize_t);
+    void *user_data;
+
+    cb = udp->rtcp_cb;
+    user_data = udp->user_data;
+
+    if (cb)
+	(*cb)(user_data, udp->rtcp_pkt, bytes_read);
+}
 
 /* Notification from ioqueue about incoming RTP packet */
@@ -463,4 +499,7 @@
     pj_status_t status;
     pj_bool_t rem_switch = PJ_FALSE;
+    pj_bool_t transport_restarted = PJ_FALSE;
+    unsigned num_err = 0;
+    pj_status_t last_err = PJ_SUCCESS;
 
     PJ_UNUSED_ARG(op_key);
@@ -470,29 +509,16 @@
     udp = (struct transport_udp*) pj_ioqueue_get_user_data(key);
 
-#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
-	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
     if (-bytes_read == PJ_ESOCKETSTOP) {
 	/* Try to recover by restarting the transport. */
-	PJ_LOG(4, (udp->base.name, "Restarting RTP transport"));
 	status = transport_restart(PJ_TRUE, udp);
-	if (status == PJ_SUCCESS) {
-	    PJ_LOG(4, (udp->base.name, "Success restarting RTP transport"));
-	} else {
-	    PJ_PERROR(1, (udp->base.name, status, 
-			  "Error restarting RTP transport"));
+	if (status != PJ_SUCCESS) {
+	    bytes_read = -PJ_ESOCKETSTOP;
+	    call_rtp_cb(udp, bytes_read, NULL);
 	}
 	return;
     }
-#endif
 
     do {
-	void (*cb)(void*,void*,pj_ssize_t);
-	void (*cb2)(pjmedia_tp_cb_param*);
-	void *user_data;
 	pj_bool_t discard = PJ_FALSE;
-
-	cb = udp->rtp_cb;
-	cb2 = udp->rtp_cb2;
-	user_data = udp->user_data;
 
 	/* Simulate packet lost on RX direction */
@@ -507,18 +533,8 @@
 
 	//if (!discard && udp->attached && cb)
-	if (!discard) {
-	    if (cb2) {
-		pjmedia_tp_cb_param param;
-
-	    	param.user_data = user_data;
-	    	param.pkt = udp->rtp_pkt;
-	    	param.size = bytes_read;
-	    	param.src_addr = &udp->rtp_src_addr;
-	    	param.rem_switch = PJ_FALSE;
-	    	(*cb2)(&param);
-	    	rem_switch = param.rem_switch;
-	    } else if (cb) {
-	    	(*cb)(user_data, udp->rtp_pkt, bytes_read);
-	    }
+	if (!discard && 
+	    (-bytes_read != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))) 
+	{
+	    call_rtp_cb(udp, bytes_read, &rem_switch);
 	}
 
@@ -566,11 +582,37 @@
 	udp->rtp_addrlen = sizeof(udp->rtp_src_addr);
 	status = pj_ioqueue_recvfrom(udp->rtp_key, &udp->rtp_read_op,
-				     udp->rtp_pkt, &bytes_read, 0,
-				     &udp->rtp_src_addr, 
-				     &udp->rtp_addrlen);
-
-	if (status != PJ_EPENDING && status != PJ_SUCCESS)
+					udp->rtp_pkt, &bytes_read, 0,
+					&udp->rtp_src_addr,
+					&udp->rtp_addrlen);
+
+	if (status != PJ_EPENDING && status != PJ_SUCCESS) {	    
+	    if (transport_restarted && last_err == status) {
+		/* Still the same error after restart */
+		bytes_read = -PJ_ESOCKETSTOP;
+		call_rtp_cb(udp, bytes_read, NULL);
+		break;
+	    } else if (PJMEDIA_IGNORE_RECV_ERR_CNT) {
+		if (last_err == status) {
+		    ++num_err;
+		} else {
+		    num_err = 1;
+		    last_err = status;
+		}
+
+		if (status == PJ_ESOCKETSTOP ||
+		    num_err > PJMEDIA_IGNORE_RECV_ERR_CNT)
+		{
+		    status = transport_restart(PJ_TRUE, udp);		    
+		    if (status != PJ_SUCCESS) {
+			bytes_read = -PJ_ESOCKETSTOP;
+			call_rtp_cb(udp, bytes_read, NULL);
+			break;
+		    }
+		    transport_restarted = PJ_TRUE;
+		    num_err = 0;
+		}
+	    }
 	    bytes_read = -status;
-
+	}
     } while (status != PJ_EPENDING && status != PJ_ECANCELLED &&
 	     udp->started);
@@ -585,4 +627,7 @@
     struct transport_udp *udp;
     pj_status_t status = PJ_SUCCESS;
+    pj_bool_t transport_restarted = PJ_FALSE;
+    unsigned num_err = 0;
+    pj_status_t last_err = PJ_SUCCESS;
 
     PJ_UNUSED_ARG(op_key);
@@ -592,30 +637,16 @@
     udp = (struct transport_udp*) pj_ioqueue_get_user_data(key);
 
-#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
-	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
     if (-bytes_read == PJ_ESOCKETSTOP) {
 	/* Try to recover by restarting the transport. */
-	PJ_LOG(4, (udp->base.name, "Restarting RTCP transport"));
 	status = transport_restart(PJ_FALSE, udp);
-	if (status == PJ_SUCCESS) {
-	    PJ_LOG(4, (udp->base.name, "Success restarting RTCP transport"));
-	} else {
-	    PJ_PERROR(1, (udp->base.name, status, 
-			  "Error restarting RTCP transport"));
+	if (status != PJ_SUCCESS) {
+	    bytes_read = -PJ_ESOCKETSTOP;
+	    call_rtcp_cb(udp, bytes_read);
 	}
 	return;
     }
-#endif
 
     do {
-	void (*cb)(void*,void*,pj_ssize_t);
-	void *user_data;
-
-	cb = udp->rtcp_cb;
-	user_data = udp->user_data;
-
-	//if (udp->attached && cb)
-	if (cb)
-	    (*cb)(user_data, udp->rtcp_pkt, bytes_read);
+	call_rtcp_cb(udp, bytes_read);
 
 #if defined(PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR) && \
@@ -656,7 +687,34 @@
 				     &udp->rtcp_src_addr, 
 				     &udp->rtcp_addr_len);
-	if (status != PJ_EPENDING && status != PJ_SUCCESS)
+
+	if (status != PJ_EPENDING && status != PJ_SUCCESS) {
+	    if (transport_restarted && last_err == status) {
+		/* Still the same error after restart */
+		bytes_read = -PJ_ESOCKETSTOP;
+		call_rtcp_cb(udp, bytes_read);
+		break;
+	    } else if (PJMEDIA_IGNORE_RECV_ERR_CNT) {
+		if (last_err == status) {
+		    ++num_err;
+		} else {
+		    num_err = 1;
+		    last_err = status;
+		}
+
+		if (status == PJ_ESOCKETSTOP ||
+		    num_err > PJMEDIA_IGNORE_RECV_ERR_CNT)
+		{
+		    status = transport_restart(PJ_FALSE, udp);		    
+		    if (status != PJ_SUCCESS) {
+			bytes_read = -PJ_ESOCKETSTOP;
+			call_rtcp_cb(udp, bytes_read);
+			break;
+		    }
+		    transport_restarted = PJ_TRUE;
+		    num_err = 0;
+		}
+	    }
 	    bytes_read = -status;
-
+	}	
     } while (status != PJ_EPENDING && status != PJ_ECANCELLED &&
 	     udp->started);
@@ -928,4 +986,8 @@
     PJ_ASSERT_RETURN(size <= PJMEDIA_MAX_MTU, PJ_ETOOBIG);
 
+    if (!udp->started) {
+	return PJ_SUCCESS;
+    }
+
     /* Simulate packet lost on TX direction */
     if (udp->tx_drop_pct) {
@@ -985,4 +1047,8 @@
 
     //PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP);
+
+    if (!udp->started) {
+	return PJ_SUCCESS;
+    }
 
     if (addr == NULL) {
@@ -1181,7 +1247,5 @@
 }
 
-#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
-	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
-static pj_status_t transport_restart(pj_bool_t is_rtp,
+static pj_status_t transport_restart(pj_bool_t is_rtp, 
 				     struct transport_udp *udp)
 {
@@ -1194,4 +1258,8 @@
     pj_ssize_t size;
 
+    PJ_LOG(4, (udp->base.name, "Restarting %s transport", 
+	      (is_rtp)?"RTP":"RTCP"));
+
+    udp->started = PJ_FALSE;
     /* Destroy existing socket, if any. */    
     if (key) {
@@ -1208,5 +1276,5 @@
 	pj_sock_close(*sock);
     }
-    *sock = PJ_INVALID_SOCKET;
+    *sock = PJ_INVALID_SOCKET;   
 
     /* Create socket */
@@ -1224,41 +1292,17 @@
     /* Set buffer size for RTP socket */
 #if PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE
-    {
+    if (is_rtp) {
 	unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE;
 
-	status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_RCVBUF(),
-					  PJ_TRUE, &sobuf_size);
-	if (status != PJ_SUCCESS) {
-	    pj_perror(3, udp->base.name, status, "Failed setting SO_RCVBUF");
-	} else {
-	    if (sobuf_size < PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE) {
-		PJ_LOG(4, (udp->base.name,
-			   "Warning! Cannot set SO_RCVBUF as configured, "
-			   "now=%d, configured=%d",
-			   sobuf_size, PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE));
-	    } else {
-		PJ_LOG(5, (udp->base.name, "SO_RCVBUF set to %d", sobuf_size));
-	    }
-	}
+	pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_RCVBUF(), 
+				 PJ_TRUE, &sobuf_size);
     }
 #endif
 #if PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE
-    {
+    if (is_rtp) {
 	unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE;
 
-	status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_SNDBUF(),
-					  PJ_TRUE, &sobuf_size);
-	if (status != PJ_SUCCESS) {
-	    pj_perror(3, udp->base.name, status, "Failed setting SO_SNDBUF");
-	} else {
-	    if (sobuf_size < PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE) {
-		PJ_LOG(4, (udp->base.name,
-			   "Warning! Cannot set SO_SNDBUF as configured, "
-			   "now=%d, configured=%d",
-			   sobuf_size, PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE));
-	    } else {
-		PJ_LOG(5, (udp->base.name, "SO_SNDBUF set to %d", sobuf_size));
-	    }
-	}
+	pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_SNDBUF(), 
+				 PJ_TRUE, &sobuf_size);
     }
 #endif
@@ -1296,5 +1340,7 @@
 	goto on_error;
 
-
+    udp->started = PJ_TRUE;
+    PJ_LOG(4, (udp->base.name, "Success restarting %s transport", 
+	      (is_rtp)?"RTP":"RTCP"));
     return PJ_SUCCESS;
 on_error:
@@ -1303,5 +1349,6 @@
 	*sock = PJ_INVALID_SOCKET;
     }
+    PJ_PERROR(1, (udp->base.name, status, 
+		 "Error restarting %s transport", (is_rtp)?"RTP":"RTCP"));
     return status;
 }
-#endif
