Index: /pjproject/trunk/pjlib/include/pj/sock.h
===================================================================
--- /pjproject/trunk/pjlib/include/pj/sock.h	(revision 4537)
+++ /pjproject/trunk/pjlib/include/pj/sock.h	(revision 4538)
@@ -1308,4 +1308,25 @@
 
 /**
+ * Helper function to set socket buffer size using #pj_sock_setsockopt()
+ * with capability to auto retry with lower buffer setting value until
+ * the highest possible value is successfully set.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param optname	The option name, valid values are pj_SO_RCVBUF()
+ *			and pj_SO_SNDBUF().
+ * @param auto_retry	Option whether auto retry with lower value is
+ *			enabled.
+ * @param buf_size	On input, specify the prefered buffer size setting,
+ *			on output, the buffer size setting applied.
+ *
+ * @return		PJ_SUCCESS or the status code.
+ */
+PJ_DECL(pj_status_t) pj_sock_setsockopt_sobuf( pj_sock_t sockfd,
+					       pj_uint16_t optname,
+					       pj_bool_t auto_retry,
+					       unsigned *buf_size);
+
+
+/**
  * Receives data stream or message coming to the specified socket.
  *
Index: /pjproject/trunk/pjlib/src/pj/sock_common.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/sock_common.c	(revision 4537)
+++ /pjproject/trunk/pjlib/src/pj/sock_common.c	(revision 4538)
@@ -1080,4 +1080,67 @@
 
 
+/*
+ * Adjust socket send/receive buffer size.
+ */
+PJ_DEF(pj_status_t) pj_sock_setsockopt_sobuf( pj_sock_t sockfd,
+					      pj_uint16_t optname,
+					      pj_bool_t auto_retry,
+					      unsigned *buf_size)
+{
+    pj_status_t status;
+    int try_size, cur_size, i, step, size_len;
+    enum { MAX_TRY = 20 };
+
+    PJ_CHECK_STACK();
+
+    PJ_ASSERT_RETURN(sockfd != PJ_INVALID_SOCKET &&
+		     buf_size &&
+		     *buf_size > 0 &&
+		     (optname == pj_SO_RCVBUF() ||
+		      optname == pj_SO_SNDBUF()),
+		     PJ_EINVAL);
+
+    size_len = sizeof(cur_size);
+    status = pj_sock_getsockopt(sockfd, pj_SOL_SOCKET(), optname,
+				&cur_size, &size_len);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    try_size = *buf_size;
+    step = (try_size - cur_size) / MAX_TRY;
+    if (step < 4096)
+	step = 4096;
+
+    for (i = 0; i < (MAX_TRY-1); ++i) {
+	if (try_size <= cur_size) {
+	    /* Done, return current size */
+	    *buf_size = cur_size;
+	    break;
+	}
+
+	status = pj_sock_setsockopt(sockfd, pj_SOL_SOCKET(), optname,
+				    &try_size, sizeof(try_size));
+	if (status == PJ_SUCCESS) {
+	    status = pj_sock_getsockopt(sockfd, pj_SOL_SOCKET(), optname,
+					&cur_size, &size_len);
+	    if (status != PJ_SUCCESS) {
+		/* Ops! No info about current size, just return last try size
+		 * and quit.
+		 */
+		*buf_size = try_size;
+		break;
+	    }
+	}
+
+	if (!auto_retry)
+	    break;
+
+	try_size -= step;
+    }
+
+    return status;
+}
+
+
 /* Only need to implement these in DLL build */
 #if defined(PJ_DLL)
Index: /pjproject/trunk/pjmedia/include/pjmedia/config.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 4537)
+++ /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 4538)
@@ -1218,4 +1218,44 @@
 
 /**
+ * Specify target value for socket receive buffer size. It will be
+ * applied to RTP socket of media transport using setsockopt(). When
+ * transport failed to set the specified size, it will try with lower
+ * value until the highest possible is successfully set.
+ *
+ * Setting this to zero will leave the socket receive buffer size to
+ * OS default (e.g: usually 8 KB on desktop platforms).
+ *
+ * Default: 64 KB when video is enabled, otherwise zero (OS default)
+ */
+#ifndef PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE
+#   if PJMEDIA_HAS_VIDEO
+#	define PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE	(64*1024)
+#   else
+#	define PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE	0
+#   endif
+#endif
+
+
+/**
+ * Specify target value for socket send buffer size. It will be
+ * applied to RTP socket of media transport using setsockopt(). When
+ * transport failed to set the specified size, it will try with lower
+ * value until the highest possible is successfully set.
+ *
+ * Setting this to zero will leave the socket send buffer size to
+ * OS default (e.g: usually 8 KB on desktop platforms).
+ *
+ * Default: 64 KB when video is enabled, otherwise zero (OS default)
+ */
+#ifndef PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE
+#   if PJMEDIA_HAS_VIDEO
+#	define PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE	(64*1024)
+#   else
+#	define PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE	0
+#   endif
+#endif
+
+
+/**
  * @}
  */
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 4537)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 4538)
@@ -226,4 +226,5 @@
     pj_pool_t *pool;
     pj_ice_strans_cb ice_st_cb;
