From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> This stores the channel if it had been connected ahead of Open procedure so it can later be processed. --- profiles/audio/avdtp.c | 75 +++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c index b44a23c48..ae93fb26f 100644 --- a/profiles/audio/avdtp.c +++ b/profiles/audio/avdtp.c @@ -388,6 +388,7 @@ struct avdtp { GSList *prio_queue; /* Same as req_queue but is processed before it */ struct avdtp_stream *pending_open; + GIOChannel *pending_open_io; uint32_t phy; uint16_t imtu; @@ -609,11 +610,33 @@ static gboolean stream_open_timeout(gpointer user_data) stream->session->pending_open = NULL; + if (stream->session->pending_open_io) { + g_io_channel_unref(stream->session->pending_open_io); + stream->session->pending_open_io = NULL; + } + avdtp_abort(stream->session, stream); return FALSE; } +static void stream_set_timer(struct avdtp_stream *stream, guint timeout, + GSourceFunc func) +{ + if (stream->timer) + g_source_remove(stream->timer); + + stream->timer = g_timeout_add_seconds(timeout, func, stream); +} + +static void stream_set_pending_open(struct avdtp_stream *stream, GIOChannel *io) +{ + stream->open_acp = TRUE; + stream->session->pending_open = stream; + stream->session->pending_open_io = io; + stream_set_timer(stream, REQ_TIMEOUT, stream_open_timeout); +} + void avdtp_error_init(struct avdtp_error *err, uint8_t category, int id) { err->category = category; @@ -836,6 +859,12 @@ proceed: stream->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) transport_cb, stream); + + /* Release pending IO */ + if (session->pending_open_io) { + g_io_channel_unref(session->pending_open_io); + session->pending_open_io = NULL; + } } static int pending_req_cmp(gconstpointer a, gconstpointer b) @@ -1674,6 +1703,14 @@ static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction, stream = sep->stream; + /* Check if the stream is pending and there is an IO set already */ + if (stream == session->pending_open && session->pending_open_io) { + handle_transport_connect(session, session->pending_open_io, + stream->imtu, stream->omtu); + return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, + AVDTP_OPEN, NULL, 0); + } + if (sep->ind && sep->ind->open && !session->pending_open) { if (!sep->ind->open(session, sep, stream, &err, sep->user_data)) @@ -1686,13 +1723,8 @@ static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction, AVDTP_OPEN, NULL, 0)) return FALSE; - if (!session->pending_open) { - stream->open_acp = TRUE; - session->pending_open = stream; - stream->timer = g_timeout_add_seconds(REQ_TIMEOUT, - stream_open_timeout, - stream); - } + if (!session->pending_open) + stream_set_pending_open(stream, NULL); return TRUE; @@ -3139,18 +3171,39 @@ struct avdtp_remote_sep *avdtp_stream_get_remote_sep( gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd, size_t imtu, size_t omtu) { - GIOChannel *io; + GIOChannel *io = g_io_channel_unix_new(fd); - if (stream != stream->session->pending_open) - return FALSE; + if (stream != stream->session->pending_open) { + uint8_t err; + + if (stream->session->pending_open) + goto failed; + + /* Attempt to Open there is no pending stream set yet */ + if (stream->lsep->ind && stream->lsep->ind->open) { + if (!stream->lsep->ind->open(stream->session, + stream->lsep, + stream, &err, + stream->lsep->user_data)) + goto failed; + } - io = g_io_channel_unix_new(fd); + stream_set_pending_open(stream, io); + stream->imtu = imtu; + stream->omtu = omtu; + + return TRUE; + } handle_transport_connect(stream->session, io, imtu, omtu); g_io_channel_unref(io); return TRUE; + +failed: + g_io_channel_unref(io); + return FALSE; } gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock, -- 2.26.2