summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2009-02-19 20:36:09 +0200
committerJohan Hedberg <johan.hedberg@nokia.com>2009-02-19 20:36:09 +0200
commit3e3b34a52fd3957421adbae2cf9258bc4adf5d7e (patch)
tree63eafb655db9908b71c73e330fa9943b336c4afd /audio
parentba1b8ea534d8680b128755ffd0bc26b35e248699 (diff)
Convert AVDTP code to use btio confirm_cb
Diffstat (limited to 'audio')
-rw-r--r--audio/avdtp.c434
1 files changed, 210 insertions, 224 deletions
diff --git a/audio/avdtp.c b/audio/avdtp.c
index da1a4df7..62a9a8fc 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -334,7 +334,7 @@ struct stream_callback {
};
struct avdtp_stream {
- int sock;
+ GIOChannel *io;
uint16_t imtu;
uint16_t omtu;
struct avdtp *session;
@@ -343,7 +343,7 @@ struct avdtp_stream {
GSList *caps;
GSList *callbacks;
struct avdtp_service_capability *codec;
- guint io; /* Transport GSource ID */
+ guint io_id; /* Transport GSource ID */
guint timer; /* Waiting for other side to close or open
the transport channel */
gboolean open_acp; /* If we are in ACT role for Open */
@@ -366,8 +366,8 @@ struct avdtp {
/* True if the session should be automatically disconnected */
gboolean auto_dc;
- guint io;
- int sock;
+ GIOChannel *io;
+ guint io_id;
GSList *seps; /* Elements of type struct avdtp_remote_sep * */
@@ -478,12 +478,15 @@ static gboolean avdtp_send(struct avdtp *session, uint8_t transaction,
unsigned int cont_fragments, sent;
struct avdtp_start_header start;
struct avdtp_continue_header cont;
+ int sock;
- if (session->sock < 0) {
+ if (session->io == NULL) {
error("avdtp_send: session is closed");
return FALSE;
}
+ sock = g_io_channel_unix_get_fd(session->io);
+
/* Single packet - no fragmentation */
if (sizeof(struct avdtp_single_header) + len <= session->omtu) {
struct avdtp_single_header single;
@@ -498,8 +501,7 @@ static gboolean avdtp_send(struct avdtp *session, uint8_t transaction,
memcpy(session->buf, &single, sizeof(single));
memcpy(session->buf + sizeof(single), data, len);
- return try_send(session->sock, session->buf,
- sizeof(single) + len);
+ return try_send(sock, session->buf, sizeof(single) + len);
}
/* Count the number of needed fragments */
@@ -521,7 +523,7 @@ static gboolean avdtp_send(struct avdtp *session, uint8_t transaction,
memcpy(session->buf + sizeof(start), data,
session->omtu - sizeof(start));
- if (!try_send(session->sock, session->buf, session->omtu))
+ if (!try_send(sock, session->buf, session->omtu))
return FALSE;
debug("avdtp_send: first packet with %d bytes sent",
@@ -552,8 +554,7 @@ static gboolean avdtp_send(struct avdtp *session, uint8_t transaction,
memcpy(session->buf, &cont, sizeof(cont));
memcpy(session->buf + sizeof(cont), data + sent, to_copy);
- if (!try_send(session->sock, session->buf,
- to_copy + sizeof(cont)))
+ if (!try_send(sock, session->buf, to_copy + sizeof(cont)))
return FALSE;
sent += to_copy;
@@ -578,7 +579,7 @@ static gboolean stream_close_timeout(gpointer user_data)
stream->timer = 0;
- close(stream->sock);
+ g_io_channel_shutdown(stream->io, FALSE, NULL);
return FALSE;
}
@@ -710,11 +711,13 @@ static void stream_free(struct avdtp_stream *stream)
if (stream->timer)
g_source_remove(stream->timer);
- if (stream->sock >= 0)
- close(stream->sock);
+ if (stream->io) {
+ g_io_channel_shutdown(stream->io, FALSE, NULL);
+ g_io_channel_unref(stream->io);
+ }
- if (stream->io)
- g_source_remove(stream->io);
+ if (stream->io_id)
+ g_source_remove(stream->io_id);
g_slist_foreach(stream->callbacks, (GFunc) g_free, NULL);
g_slist_free(stream->callbacks);
@@ -754,12 +757,11 @@ static gboolean transport_cb(GIOChannel *chan, GIOCondition cond,
return FALSE;
}
-static void handle_transport_connect(struct avdtp *session, int sock,
+static void handle_transport_connect(struct avdtp *session, GIOChannel *io,
uint16_t imtu, uint16_t omtu)
{
struct avdtp_stream *stream = session->pending_open;
struct avdtp_local_sep *sep = stream->lsep;
- GIOChannel *channel;
session->pending_open = NULL;
@@ -768,7 +770,7 @@ static void handle_transport_connect(struct avdtp *session, int sock,
stream->timer = 0;
}
- if (sock < 0) {
+ if (io == NULL) {
if (!stream->open_acp && sep->cfm && sep->cfm->open) {
struct avdtp_error err;
avdtp_error_init(&err, AVDTP_ERROR_ERRNO, EIO);
@@ -778,7 +780,7 @@ static void handle_transport_connect(struct avdtp *session, int sock,
return;
}
- stream->sock = sock;
+ stream->io = g_io_channel_ref(io);
stream->omtu = omtu;
stream->imtu = imtu;
@@ -787,11 +789,8 @@ static void handle_transport_connect(struct avdtp *session, int sock,
avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
- channel = g_io_channel_unix_new(stream->sock);
-
- stream->io = g_io_add_watch(channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ stream->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
(GIOFunc) transport_cb, stream);
- g_io_channel_unref(channel);
}
static void avdtp_sep_set_state(struct avdtp *session,
@@ -847,7 +846,7 @@ static void avdtp_sep_set_state(struct avdtp *session,
}
session->streams = g_slist_remove(session->streams, stream);
if (session->pending_open == stream)
- handle_transport_connect(session, -1, 0, 0);
+ handle_transport_connect(session, NULL, 0, 0);
if (session->req && session->req->stream == stream)
session->req->stream = NULL;
stream_free(stream);
@@ -913,16 +912,17 @@ static void connection_lost(struct avdtp *session, int err)
session->free_lock = 0;
- if (session->sock >= 0) {
- close(session->sock);
- session->sock = -1;
+ if (session->io) {
+ g_io_channel_shutdown(session->io, FALSE, NULL);
+ g_io_channel_unref(session->io);
+ session->io = NULL;
}
session->state = AVDTP_SESSION_STATE_DISCONNECTED;
- if (session->io) {
- g_source_remove(session->io);
- session->io = 0;
+ if (session->io_id) {
+ g_source_remove(session->io_id);
+ session->io_id = 0;
}
if (session->ref != 1)
@@ -946,12 +946,14 @@ void avdtp_unref(struct avdtp *session)
debug("avdtp_unref(%p): ref=%d", session, session->ref);
if (session->ref == 1) {
- if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
- close(session->sock);
- session->sock = -1;
+ if (session->state == AVDTP_SESSION_STATE_CONNECTING &&
+ session->io) {
+ g_io_channel_shutdown(session->io, TRUE, NULL);
+ g_io_channel_unref(session->io);
+ session->io = NULL;
}
- if (session->sock >= 0)
+ if (session->io)
set_disconnect_timer(session);
else if (!session->free_lock) /* Drop the local ref if we
aren't connected */
@@ -1192,7 +1194,6 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
stream->caps = caps_to_list(req->caps,
size - sizeof(struct setconf_req),
&stream->codec);
- stream->sock = -1;
if (sep->ind && sep->ind->set_configuration) {
if (!sep->ind->set_configuration(session, sep, stream,
@@ -1765,15 +1766,71 @@ failed:
return FALSE;
}
-static void l2cap_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+static struct avdtp *find_session(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ GSList *l;
+
+ for (l = sessions; l != NULL; l = g_slist_next(l)) {
+ struct avdtp *s = l->data;
+
+ if (bacmp(src, &s->server->src) || bacmp(dst, &s->dst))
+ continue;
+
+ return s;
+ }
+
+ return NULL;
+}
+
+static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ struct avdtp *session;
+
+ assert(src != NULL);
+ assert(dst != NULL);
+
+ session = find_session(src, dst);
+ if (session) {
+ if (session->pending_auth)
+ return NULL;
+ else
+ return session;
+ }
+
+ session = g_new0(struct avdtp, 1);
+
+ session->server = find_server(servers, src);
+ bacpy(&session->dst, dst);
+ session->ref = 1;
+ session->state = AVDTP_SESSION_STATE_DISCONNECTED;
+ session->auto_dc = TRUE;
+
+ sessions = g_slist_append(sessions, session);
+
+ return session;
+}
+
+struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct avdtp *session;
+
+ session = avdtp_get_internal(src, dst);
+
+ if (!session)
+ return NULL;
+
+ return avdtp_ref(session);
+}
+
+static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
struct avdtp *session = user_data;
- int sk;
char address[18];
GError *gerr = NULL;
if (!g_slist_find(sessions, session)) {
- debug("l2cap_connect_cb: session got removed");
+ debug("avdtp_connect_cb: session got removed");
+ g_io_channel_close(chan);
return;
}
@@ -1782,10 +1839,8 @@ static void l2cap_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
goto failed;
}
- sk = g_io_channel_unix_get_fd(chan);
-
if (session->state == AVDTP_SESSION_STATE_DISCONNECTED) {
- session->sock = sk;
+ session->io = g_io_channel_ref(chan);
session->state = AVDTP_SESSION_STATE_CONNECTING;
}
@@ -1811,17 +1866,27 @@ static void l2cap_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
session->buf = g_malloc0(session->imtu);
session->state = AVDTP_SESSION_STATE_CONNECTED;
- session->io = g_io_add_watch(chan,
+ session->io_id = g_io_add_watch(chan,
G_IO_IN | G_IO_ERR | G_IO_HUP
| G_IO_NVAL,
(GIOFunc) session_cb, session);
+ if (session->stream_setup) {
+ set_disconnect_timer(session);
+ avdtp_set_auto_disconnect(session, FALSE);
+ }
+
dev = manager_find_device(&session->dst,
- AUDIO_CONTROL_INTERFACE, FALSE);
- if (dev)
- avrcp_connect(dev);
+ AUDIO_CONTROL_INTERFACE, FALSE);
+ if (dev && dev->control) {
+ if (session->stream_setup)
+ device_set_control_timer(dev);
+ else
+ avrcp_connect(dev);
+ }
} else if (session->pending_open)
- handle_transport_connect(session, sk, session->imtu, session->omtu);
+ handle_transport_connect(session, chan, session->imtu,
+ session->omtu);
else
goto failed;
@@ -1833,7 +1898,7 @@ failed:
if (session->pending_open) {
struct avdtp_stream *stream = session->pending_open;
- handle_transport_connect(session, -1, 0, 0);
+ handle_transport_connect(session, NULL, 0, 0);
if (avdtp_abort(session, stream) < 0)
avdtp_sep_set_state(session, stream->lsep,
@@ -1844,12 +1909,100 @@ failed:
return;
}
+static void auth_cb(DBusError *derr, void *user_data)
+{
+ struct avdtp *session = user_data;
+ GError *err = NULL;
+
+ if (derr && dbus_error_is_set(derr)) {
+ error("Access denied: %s", derr->message);
+ connection_lost(session, -EACCES);
+ return;
+ }
+
+ if (!bt_io_accept(session->io, avdtp_connect_cb, session, NULL,
+ &err)) {
+ error("bt_io_accept: %s", err->message);
+ connection_lost(session, -EACCES);
+ g_error_free(err);
+ return;
+ }
+
+ /* Here we set the disconnect timer so we don't stay in IDLE state
+ * indefinitely but set auto_dc to FALSE so that when a stream is
+ * finally opened it doesn't get closed due to a timeout */
+ session->stream_setup = TRUE;
+}
+
+static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
+{
+ int sk;
+ struct avdtp *session;
+ struct audio_device *dev;
+ char address[18];
+ bdaddr_t src, dst;
+ int perr;
+ GError *err = NULL;
+
+ bt_io_get(chan, BT_IO_L2CAP, &err,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_DEST, address,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ goto drop;
+ }
+
+ debug("AVDTP: incoming connect from %s", address);
+
+ session = avdtp_get_internal(&src, &dst);
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ if (session->pending_open && session->pending_open->open_acp) {
+ if (!bt_io_accept(chan, avdtp_connect_cb, session, NULL, NULL))
+ goto drop;
+ return;
+ }
+
+ if (session->io) {
+ error("Refusing unexpected connect from %s", address);
+ goto drop;
+ }
+
+ dev = manager_get_device(&src, &dst);
+ if (!dev) {
+ error("Unable to get audio device object for %s", address);
+ goto drop;
+ }
+
+ session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) session_cb, session);
+ perr = btd_request_authorization(&src, &dst, ADVANCED_AUDIO_UUID,
+ auth_cb, session);
+ if (perr < 0) {
+ avdtp_unref(session);
+ goto drop;
+ }
+
+ session->io = g_io_channel_ref(chan);
+
+ session->state = AVDTP_SESSION_STATE_CONNECTING;
+
+ return;
+
+drop:
+ g_io_channel_close(chan);
+}
+
static int l2cap_connect(struct avdtp *session)
{
GError *err = NULL;
GIOChannel *io;
- io = bt_io_connect(BT_IO_L2CAP, l2cap_connect_cb, session,
+ io = bt_io_connect(BT_IO_L2CAP, avdtp_connect_cb, session,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &session->server->src,
BT_IO_OPT_DEST_BDADDR, &session->dst,
@@ -2173,8 +2326,7 @@ static gboolean avdtp_close_resp(struct avdtp *session,
avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING);
- close(stream->sock);
- stream->sock = -1;
+ g_io_channel_shutdown(session->io, TRUE, NULL);
return TRUE;
}
@@ -2397,63 +2549,6 @@ static gboolean avdtp_parse_rej(struct avdtp *session,
}
}
-static struct avdtp *find_session(const bdaddr_t *src, const bdaddr_t *dst)
-{
- GSList *l;
-
- for (l = sessions; l != NULL; l = g_slist_next(l)) {
- struct avdtp *s = l->data;
-
- if (bacmp(src, &s->server->src) || bacmp(dst, &s->dst))
- continue;
-
- return s;
- }
-
- return NULL;
-}
-
-static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst)
-{
- struct avdtp *session;
-
- assert(src != NULL);
- assert(dst != NULL);
-
- session = find_session(src, dst);
- if (session) {
- if (session->pending_auth)
- return NULL;
- else
- return session;
- }
-
- session = g_new0(struct avdtp, 1);
-
- session->sock = -1;
- session->server = find_server(servers, src);
- bacpy(&session->dst, dst);
- session->ref = 1;
- session->state = AVDTP_SESSION_STATE_DISCONNECTED;
- session->auto_dc = TRUE;
-
- sessions = g_slist_append(sessions, session);
-
- return session;
-}
-
-struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst)
-{
- struct avdtp *session;
-
- session = avdtp_get_internal(src, dst);
-
- if (!session)
- return NULL;
-
- return avdtp_ref(session);
-}
-
gboolean avdtp_is_connected(const bdaddr_t *src, const bdaddr_t *dst)
{
struct avdtp *session;
@@ -2506,11 +2601,11 @@ gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
uint16_t *imtu, uint16_t *omtu,
GSList **caps)
{
- if (stream->sock < 0)
+ if (stream->io == NULL)
return FALSE;
if (sock)
- *sock = stream->sock;
+ *sock = g_io_channel_unix_get_fd(stream->io);
if (omtu)
*omtu = stream->omtu;
@@ -2727,7 +2822,6 @@ int avdtp_set_configuration(struct avdtp *session,
session, lsep->info.seid, rsep->seid);
new_stream = g_new0(struct avdtp_stream, 1);
- new_stream->sock = -1;
new_stream->session = session;
new_stream->lsep = lsep;
new_stream->rseid = rsep->seid;
@@ -2955,130 +3049,22 @@ int avdtp_unregister_sep(struct avdtp_local_sep *sep)
server = sep->server;
server->seps = g_slist_remove(server->seps, sep);
+ if (sep->stream)
+ avdtp_sep_set_state(sep->stream->session, sep,
+ AVDTP_STATE_IDLE);
+
g_free(sep);
return 0;
}
-static void auth_cb(DBusError *derr, void *user_data)
-{
- struct avdtp *session = user_data;
- struct audio_device *dev;
- GIOChannel *io;
-
- if (derr && dbus_error_is_set(derr)) {
- error("Access denied: %s", derr->message);
-
- connection_lost(session, -EACCES);
- return;
- }
-
- session->buf = g_malloc0(session->imtu);
-
- /* Here we set the disconnect timer so we don't stay in IDLE state
- * indefinitely but set auto_dc to FALSE so that when a stream is
- * finally opened it doesn't get closed due to a timeout */
- session->stream_setup = TRUE;
- set_disconnect_timer(session);
- avdtp_set_auto_disconnect(session, FALSE);
-
- session->state = AVDTP_SESSION_STATE_CONNECTED;
-
- dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE,
- FALSE);
- if (dev && dev->control)
- device_set_control_timer(dev);
-
- g_source_remove(session->io);
-
- io = g_io_channel_unix_new(session->sock);
- session->io = g_io_add_watch(io,
- G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- (GIOFunc) session_cb, session);
- g_io_channel_unref(io);
-}
-
-static void avdtp_server_cb(GIOChannel *chan, GError *err, gpointer data)
-{
- int sk;
- struct avdtp *session;
- struct audio_device *dev;
- char address[18];
- bdaddr_t src, dst;
- uint16_t imtu, omtu;
- int perr;
- GError *gerr = NULL;
-
- if (err) {
- error("%s", err->message);
- return;
- }
-
- bt_io_get(chan, BT_IO_L2CAP, &gerr,
- BT_IO_OPT_SOURCE_BDADDR, &src,
- BT_IO_OPT_DEST_BDADDR, &dst,
- BT_IO_OPT_DEST, address,
- BT_IO_OPT_OMTU, &omtu,
- BT_IO_OPT_IMTU, &imtu,
- BT_IO_OPT_INVALID);
- if (gerr) {
- error("%s", gerr->message);
- g_error_free(gerr);
- goto drop;
- }
-
- debug("AVDTP: incoming connect from %s", address);
-
- session = avdtp_get_internal(&src, &dst);
-
- sk = g_io_channel_unix_get_fd(chan);
-
- if (session->pending_open && session->pending_open->open_acp) {
- handle_transport_connect(session, sk, imtu, omtu);
- return;
- }
-
- if (session->sock >= 0) {
- error("Refusing unexpected connect from %s", address);
- goto drop;
- }
-
- dev = manager_get_device(&src, &dst);
- if (!dev) {
- error("Unable to get audio device object for %s", address);
- goto drop;
- }
-
- session->imtu = imtu;
- session->omtu = omtu;
- session->sock = sk;
-
- debug("AVDTP imtu=%u, omtu=%u", session->imtu, session->omtu);
-
- session->io = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- (GIOFunc) session_cb, session);
- perr = btd_request_authorization(&src, &dst, ADVANCED_AUDIO_UUID,
- auth_cb, session);
- if (perr < 0) {
- avdtp_unref(session);
- goto drop;
- }
-
- session->state = AVDTP_SESSION_STATE_CONNECTING;
-
- return;
-
-drop:
- g_io_channel_close(chan);
-}
-
static GIOChannel *avdtp_server_socket(const bdaddr_t *src, gboolean master)
{
GError *err = NULL;
GIOChannel *io;
- io = bt_io_listen(BT_IO_L2CAP, avdtp_server_cb, NULL, NULL,
- NULL, &err,
+ io = bt_io_listen(BT_IO_L2CAP, avdtp_connect_cb, avdtp_confirm_cb,
+ NULL, NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, src,
BT_IO_OPT_PSM, AVDTP_PSM,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,