+    pj_ice_strans_cfg ice_st_cfg;
     struct transport_ice *tp_ice;
     pj_status_t status;
@@ -246,4 +247,5 @@
     tp_ice->use_ice = PJ_FALSE;
 
+    pj_memcpy(&ice_st_cfg, cfg, sizeof(pj_ice_strans_cfg));
     if (cb)
 	pj_memcpy(&tp_ice->cb, cb, sizeof(pjmedia_ice_cb));
@@ -259,6 +261,16 @@
     ice_st_cb.on_rx_data = &ice_on_rx_data;
 
+    /* Configure RTP socket buffer settings, if not set */
+    if (ice_st_cfg.comp[COMP_RTP-1].so_rcvbuf_size == 0) {
+	ice_st_cfg.comp[COMP_RTP-1].so_rcvbuf_size = 
+			    PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE;
+    }
+    if (ice_st_cfg.comp[COMP_RTP-1].so_sndbuf_size == 0) {
+	ice_st_cfg.comp[COMP_RTP-1].so_sndbuf_size = 
+			    PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE;
+    }
+
     /* Create ICE */
-    status = pj_ice_strans_create(name, cfg, comp_cnt, tp_ice, 
+    status = pj_ice_strans_create(name, &ice_st_cfg, comp_cnt, tp_ice, 
 				  &ice_st_cb, &tp_ice->ice_st);
     if (status != PJ_SUCCESS) {
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 4537)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 4538)
@@ -694,4 +694,46 @@
     udp->rtcp_src_cnt = 0;
 
+    /* Set buffer size for RTP socket */
+#if PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE
+    {
+	unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE;
+	pj_status_t status;
+	status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_RCVBUF(),
+					  PJ_TRUE, &sobuf_size);
+	if (status != PJ_SUCCESS) {
+	    pj_perror(3, tp->name, status, "Failed setting SO_RCVBUF");
+	} else {
+	    if (sobuf_size < PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE) {
+		PJ_LOG(4, (tp->name, 
+			   "Warning! Cannot set SO_RCVBUF as configured, "
+			   "now=%d, configured=%d",
+			   sobuf_size, PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE));
+	    } else {
+		PJ_LOG(5, (tp->name, "SO_RCVBUF set to %d", sobuf_size));
+	    }
+	}
+    }
+#endif
+#if PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE
+    {
+	unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE;
+	pj_status_t status;
+	status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_SNDBUF(),
+					  PJ_TRUE, &sobuf_size);
+	if (status != PJ_SUCCESS) {
+	    pj_perror(3, tp->name, status, "Failed setting SO_SNDBUF");
+	} else {
+	    if (sobuf_size < PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE) {
+		PJ_LOG(4, (tp->name, 
+			   "Warning! Cannot set SO_SNDBUF as configured, "
+			   "now=%d, configured=%d",
+			   sobuf_size, PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE));
+	    } else {
+		PJ_LOG(5, (tp->name, "SO_SNDBUF set to %d", sobuf_size));
+	    }
+	}
+    }
+#endif
+
     /* Unlock keys */
     pj_ioqueue_unlock_key(udp->rtcp_key);
Index: /pjproject/trunk/pjnath/include/pjnath/ice_strans.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/ice_strans.h	(revision 4537)
+++ /pjproject/trunk/pjnath/include/pjnath/ice_strans.h	(revision 4538)
@@ -371,4 +371,38 @@
 	pj_qos_params qos_params;
 
