Return-Path: From: Dmitriy Paliy To: linux-bluetooth@vger.kernel.org Cc: Dmitriy Paliy Subject: [PATCH] Add AVDTP SRC stream send buffer size verification Date: Wed, 15 Dec 2010 11:48:53 +0200 Message-Id: <1292406533-18574-2-git-send-email-dmitriy.paliy@nokia.com> In-Reply-To: <1292406533-18574-1-git-send-email-dmitriy.paliy@nokia.com> References: <1292406533-18574-1-git-send-email-dmitriy.paliy@nokia.com> Sender: linux-bluetooth-owner@vger.kernel.org List-ID: Functions get_send_buffer_size and set_send_buffer_size are added to avdpt.c. get_send_buffer_size returns size of send buffer for a given socket on success or error code on failure. set_send_buffer_size sets size of send buffer for a given socket, and returns 0 on success or error code on failure. Size of send buffer for L2CAP socket for SRC AVDTP stream is verified during establishment of a new transport channel. If the size is less than twice of outgoing L2CAP MTU, then it is considered as being insufficient to handle streaming data reliably. In this case buffer size is increased to be twice of MTU size. Such fixes some IOP problems with car-kits that use large MTU for music playback. --- audio/avdtp.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 53 insertions(+), 0 deletions(-) diff --git a/audio/avdtp.c b/audio/avdtp.c index 1683e7c..34b95fd 100644 --- a/audio/avdtp.c +++ b/audio/avdtp.c @@ -838,6 +838,40 @@ static gboolean transport_cb(GIOChannel *chan, GIOCondition cond, return FALSE; } +static int get_send_buffer_size(int sk) +{ + int size; + socklen_t optlen = sizeof(size); + + if (getsockopt(sk, SOL_SOCKET, SO_SNDBUF, &size, &optlen) < 0) { + int err = -errno; + error("getsockopt(SO_SNDBUF) failed: %s (%d)", strerror(-err), + -err); + return err; + } + + /* + * Doubled value is returned by getsockopt since kernel uses that + * space for its own purposes (see man 7 socket, bookkeeping overhead + * for SO_SNDBUF). + */ + return size / 2; +} + +static int set_send_buffer_size(int sk, int size) +{ + socklen_t optlen = sizeof(size); + + if (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &size, optlen) < 0) { + int err = -errno; + error("setsockopt(SO_SNDBUF) failed: %s (%d)", strerror(-err), + -err); + return err; + } + + return 0; +} + static void handle_transport_connect(struct avdtp *session, GIOChannel *io, uint16_t imtu, uint16_t omtu) { @@ -865,6 +899,25 @@ static void handle_transport_connect(struct avdtp *session, GIOChannel *io, stream->omtu = omtu; stream->imtu = imtu; + /* only if local SEP is of type SRC */ + if (sep->info.type == AVDTP_SEP_TYPE_SOURCE) { + int sk, buf_size, min_buf_size; + + sk = g_io_channel_unix_get_fd(stream->io); + buf_size = get_send_buffer_size(sk); + if (buf_size < 0) + goto proceed; + + DBG("sk %d, omtu %d, send buffer size %d", sk, omtu, buf_size); + min_buf_size = omtu * 2; + if (buf_size < min_buf_size) { + DBG("send buffer size to be increassed to %d", + min_buf_size); + set_send_buffer_size(sk, min_buf_size); + } + } + +proceed: if (!stream->open_acp && sep->cfm && sep->cfm->open) sep->cfm->open(session, sep, stream, NULL, sep->user_data); -- 1.7.0.4