+	/**
+	 * Specify target value for socket receive buffer size. It will be
+	 * applied using setsockopt(). When it fails to set the specified
+	 * size, it will try with lower value until the highest possible is
+	 * successfully set.
+	 *
+	 * When this is set to zero, this component will apply socket receive
+	 * buffer size settings specified in STUN and TURN socket config
+	 * above, i.e: \a stun::cfg::so_rcvbuf_size and
+	 * \a turn::cfg::so_rcvbuf_size. Otherwise, this setting will be
+	 * applied to STUN and TURN sockets for this component, overriding
+	 * the setting specified in STUN/TURN socket config.
+	 *
+	 * Default: 0
+	 */
+	unsigned so_rcvbuf_size;
+
+	/**
+	 * Specify target value for socket send buffer size. It will be
+	 * applied using setsockopt(). When it fails to set the specified
+	 * size, it will try with lower value until the highest possible is
+	 * successfully set.
+	 *
+	 * When this is set to zero, this component will apply socket send
+	 * buffer size settings specified in STUN and TURN socket config
+	 * above, i.e: \a stun::cfg::so_sndbuf_size and
+	 * \a turn::cfg::so_sndbuf_size. Otherwise, this setting will be
+	 * applied to STUN and TURN sockets for this component, overriding
+	 * the setting specified in STUN/TURN socket config.
+	 *
+	 * Default: 0
+	 */
+	unsigned so_sndbuf_size;
+
     } comp[PJ_ICE_MAX_COMP];
 
Index: /pjproject/trunk/pjnath/include/pjnath/stun_sock.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/stun_sock.h	(revision 4537)
+++ /pjproject/trunk/pjnath/include/pjnath/stun_sock.h	(revision 4538)
@@ -295,4 +295,24 @@
      */
     pj_bool_t qos_ignore_error;
+
+    /**
+     * Specify target value for socket receive buffer size. It will be
+     * applied using setsockopt(). When it fails to set the specified size,
+     * it will try with lower value until the highest possible is
+     * successfully set.
+     *
+     * Default: 0 (OS default)
+     */
+    unsigned so_rcvbuf_size;
+
+    /**
+     * Specify target value for socket send buffer size. It will be
+     * applied using setsockopt(). When it fails to set the specified size,
+     * it will try with lower value until the highest possible is
+     * successfully set.
+     *
+     * Default: 0 (OS default)
+     */
+    unsigned so_sndbuf_size;
 
 } pj_stun_sock_cfg;
Index: /pjproject/trunk/pjnath/include/pjnath/turn_sock.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/turn_sock.h	(revision 4537)
+++ /pjproject/trunk/pjnath/include/pjnath/turn_sock.h	(revision 4538)
@@ -166,4 +166,24 @@
      */
     pj_uint16_t	port_range;
+
+    /**
+     * Specify target value for socket receive buffer size. It will be
+     * applied using setsockopt(). When it fails to set the specified size,
+     * it will try with lower value until the highest possible has been
+     * successfully set.
+     *
+     * Default: 0 (OS default)
+     */
+    unsigned so_rcvbuf_size;
+
+    /**
+     * Specify target value for socket send buffer size. It will be
+     * applied using setsockopt(). When it fails to set the specified size,
+     * it will try with lower value until the highest possible has been
+     * successfully set.
+     *
+     * Default: 0 (OS default)
+     */
+    unsigned so_sndbuf_size;
 
 } pj_turn_sock_cfg;
Index: /pjproject/trunk/pjnath/src/pjnath/ice_strans.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 4537)
+++ /pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 4538)
@@ -297,4 +297,14 @@
     }
 
+    /* Override with component specific socket buffer size settings, if any */
+    if (ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size > 0) {
+	ice_st->cfg.turn.cfg.so_rcvbuf_size = 
+	    ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size;
+    }
+    if (ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size > 0) {
+	ice_st->cfg.turn.cfg.so_sndbuf_size = 
+	    ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size;
+    }
+
     /* Create the TURN transport */
     status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, ice_st->cfg.af,
@@ -382,4 +392,14 @@
 		      &ice_st->cfg.comp[comp_id-1].qos_params,
 		      sizeof(ice_st->cfg.stun.cfg.qos_params));
+	}
+
+	/* Override component specific socket buffer size settings, if any */
+	if (ice_st->cfg.comp[comp_id-1].so_rcvbuf_size > 0) {
+	    ice_st->cfg.stun.cfg.so_rcvbuf_size = 
+		ice_st->cfg.comp[comp_id-1].so_rcvbuf_size;
+	}
+	if (ice_st->cfg.comp[comp_id-1].so_sndbuf_size > 0) {
+	    ice_st->cfg.stun.cfg.so_sndbuf_size = 
+		ice_st->cfg.comp[comp_id-1].so_sndbuf_size;
 	}
 
Index: /pjproject/trunk/pjnath/src/pjnath/stun_sock.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/stun_sock.c	(revision 4537)
+++ /pjproject/trunk/pjnath/src/pjnath/stun_sock.c	(revision 4538)
@@ -238,4 +238,44 @@
 	goto on_error;
 
+    /* Apply socket buffer size */
+    if (cfg->so_rcvbuf_size > 0) {
+	unsigned sobuf_size = cfg->so_rcvbuf_size;
+	status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_RCVBUF(),
+					  PJ_TRUE, &sobuf_size);
+	if (status != PJ_SUCCESS) {
+	    pj_perror(3, stun_sock->obj_name, status,
+		      "Failed setting SO_RCVBUF");
+	} else {
+	    if (sobuf_size < cfg->so_rcvbuf_size) {
+		PJ_LOG(4, (stun_sock->obj_name, 
+			   "Warning! Cannot set SO_RCVBUF as configured, "
+			   "now=%d, configured=%d",
+			   sobuf_size, cfg->so_rcvbuf_size));
+	    } else {
+		PJ_LOG(5, (stun_sock->obj_name, "SO_RCVBUF set to %d",
+			   sobuf_size));
+	    }
+	}
+    }
+    if (cfg->so_sndbuf_size > 0) {
+	unsigned sobuf_size = cfg->so_sndbuf_size;
+	status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_SNDBUF(),
+					  PJ_TRUE, &sobuf_size);
+	if (status != PJ_SUCCESS) {
+	    pj_perror(3, stun_sock->obj_name, status,
+		      "Failed setting SO_SNDBUF");
+	} else {
+	    if (sobuf_size < cfg->so_sndbuf_size) {
+		PJ_LOG(4, (stun_sock->obj_name, 
+			   "Warning! Cannot set SO_SNDBUF as configured, "
+			   "now=%d, configured=%d",
+			   sobuf_size, cfg->so_sndbuf_size));
+	    } else {
+		PJ_LOG(5, (stun_sock->obj_name, "SO_SNDBUF set to %d",
+			   sobuf_size));
+	    }
+	}
+    }
+
     /* Bind socket */
     max_bind_retry = MAX_BIND_RETRY;
Index: /pjproject/trunk/pjnath/src/pjnath/turn_sock.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/turn_sock.c	(revision 4537)
+++ /pjproject/trunk/pjnath/src/pjnath/turn_sock.c	(revision 4538)
@@ -811,4 +811,44 @@
 	}
 
+	/* Apply socket buffer size */
+	if (turn_sock->setting.so_rcvbuf_size > 0) {
+	    unsigned sobuf_size = turn_sock->setting.so_rcvbuf_size;
+	    status = pj_sock_setsockopt_sobuf(sock, pj_SO_RCVBUF(),
+					      PJ_TRUE, &sobuf_size);
+	    if (status != PJ_SUCCESS) {
+		pj_perror(3, turn_sock->obj_name, status,
+			  "Failed setting SO_RCVBUF");
+	    } else {
+		if (sobuf_size < turn_sock->setting.so_rcvbuf_size) {
+		    PJ_LOG(4, (turn_sock->obj_name, 
+			       "Warning! Cannot set SO_RCVBUF as configured,"
+			       " now=%d, configured=%d", sobuf_size,
+			       turn_sock->setting.so_rcvbuf_size));
+		} else {
+		    PJ_LOG(5, (turn_sock->obj_name, "SO_RCVBUF set to %d",
+			       sobuf_size));
+		}
+	    }
+	}
+	if (turn_sock->setting.so_sndbuf_size > 0) {
+	    unsigned sobuf_size = turn_sock->setting.so_sndbuf_size;
+	    status = pj_sock_setsockopt_sobuf(sock, pj_SO_SNDBUF(),
+					      PJ_TRUE, &sobuf_size);
+	    if (status != PJ_SUCCESS) {
+		pj_perror(3, turn_sock->obj_name, status,
+			  "Failed setting SO_SNDBUF");
+	    } else {
+		if (sobuf_size < turn_sock->setting.so_sndbuf_size) {
+		    PJ_LOG(4, (turn_sock->obj_name, 
+			       "Warning! Cannot set SO_SNDBUF as configured,"
+			       " now=%d, configured=%d", sobuf_size,
+			       turn_sock->setting.so_sndbuf_size));
+		} else {
+		    PJ_LOG(5, (turn_sock->obj_name, "SO_SNDBUF set to %d",
+			       sobuf_size));
+		}
+	    }
+	}
+
 	/* Create active socket */
 	pj_activesock_cfg_default(&asock_cfg);
