* [PATCH BlueZ v2 1/8] android: Add copy of current AVCTP implemention
@ 2014-01-24 13:24 Luiz Augusto von Dentz
2014-01-24 13:24 ` [PATCH BlueZ v2 2/8] android/AVCTP: Strip dependencies Luiz Augusto von Dentz
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2014-01-24 13:24 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
These files are not added to any makefile on purpose because they still
have external dependencies.
---
v2: Fix issues with dependencies in Android, adds proper reject for messages
that cannot be handled, fix avctp_new not initializing the handlers properly
and finally fixes using 0 instead of NULL in various places.
{profiles/audio => android}/avctp.c | 0
{profiles/audio => android}/avctp.h | 0
2 files changed, 0 insertions(+), 0 deletions(-)
copy {profiles/audio => android}/avctp.c (100%)
copy {profiles/audio => android}/avctp.h (100%)
diff --git a/profiles/audio/avctp.c b/android/avctp.c
similarity index 100%
copy from profiles/audio/avctp.c
copy to android/avctp.c
diff --git a/profiles/audio/avctp.h b/android/avctp.h
similarity index 100%
copy from profiles/audio/avctp.h
copy to android/avctp.h
--
1.8.4.2
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH BlueZ v2 2/8] android/AVCTP: Strip dependencies 2014-01-24 13:24 [PATCH BlueZ v2 1/8] android: Add copy of current AVCTP implemention Luiz Augusto von Dentz @ 2014-01-24 13:24 ` Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 3/8] android: Add initial skeleton for AVRCP in the daemon Luiz Augusto von Dentz ` (5 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: Luiz Augusto von Dentz @ 2014-01-24 13:24 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> This strips AVCTP code of any dependency of core and btio to make it transport agnostic. --- android/Android.mk | 1 + android/Makefile.am | 1 + android/avctp.c | 794 ++++++++-------------------------------------------- android/avctp.h | 40 +-- 4 files changed, 134 insertions(+), 702 deletions(-) diff --git a/android/Android.mk b/android/Android.mk index c274295..fd76f1d 100644 --- a/android/Android.mk +++ b/android/Android.mk @@ -29,6 +29,7 @@ LOCAL_SRC_FILES := \ bluez/android/audio-ipc.c \ bluez/android/avdtp.c \ bluez/android/a2dp.c \ + bluez/android/avctp.c \ bluez/android/pan.c \ bluez/src/log.c \ bluez/src/shared/mgmt.c \ diff --git a/android/Makefile.am b/android/Makefile.am index f85de20..88fe667 100644 --- a/android/Makefile.am +++ b/android/Makefile.am @@ -33,6 +33,7 @@ android_bluetoothd_SOURCES = android/main.c \ android/audio-ipc.h android/audio-ipc.c \ android/avdtp.h android/avdtp.c \ android/a2dp.h android/a2dp.c \ + android/avctp.h android/avctp.c \ android/socket.h android/socket.c \ android/pan.h android/pan.c \ btio/btio.h btio/btio.c \ diff --git a/android/avctp.c b/android/avctp.c index 6669ddc..1255c3e 100644 --- a/android/avctp.c +++ b/android/avctp.c @@ -34,27 +34,19 @@ #include <unistd.h> #include <assert.h> #include <signal.h> +#include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <netinet/in.h> -#include <bluetooth/bluetooth.h> #include <bluetooth/sdp.h> -#include <bluetooth/l2cap.h> #include <glib.h> -#include <btio/btio.h> - -#include "lib/uuid.h" -#include "src/adapter.h" -#include "src/device.h" #include "log.h" -#include "error.h" #include "uinput.h" #include "avctp.h" -#include "avrcp.h" /* AV/C Panel 1.23, page 76: * command with the pressed value is valid for two seconds @@ -115,20 +107,6 @@ struct avc_header { #error "Unknown byte order" #endif -struct avctp_state_callback { - avctp_state_cb cb; - struct btd_device *dev; - unsigned int id; - void *user_data; -}; - -struct avctp_server { - struct btd_adapter *adapter; - GIOChannel *control_io; - GIOChannel *browsing_io; - GSList *sessions; -}; - struct avctp_control_req { struct avctp_pending_req *p; uint8_t code; @@ -157,7 +135,7 @@ struct avctp_pending_req { int err; avctp_process_cb process; void *data; - GDestroyNotify destroy; + avctp_destroy_cb_t destroy; }; struct avctp_channel { @@ -173,7 +151,7 @@ struct avctp_channel { GQueue *queue; GSList *processed; guint process_id; - GDestroyNotify destroy; + avctp_destroy_cb_t destroy; }; struct key_pressed { @@ -182,14 +160,8 @@ struct key_pressed { }; struct avctp { - struct avctp_server *server; - struct btd_device *device; - - avctp_state_t state; - int uinput; - guint auth_id; unsigned int passthrough_id; unsigned int unit_id; unsigned int subunit_id; @@ -201,7 +173,7 @@ struct avctp { uint8_t key_quirks[256]; struct key_pressed key; - bool initiator; + uint16_t version; }; struct avctp_passthrough_handler { @@ -221,7 +193,7 @@ struct avctp_browsing_pdu_handler { avctp_browsing_pdu_cb cb; void *user_data; unsigned int id; - GDestroyNotify destroy; + avctp_destroy_cb_t destroy; }; static struct { @@ -259,10 +231,6 @@ static struct { { NULL } }; -static GSList *callbacks = NULL; -static GSList *servers = NULL; - -static void auth_cb(DBusError *derr, void *user_data); static gboolean process_queue(gpointer user_data); static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code, uint8_t subunit, uint8_t *operands, @@ -488,83 +456,6 @@ static void avctp_channel_destroy(struct avctp_channel *chan) g_free(chan); } -static void avctp_disconnected(struct avctp *session) -{ - struct avctp_server *server; - - if (!session) - return; - - if (session->browsing) - avctp_channel_destroy(session->browsing); - - if (session->control) - avctp_channel_destroy(session->control); - - if (session->auth_id != 0) { - btd_cancel_authorization(session->auth_id); - session->auth_id = 0; - } - - if (session->key.timer > 0) - g_source_remove(session->key.timer); - - if (session->uinput >= 0) { - char address[18]; - - ba2str(device_get_address(session->device), address); - DBG("AVCTP: closing uinput for %s", address); - - ioctl(session->uinput, UI_DEV_DESTROY); - close(session->uinput); - session->uinput = -1; - } - - server = session->server; - server->sessions = g_slist_remove(server->sessions, session); - btd_device_unref(session->device); - g_free(session); -} - -static void avctp_set_state(struct avctp *session, avctp_state_t new_state) -{ - GSList *l; - avctp_state_t old_state = session->state; - - session->state = new_state; - - for (l = callbacks; l != NULL; l = l->next) { - struct avctp_state_callback *cb = l->data; - - if (cb->dev && cb->dev != session->device) - continue; - - cb->cb(session->device, old_state, new_state, cb->user_data); - } - - switch (new_state) { - case AVCTP_STATE_DISCONNECTED: - DBG("AVCTP Disconnected"); - avctp_disconnected(session); - break; - case AVCTP_STATE_CONNECTING: - DBG("AVCTP Connecting"); - break; - case AVCTP_STATE_CONNECTED: - DBG("AVCTP Connected"); - break; - case AVCTP_STATE_BROWSING_CONNECTING: - DBG("AVCTP Browsing Connecting"); - break; - case AVCTP_STATE_BROWSING_CONNECTED: - DBG("AVCTP Browsing Connected"); - break; - default: - error("Invalid AVCTP state %d", new_state); - return; - } -} - static int avctp_send(struct avctp_channel *control, uint8_t transaction, uint8_t cr, uint8_t code, uint8_t subunit, uint8_t opcode, @@ -874,7 +765,8 @@ static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond, handler = g_slist_nth_data(browsing->handlers, 0); if (handler == NULL) { DBG("handler not found"); - packet_size += avrcp_browsing_general_reject(operands); + /* FIXME: Add general reject */ + /* packet_size += avrcp_browsing_general_reject(operands); */ goto send; } @@ -893,7 +785,6 @@ send: failed: DBG("AVCTP Browsing: disconnected"); - avctp_set_state(session, AVCTP_STATE_CONNECTED); if (session->browsing) { avctp_channel_destroy(session->browsing); @@ -966,7 +857,9 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond, handler = find_handler(control->handlers, avc->opcode); if (!handler) { DBG("handler not found for 0x%02x", avc->opcode); - packet_size += avrcp_handle_vendor_reject(&code, operands); + /* FIXME: + * packet_size += avrcp_handle_vendor_reject(&code, operands); + */ avc->code = code; goto done; } @@ -990,11 +883,11 @@ done: failed: DBG("AVCTP session %p got disconnected", session); - avctp_set_state(session, AVCTP_STATE_DISCONNECTED); + avctp_shutdown(session); return FALSE; } -static int uinput_create(char *name) +static int uinput_create(const char *name) { struct uinput_dev dev; int fd, err, i; @@ -1049,11 +942,9 @@ static int uinput_create(char *name) return fd; } -static void init_uinput(struct avctp *session) +int avctp_init_uinput(struct avctp *session, const char *name, + const char *address) { - char address[18], name[248 + 1]; - - device_get_name(session->device, name, sizeof(name)); if (g_str_equal(name, "Nokia CK-20W")) { session->key_quirks[AVC_FORWARD] |= QUIRK_NO_RELEASE; session->key_quirks[AVC_BACKWARD] |= QUIRK_NO_RELEASE; @@ -1061,24 +952,28 @@ static void init_uinput(struct avctp *session) session->key_quirks[AVC_PAUSE] |= QUIRK_NO_RELEASE; } - ba2str(device_get_address(session->device), address); session->uinput = uinput_create(address); - if (session->uinput < 0) - error("AVRCP: failed to init uinput for %s", address); - else - DBG("AVRCP: uinput initialized for %s", address); + if (session->uinput < 0) { + error("AVCTP: failed to init uinput for %s", address); + return session->uinput; + } + + return 0; } -static struct avctp_channel *avctp_channel_create(struct avctp *session, - GIOChannel *io, - GDestroyNotify destroy) +static struct avctp_channel *avctp_channel_create(struct avctp *session, int fd, + size_t imtu, size_t omtu, + avctp_destroy_cb_t destroy) { struct avctp_channel *chan; chan = g_new0(struct avctp_channel, 1); chan->session = session; - chan->io = g_io_channel_ref(io); + chan->io = g_io_channel_unix_new(fd); chan->queue = g_queue_new(); + chan->imtu = imtu; + chan->omtu = omtu; + chan->buffer = g_malloc0(MAX(imtu, omtu)); chan->destroy = destroy; return chan; @@ -1103,381 +998,10 @@ static void avctp_destroy_browsing(void *data) chan->handlers = NULL; } -static void avctp_connect_browsing_cb(GIOChannel *chan, GError *err, - gpointer data) -{ - struct avctp *session = data; - struct avctp_channel *browsing = session->browsing; - char address[18]; - uint16_t imtu, omtu; - GError *gerr = NULL; - - if (err) { - error("Browsing: %s", err->message); - goto fail; - } - - bt_io_get(chan, &gerr, - BT_IO_OPT_DEST, &address, - BT_IO_OPT_IMTU, &imtu, - BT_IO_OPT_OMTU, &omtu, - BT_IO_OPT_INVALID); - if (gerr) { - error("%s", gerr->message); - g_io_channel_shutdown(chan, TRUE, NULL); - g_io_channel_unref(chan); - g_error_free(gerr); - goto fail; - } - - DBG("AVCTP Browsing: connected to %s", address); - - if (browsing == NULL) { - browsing = avctp_channel_create(session, chan, - avctp_destroy_browsing); - session->browsing = browsing; - } - - browsing->imtu = imtu; - browsing->omtu = omtu; - browsing->buffer = g_malloc0(MAX(imtu, omtu)); - browsing->watch = g_io_add_watch(session->browsing->io, - G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc) session_browsing_cb, session); - - avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTED); - - /* Process any request that was pending the connection to complete */ - if (browsing->process_id == 0 && !g_queue_is_empty(browsing->queue)) - browsing->process_id = g_idle_add(process_queue, browsing); - - return; - -fail: - avctp_set_state(session, AVCTP_STATE_CONNECTED); - - if (session->browsing) { - avctp_channel_destroy(session->browsing); - session->browsing = NULL; - } -} - -static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data) -{ - struct avctp *session = data; - char address[18]; - uint16_t imtu, omtu; - GError *gerr = NULL; - - if (err) { - avctp_set_state(session, AVCTP_STATE_DISCONNECTED); - error("%s", err->message); - return; - } - - bt_io_get(chan, &gerr, - BT_IO_OPT_DEST, &address, - BT_IO_OPT_IMTU, &imtu, - BT_IO_OPT_IMTU, &omtu, - BT_IO_OPT_INVALID); - if (gerr) { - avctp_set_state(session, AVCTP_STATE_DISCONNECTED); - error("%s", gerr->message); - g_error_free(gerr); - return; - } - - DBG("AVCTP: connected to %s", address); - - if (session->control == NULL) - session->control = avctp_channel_create(session, chan, NULL); - - session->control->imtu = imtu; - session->control->omtu = omtu; - session->control->buffer = g_malloc0(MAX(imtu, omtu)); - session->control->watch = g_io_add_watch(session->control->io, - G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc) session_cb, session); - - session->passthrough_id = avctp_register_pdu_handler(session, - AVC_OP_PASSTHROUGH, - handle_panel_passthrough, - NULL); - session->unit_id = avctp_register_pdu_handler(session, - AVC_OP_UNITINFO, - handle_unit_info, - NULL); - session->subunit_id = avctp_register_pdu_handler(session, - AVC_OP_SUBUNITINFO, - handle_subunit_info, - NULL); - - init_uinput(session); - - avctp_set_state(session, AVCTP_STATE_CONNECTED); -} - -static void auth_cb(DBusError *derr, void *user_data) -{ - struct avctp *session = user_data; - GError *err = NULL; - - session->auth_id = 0; - - if (session->control->watch > 0) { - g_source_remove(session->control->watch); - session->control->watch = 0; - } - - if (derr && dbus_error_is_set(derr)) { - error("Access denied: %s", derr->message); - avctp_set_state(session, AVCTP_STATE_DISCONNECTED); - return; - } - - if (!bt_io_accept(session->control->io, avctp_connect_cb, session, - NULL, &err)) { - error("bt_io_accept: %s", err->message); - g_error_free(err); - avctp_set_state(session, AVCTP_STATE_DISCONNECTED); - } -} - -static struct avctp_server *find_server(GSList *list, struct btd_adapter *a) -{ - for (; list; list = list->next) { - struct avctp_server *server = list->data; - - if (server->adapter == a) - return server; - } - - return NULL; -} - -static struct avctp *find_session(GSList *list, struct btd_device *device) -{ - for (; list != NULL; list = g_slist_next(list)) { - struct avctp *s = list->data; - - if (s->device == device) - return s; - } - - return NULL; -} - -static struct avctp *avctp_get_internal(struct btd_device *device) -{ - struct avctp_server *server; - struct avctp *session; - - server = find_server(servers, device_get_adapter(device)); - if (server == NULL) - return NULL; - - session = find_session(server->sessions, device); - if (session) - return session; - - session = g_new0(struct avctp, 1); - - session->server = server; - session->device = btd_device_ref(device); - session->state = AVCTP_STATE_DISCONNECTED; - session->uinput = -1; - - server->sessions = g_slist_append(server->sessions, session); - - return session; -} - -static void avctp_control_confirm(struct avctp *session, GIOChannel *chan, - struct btd_device *dev) -{ - const bdaddr_t *src; - const bdaddr_t *dst; - - if (session->control != NULL) { - error("Control: Refusing unexpected connect"); - g_io_channel_shutdown(chan, TRUE, NULL); - return; - } - - avctp_set_state(session, AVCTP_STATE_CONNECTING); - session->control = avctp_channel_create(session, chan, NULL); - - src = btd_adapter_get_address(device_get_adapter(dev)); - dst = device_get_address(dev); - - session->auth_id = btd_request_authorization(src, dst, - AVRCP_REMOTE_UUID, - auth_cb, session); - if (session->auth_id == 0) - goto drop; - - session->control->watch = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | - G_IO_NVAL, session_cb, session); - return; - -drop: - avctp_set_state(session, AVCTP_STATE_DISCONNECTED); -} - -static void avctp_browsing_confirm(struct avctp *session, GIOChannel *chan, - struct btd_device *dev) -{ - GError *err = NULL; - - if (session->control == NULL || session->browsing != NULL) { - error("Browsing: Refusing unexpected connect"); - g_io_channel_shutdown(chan, TRUE, NULL); - return; - } - - if (bt_io_accept(chan, avctp_connect_browsing_cb, session, NULL, - &err)) { - avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING); - return; - } - - error("Browsing: %s", err->message); - g_error_free(err); - - return; -} - -static void avctp_confirm_cb(GIOChannel *chan, gpointer data) -{ - struct avctp *session; - char address[18]; - bdaddr_t src, dst; - GError *err = NULL; - uint16_t psm; - struct btd_device *device; - - bt_io_get(chan, &err, - BT_IO_OPT_SOURCE_BDADDR, &src, - BT_IO_OPT_DEST_BDADDR, &dst, - BT_IO_OPT_DEST, address, - BT_IO_OPT_PSM, &psm, - BT_IO_OPT_INVALID); - if (err) { - error("%s", err->message); - g_error_free(err); - g_io_channel_shutdown(chan, TRUE, NULL); - return; - } - - DBG("AVCTP: incoming connect from %s", address); - - device = btd_adapter_find_device(adapter_find(&src), &dst); - if (!device) - return; - - session = avctp_get_internal(device); - if (session == NULL) - return; - - if (btd_device_get_service(device, AVRCP_REMOTE_UUID) == NULL) - btd_device_add_uuid(device, AVRCP_REMOTE_UUID); - - if (btd_device_get_service(device, AVRCP_TARGET_UUID) == NULL) - btd_device_add_uuid(device, AVRCP_TARGET_UUID); - - switch (psm) { - case AVCTP_CONTROL_PSM: - avctp_control_confirm(session, chan, device); - break; - case AVCTP_BROWSING_PSM: - avctp_browsing_confirm(session, chan, device); - break; - } - - return; -} - -static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master, - uint8_t mode, uint16_t psm) -{ - GError *err = NULL; - GIOChannel *io; - - io = bt_io_listen(NULL, avctp_confirm_cb, NULL, - NULL, &err, - BT_IO_OPT_SOURCE_BDADDR, src, - BT_IO_OPT_PSM, psm, - BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, - BT_IO_OPT_MASTER, master, - BT_IO_OPT_MODE, mode, - BT_IO_OPT_INVALID); - if (!io) { - error("%s", err->message); - g_error_free(err); - } - - return io; -} - -int avctp_register(struct btd_adapter *adapter, gboolean master) -{ - struct avctp_server *server; - const bdaddr_t *src = btd_adapter_get_address(adapter); - - server = g_new0(struct avctp_server, 1); - - server->control_io = avctp_server_socket(src, master, L2CAP_MODE_BASIC, - AVCTP_CONTROL_PSM); - if (!server->control_io) { - g_free(server); - return -1; - } - server->browsing_io = avctp_server_socket(src, master, L2CAP_MODE_ERTM, - AVCTP_BROWSING_PSM); - if (!server->browsing_io) { - if (server->control_io) { - g_io_channel_shutdown(server->control_io, TRUE, NULL); - g_io_channel_unref(server->control_io); - server->control_io = NULL; - } - g_free(server); - return -1; - } - - server->adapter = btd_adapter_ref(adapter); - - servers = g_slist_append(servers, server); - - return 0; -} - -void avctp_unregister(struct btd_adapter *adapter) -{ - struct avctp_server *server; - - server = find_server(servers, adapter); - if (!server) - return; - - while (server->sessions) - avctp_disconnected(server->sessions->data); - - servers = g_slist_remove(servers, server); - - g_io_channel_shutdown(server->browsing_io, TRUE, NULL); - g_io_channel_unref(server->browsing_io); - server->browsing_io = NULL; - - g_io_channel_shutdown(server->control_io, TRUE, NULL); - g_io_channel_unref(server->control_io); - btd_adapter_unref(server->adapter); - g_free(server); -} - static struct avctp_pending_req *pending_create(struct avctp_channel *chan, avctp_process_cb process, void *data, - GDestroyNotify destroy) + avctp_destroy_cb_t destroy) { struct avctp_pending_req *p; GSList *l, *tmp; @@ -1732,39 +1256,6 @@ int avctp_send_vendordep_req(struct avctp *session, uint8_t code, func, user_data); } -unsigned int avctp_add_state_cb(struct btd_device *dev, avctp_state_cb cb, - void *user_data) -{ - struct avctp_state_callback *state_cb; - static unsigned int id = 0; - - state_cb = g_new(struct avctp_state_callback, 1); - state_cb->cb = cb; - state_cb->dev = dev; - state_cb->id = ++id; - state_cb->user_data = user_data; - - callbacks = g_slist_append(callbacks, state_cb); - - return state_cb->id; -} - -gboolean avctp_remove_state_cb(unsigned int id) -{ - GSList *l; - - for (l = callbacks; l != NULL; l = l->next) { - struct avctp_state_callback *cb = l->data; - if (cb && cb->id == id) { - callbacks = g_slist_remove(callbacks, cb); - g_free(cb); - return TRUE; - } - } - - return FALSE; -} - unsigned int avctp_register_passthrough_handler(struct avctp *session, avctp_passthrough_cb cb, void *user_data) @@ -1786,29 +1277,18 @@ unsigned int avctp_register_passthrough_handler(struct avctp *session, return handler->id; } -bool avctp_unregister_passthrough_handler(unsigned int id) +bool avctp_unregister_passthrough_handler(struct avctp *session, + unsigned int id) { - GSList *l; - - for (l = servers; l; l = l->next) { - struct avctp_server *server = l->data; - GSList *s; + if (session->handler == NULL) + return false; - for (s = server->sessions; s; s = s->next) { - struct avctp *session = s->data; - - if (session->handler == NULL) - continue; - - if (session->handler->id == id) { - g_free(session->handler); - session->handler = NULL; - return true; - } - } - } + if (session->handler->id != id) + return false; - return false; + g_free(session->handler); + session->handler = NULL; + return true; } unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode, @@ -1840,7 +1320,7 @@ unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode, unsigned int avctp_register_browsing_pdu_handler(struct avctp *session, avctp_browsing_pdu_cb cb, void *user_data, - GDestroyNotify destroy) + avctp_destroy_cb_t destroy) { struct avctp_channel *browsing = session->browsing; struct avctp_browsing_pdu_handler *handler; @@ -1863,165 +1343,129 @@ unsigned int avctp_register_browsing_pdu_handler(struct avctp *session, return handler->id; } -gboolean avctp_unregister_pdu_handler(unsigned int id) +bool avctp_unregister_pdu_handler(struct avctp *session, unsigned int id) { + struct avctp_channel *control = session->control; GSList *l; - for (l = servers; l; l = l->next) { - struct avctp_server *server = l->data; - GSList *s; - - for (s = server->sessions; s; s = s->next) { - struct avctp *session = s->data; - struct avctp_channel *control = session->control; - GSList *h; + if (!control) + return false; - if (control == NULL) - continue; + for (l = control->handlers; l; l = g_slist_next(l)) { + struct avctp_pdu_handler *handler = l->data; - for (h = control->handlers; h; h = h->next) { - struct avctp_pdu_handler *handler = h->data; - - if (handler->id != id) - continue; + if (handler->id != id) + continue; - control->handlers = g_slist_remove( - control->handlers, - handler); - g_free(handler); - return TRUE; - } - } + control->handlers = g_slist_remove(control->handlers, handler); + g_free(handler); + return true; } - return FALSE; + return false; } -gboolean avctp_unregister_browsing_pdu_handler(unsigned int id) +bool avctp_unregister_browsing_pdu_handler(struct avctp *session, + unsigned int id) { + struct avctp_channel *browsing = session->browsing; GSList *l; - for (l = servers; l; l = l->next) { - struct avctp_server *server = l->data; - GSList *s; - - for (s = server->sessions; s; s = s->next) { - struct avctp *session = s->data; - struct avctp_channel *browsing = session->browsing; - GSList *h; - - if (browsing == NULL) - continue; + if (browsing == NULL) + return false; - for (h = browsing->handlers; h; h = h->next) { - struct avctp_browsing_pdu_handler *handler = - h->data; + for (l = browsing->handlers; l; l = g_slist_next(l)) { + struct avctp_browsing_pdu_handler *handler = l->data; - if (handler->id != id) - continue; + if (handler->id != id) + continue; - browsing->handlers = g_slist_remove( - browsing->handlers, - handler); - g_free(handler); - return TRUE; - } - } + browsing->handlers = g_slist_remove(browsing->handlers, + handler); + g_free(handler); + return true; } - return FALSE; + return false; } -struct avctp *avctp_connect(struct btd_device *device) +struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version) { struct avctp *session; - GError *err = NULL; - GIOChannel *io; - const bdaddr_t *src; - - session = avctp_get_internal(device); - if (!session) - return NULL; - - if (session->state > AVCTP_STATE_DISCONNECTED) - return session; - - avctp_set_state(session, AVCTP_STATE_CONNECTING); + struct avctp_channel *control; + GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL; - src = btd_adapter_get_address(session->server->adapter); + session = g_new0(struct avctp, 1); + session->version = version; - io = bt_io_connect(avctp_connect_cb, session, NULL, &err, - BT_IO_OPT_SOURCE_BDADDR, src, - BT_IO_OPT_DEST_BDADDR, - device_get_address(session->device), - BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, - BT_IO_OPT_PSM, AVCTP_CONTROL_PSM, - BT_IO_OPT_INVALID); - if (err) { - avctp_set_state(session, AVCTP_STATE_DISCONNECTED); - error("%s", err->message); - g_error_free(err); + control = avctp_channel_create(session, fd, imtu, omtu, NULL); + if (!control) { + g_free(session); return NULL; } - session->control = avctp_channel_create(session, io, NULL); - session->initiator = true; - g_io_channel_unref(io); + session->control = control; + session->passthrough_id = avctp_register_pdu_handler(session, + AVC_OP_PASSTHROUGH, + handle_panel_passthrough, + NULL); + session->unit_id = avctp_register_pdu_handler(session, + AVC_OP_UNITINFO, + handle_unit_info, + NULL); + session->subunit_id = avctp_register_pdu_handler(session, + AVC_OP_SUBUNITINFO, + handle_subunit_info, + NULL); + + control->watch = g_io_add_watch(session->control->io, cond, + (GIOFunc) session_cb, session); return session; } -int avctp_connect_browsing(struct avctp *session) +int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu, + size_t omtu) { - const bdaddr_t *src; - GError *err = NULL; - GIOChannel *io; - - if (session->state != AVCTP_STATE_CONNECTED) - return -ENOTCONN; - - if (session->browsing != NULL) - return 0; + struct avctp_channel *browsing; + GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL; - avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING); - - src = btd_adapter_get_address(session->server->adapter); - - io = bt_io_connect(avctp_connect_browsing_cb, session, NULL, &err, - BT_IO_OPT_SOURCE_BDADDR, src, - BT_IO_OPT_DEST_BDADDR, - device_get_address(session->device), - BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, - BT_IO_OPT_PSM, AVCTP_BROWSING_PSM, - BT_IO_OPT_MODE, L2CAP_MODE_ERTM, - BT_IO_OPT_INVALID); - if (err) { - error("%s", err->message); - g_error_free(err); - return -EIO; - } + if (session->browsing) + return -EISCONN; - session->browsing = avctp_channel_create(session, io, + browsing = avctp_channel_create(session, fd, imtu, omtu, avctp_destroy_browsing); - g_io_channel_unref(io); + if (!browsing) + return -EINVAL; + + session->browsing = browsing; + browsing->watch = g_io_add_watch(session->browsing->io, cond, + (GIOFunc) session_browsing_cb, session); return 0; } -void avctp_disconnect(struct avctp *session) +void avctp_shutdown(struct avctp *session) { - if (session->state == AVCTP_STATE_DISCONNECTED) + if (!session) return; - avctp_set_state(session, AVCTP_STATE_DISCONNECTED); -} + if (session->browsing) + avctp_channel_destroy(session->browsing); -struct avctp *avctp_get(struct btd_device *device) -{ - return avctp_get_internal(device); -} + if (session->control) + avctp_channel_destroy(session->control); -bool avctp_is_initiator(struct avctp *session) -{ - return session->initiator; + if (session->key.timer > 0) + g_source_remove(session->key.timer); + + if (session->uinput >= 0) { + DBG("AVCTP: closing uinput"); + + ioctl(session->uinput, UI_DEV_DESTROY); + close(session->uinput); + session->uinput = -1; + } + + g_free(session); } diff --git a/android/avctp.h b/android/avctp.h index f9c665e..99aaf95 100644 --- a/android/avctp.h +++ b/android/avctp.h @@ -82,19 +82,6 @@ struct avctp; -typedef enum { - AVCTP_STATE_DISCONNECTED = 0, - AVCTP_STATE_CONNECTING, - AVCTP_STATE_CONNECTED, - AVCTP_STATE_BROWSING_CONNECTING, - AVCTP_STATE_BROWSING_CONNECTED -} avctp_state_t; - -typedef void (*avctp_state_cb) (struct btd_device *dev, - avctp_state_t old_state, - avctp_state_t new_state, - void *user_data); - typedef bool (*avctp_passthrough_cb) (struct avctp *session, uint8_t op, bool pressed, void *user_data); @@ -113,34 +100,33 @@ typedef size_t (*avctp_browsing_pdu_cb) (struct avctp *session, uint8_t *operands, size_t operand_count, void *user_data); -unsigned int avctp_add_state_cb(struct btd_device *dev, avctp_state_cb cb, - void *user_data); -gboolean avctp_remove_state_cb(unsigned int id); +typedef void (*avctp_destroy_cb_t) (void *user_data); -int avctp_register(struct btd_adapter *adapter, gboolean master); -void avctp_unregister(struct btd_adapter *adapter); +struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version); +int avctp_init_uinput(struct avctp *session, const char *name, + const char *address); +int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu, + size_t omtu); -struct avctp *avctp_connect(struct btd_device *device); -struct avctp *avctp_get(struct btd_device *device); -bool avctp_is_initiator(struct avctp *session); -int avctp_connect_browsing(struct avctp *session); -void avctp_disconnect(struct avctp *session); +void avctp_shutdown(struct avctp *session); unsigned int avctp_register_passthrough_handler(struct avctp *session, avctp_passthrough_cb cb, void *user_data); -bool avctp_unregister_passthrough_handler(unsigned int id); +bool avctp_unregister_passthrough_handler(struct avctp *session, + unsigned int id); unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode, avctp_control_pdu_cb cb, void *user_data); -gboolean avctp_unregister_pdu_handler(unsigned int id); +bool avctp_unregister_pdu_handler(struct avctp *session, unsigned int id); unsigned int avctp_register_browsing_pdu_handler(struct avctp *session, avctp_browsing_pdu_cb cb, void *user_data, - GDestroyNotify destroy); -gboolean avctp_unregister_browsing_pdu_handler(unsigned int id); + avctp_destroy_cb_t destroy); +bool avctp_unregister_browsing_pdu_handler(struct avctp *session, + unsigned int id); int avctp_send_passthrough(struct avctp *session, uint8_t op); int avctp_send_vendordep(struct avctp *session, uint8_t transaction, -- 1.8.4.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v2 3/8] android: Add initial skeleton for AVRCP in the daemon 2014-01-24 13:24 [PATCH BlueZ v2 1/8] android: Add copy of current AVCTP implemention Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 2/8] android/AVCTP: Strip dependencies Luiz Augusto von Dentz @ 2014-01-24 13:24 ` Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 4/8] android: Add initial skeleton for AVRCP in the HAL Luiz Augusto von Dentz ` (4 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: Luiz Augusto von Dentz @ 2014-01-24 13:24 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> --- android/Android.mk | 1 + android/Makefile.am | 1 + plugins/external-dummy.c => android/avrcp.c | 32 ++++++++++++++++++++++------- android/{hidhost.h => avrcp.h} | 6 +++--- android/main.c | 11 ++++++++++ 5 files changed, 41 insertions(+), 10 deletions(-) copy plugins/external-dummy.c => android/avrcp.c (62%) copy android/{hidhost.h => avrcp.h} (84%) diff --git a/android/Android.mk b/android/Android.mk index fd76f1d..bc4f7e4 100644 --- a/android/Android.mk +++ b/android/Android.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \ bluez/android/avdtp.c \ bluez/android/a2dp.c \ bluez/android/avctp.c \ + bluez/android/avrcp.c \ bluez/android/pan.c \ bluez/src/log.c \ bluez/src/shared/mgmt.c \ diff --git a/android/Makefile.am b/android/Makefile.am index 88fe667..d4a76bb 100644 --- a/android/Makefile.am +++ b/android/Makefile.am @@ -34,6 +34,7 @@ android_bluetoothd_SOURCES = android/main.c \ android/avdtp.h android/avdtp.c \ android/a2dp.h android/a2dp.c \ android/avctp.h android/avctp.c \ + android/avrcp.h android/avrcp.c \ android/socket.h android/socket.c \ android/pan.h android/pan.c \ btio/btio.h btio/btio.c \ diff --git a/plugins/external-dummy.c b/android/avrcp.c similarity index 62% copy from plugins/external-dummy.c copy to android/avrcp.c index ff31290..707506b 100644 --- a/plugins/external-dummy.c +++ b/android/avrcp.c @@ -2,6 +2,9 @@ * * BlueZ - Bluetooth protocol stack for Linux * + * Copyright (C) 2014 Intel Corporation. All rights reserved. + * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,20 +25,35 @@ #include <config.h> #endif -#include "plugin.h" +#include <stdbool.h> +#include <glib.h> + +#include "lib/bluetooth.h" #include "log.h" +#include "avrcp.h" +#include "hal-msg.h" +#include "ipc.h" + +static bdaddr_t adapter_addr; + +static const struct ipc_handler cmd_handlers[] = { +}; -static int dummy_init(void) +bool bt_avrcp_register(const bdaddr_t *addr) { DBG(""); - return 0; + bacpy(&adapter_addr, addr); + + ipc_register(HAL_SERVICE_ID_AVRCP, cmd_handlers, + G_N_ELEMENTS(cmd_handlers)); + + return true; } -static void dummy_exit(void) +void bt_avrcp_unregister(void) { DBG(""); -} -BLUETOOTH_PLUGIN_DEFINE(external_dummy, VERSION, - BLUETOOTH_PLUGIN_PRIORITY_LOW, dummy_init, dummy_exit) + ipc_unregister(HAL_SERVICE_ID_AVRCP); +} diff --git a/android/hidhost.h b/android/avrcp.h similarity index 84% copy from android/hidhost.h copy to android/avrcp.h index ea14446..6fe7fbf 100644 --- a/android/hidhost.h +++ b/android/avrcp.h @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2013 Intel Corporation. All rights reserved. + * Copyright (C) 2014 Intel Corporation. All rights reserved. * * * This program is free software; you can redistribute it and/or modify @@ -21,5 +21,5 @@ * */ -bool bt_hid_register(const bdaddr_t *addr); -void bt_hid_unregister(void); +bool bt_avrcp_register(const bdaddr_t *addr); +void bt_avrcp_unregister(void); diff --git a/android/main.c b/android/main.c index 8983a84..c353c4a 100644 --- a/android/main.c +++ b/android/main.c @@ -55,6 +55,7 @@ #include "ipc.h" #include "a2dp.h" #include "pan.h" +#include "avrcp.h" #define STARTUP_GRACE_SECONDS 5 #define SHUTDOWN_GRACE_SECONDS 10 @@ -107,6 +108,13 @@ static void service_register(const void *buf, uint16_t len) } break; + case HAL_SERVICE_ID_AVRCP: + if (!bt_avrcp_register(&adapter_bdaddr)) { + status = HAL_STATUS_FAILED; + goto failed; + } + + break; default: DBG("service %u not supported", m->service_id); status = HAL_STATUS_FAILED; @@ -149,6 +157,9 @@ static void service_unregister(const void *buf, uint16_t len) case HAL_SERVICE_ID_PAN: bt_pan_unregister(); break; + case HAL_SERVICE_ID_AVRCP: + bt_avrcp_unregister(); + break; default: /* This would indicate bug in HAL, as unregister should not be * called in init failed */ -- 1.8.4.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v2 4/8] android: Add initial skeleton for AVRCP in the HAL 2014-01-24 13:24 [PATCH BlueZ v2 1/8] android: Add copy of current AVCTP implemention Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 2/8] android/AVCTP: Strip dependencies Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 3/8] android: Add initial skeleton for AVRCP in the daemon Luiz Augusto von Dentz @ 2014-01-24 13:24 ` Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 5/8] android/haltest: Add init and cleanup calls to rc methods Luiz Augusto von Dentz ` (3 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: Luiz Augusto von Dentz @ 2014-01-24 13:24 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> --- android/Android.mk | 1 + android/Makefile.am | 1 + android/hal-avrcp.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ android/hal-bluetooth.c | 3 ++ android/hal.h | 2 ++ 5 files changed, 94 insertions(+) create mode 100644 android/hal-avrcp.c diff --git a/android/Android.mk b/android/Android.mk index bc4f7e4..160a1d4 100644 --- a/android/Android.mk +++ b/android/Android.mk @@ -97,6 +97,7 @@ LOCAL_SRC_FILES := \ bluez/android/hal-hidhost.c \ bluez/android/hal-pan.c \ bluez/android/hal-a2dp.c \ + bluez/android/hal-avrcp.c \ bluez/android/hal-utils.c \ LOCAL_C_INCLUDES += \ diff --git a/android/Makefile.am b/android/Makefile.am index d4a76bb..664524f 100644 --- a/android/Makefile.am +++ b/android/Makefile.am @@ -50,6 +50,7 @@ android_bluetooth_default_la_SOURCES = android/hal.h android/hal-bluetooth.c \ android/hal-hidhost.c \ android/hal-pan.c \ android/hal-a2dp.c \ + android/hal-avrcp.c \ android/hardware/bluetooth.h \ android/hardware/bt_av.h \ android/hardware/bt_gatt.h \ diff --git a/android/hal-avrcp.c b/android/hal-avrcp.c new file mode 100644 index 0000000..01d233b --- /dev/null +++ b/android/hal-avrcp.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <stdbool.h> +#include <stddef.h> +#include <string.h> + +#include "hal-log.h" +#include "hal.h" +#include "hal-msg.h" +#include "hal-ipc.h" + +static const btrc_callbacks_t *cbs = NULL; + +static bool interface_ready(void) +{ + return cbs != NULL; +} + +static bt_status_t init(btrc_callbacks_t *callbacks) +{ + struct hal_cmd_register_module cmd; + int ret; + + DBG(""); + + if (interface_ready()) + return BT_STATUS_DONE; + + cbs = callbacks; + + cmd.service_id = HAL_SERVICE_ID_AVRCP; + + ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE, + sizeof(cmd), &cmd, 0, NULL, NULL); + + if (ret != BT_STATUS_SUCCESS) { + cbs = NULL; + hal_ipc_unregister(HAL_SERVICE_ID_AVRCP); + } + + return ret; +} + +static void cleanup() +{ + struct hal_cmd_unregister_module cmd; + + DBG(""); + + if (!interface_ready()) + return; + + cbs = NULL; + + cmd.service_id = HAL_SERVICE_ID_AVRCP; + + hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE, + sizeof(cmd), &cmd, 0, NULL, NULL); + + hal_ipc_unregister(HAL_SERVICE_ID_AVRCP); +} + +static btrc_interface_t iface = { + .size = sizeof(iface), + .init = init, + .cleanup = cleanup +}; + +btrc_interface_t *bt_get_avrcp_interface() +{ + return &iface; +} diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c index 4f0e7b7..0dac158 100644 --- a/android/hal-bluetooth.c +++ b/android/hal-bluetooth.c @@ -762,6 +762,9 @@ static const void *get_profile_interface(const char *profile_id) if (!strcmp(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID)) return bt_get_a2dp_interface(); + if (!strcmp(profile_id, BT_PROFILE_AV_RC_ID)) + return bt_get_avrcp_interface(); + return NULL; } diff --git a/android/hal.h b/android/hal.h index b475411..1ff4fbd 100644 --- a/android/hal.h +++ b/android/hal.h @@ -20,11 +20,13 @@ #include <hardware/bt_hh.h> #include <hardware/bt_pan.h> #include <hardware/bt_av.h> +#include <hardware/bt_rc.h> btsock_interface_t *bt_get_sock_interface(void); bthh_interface_t *bt_get_hidhost_interface(void); btpan_interface_t *bt_get_pan_interface(void); btav_interface_t *bt_get_a2dp_interface(void); +btrc_interface_t *bt_get_avrcp_interface(void); void bt_thread_associate(void); void bt_thread_disassociate(void); -- 1.8.4.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v2 5/8] android/haltest: Add init and cleanup calls to rc methods 2014-01-24 13:24 [PATCH BlueZ v2 1/8] android: Add copy of current AVCTP implemention Luiz Augusto von Dentz ` (2 preceding siblings ...) 2014-01-24 13:24 ` [PATCH BlueZ v2 4/8] android: Add initial skeleton for AVRCP in the HAL Luiz Augusto von Dentz @ 2014-01-24 13:24 ` Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 6/8] android/AVRCP: Add implementation of SDP record Luiz Augusto von Dentz ` (2 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: Luiz Augusto von Dentz @ 2014-01-24 13:24 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> --- android/Android.mk | 1 + android/Makefile.am | 1 + android/client/haltest.c | 2 ++ android/client/if-bt.c | 2 +- android/client/if-main.h | 2 ++ android/client/{if-audio.c => if-rc.c} | 44 +++++++++++++--------------------- 6 files changed, 23 insertions(+), 29 deletions(-) copy android/client/{if-audio.c => if-rc.c} (57%) diff --git a/android/Android.mk b/android/Android.mk index 160a1d4..b83d1fe 100644 --- a/android/Android.mk +++ b/android/Android.mk @@ -131,6 +131,7 @@ LOCAL_SRC_FILES := \ bluez/android/client/tabcompletion.c \ bluez/android/client/if-audio.c \ bluez/android/client/if-av.c \ + bluez/android/client/if-rc.c \ bluez/android/client/if-bt.c \ bluez/android/client/if-hf.c \ bluez/android/client/if-hh.c \ diff --git a/android/Makefile.am b/android/Makefile.am index 664524f..e065c0c 100644 --- a/android/Makefile.am +++ b/android/Makefile.am @@ -85,6 +85,7 @@ android_haltest_SOURCES = android/client/haltest.c \ android/client/tabcompletion.c \ android/client/if-main.h \ android/client/if-av.c \ + android/client/if-rc.c \ android/client/if-bt.c \ android/client/if-gatt.c \ android/client/if-hf.c \ diff --git a/android/client/haltest.c b/android/client/haltest.c index f4d1ade..114fe31 100644 --- a/android/client/haltest.c +++ b/android/client/haltest.c @@ -34,6 +34,7 @@ const struct interface *interfaces[] = { &audio_if, &bluetooth_if, &av_if, + &rc_if, &gatt_if, &gatt_client_if, &gatt_server_if, @@ -382,6 +383,7 @@ static void init(void) static const char * const inames[] = { BT_PROFILE_HANDSFREE_ID, BT_PROFILE_ADVANCED_AUDIO_ID, + BT_PROFILE_AV_RC_ID, BT_PROFILE_HEALTH_ID, BT_PROFILE_HIDHOST_ID, BT_PROFILE_PAN_ID, diff --git a/android/client/if-bt.c b/android/client/if-bt.c index 6bfb439..8dcffea 100644 --- a/android/client/if-bt.c +++ b/android/client/if-bt.c @@ -760,7 +760,7 @@ static void get_profile_interface_p(int argc, const char **argv) else if (strcmp(BT_PROFILE_PAN_ID, id) == 0) pif = (const void **) &if_pan; else if (strcmp(BT_PROFILE_AV_RC_ID, id) == 0) - pif = &dummy; /* TODO: change when if_rc is there */ + pif = (const void **) &if_rc; else if (strcmp(BT_PROFILE_GATT_ID, id) == 0) pif = (const void **) &if_gatt; else diff --git a/android/client/if-main.h b/android/client/if-main.h index 2b22fc4..d82358e 100644 --- a/android/client/if-main.h +++ b/android/client/if-main.h @@ -48,6 +48,7 @@ extern audio_hw_device_t *if_audio; /* Interfaces from hal that can be populated during application lifetime */ extern const bt_interface_t *if_bluetooth; extern const btav_interface_t *if_av; +extern const btrc_interface_t *if_rc; extern const bthf_interface_t *if_hf; extern const bthh_interface_t *if_hh; extern const btpan_interface_t *if_pan; @@ -68,6 +69,7 @@ struct interface { extern const struct interface audio_if; extern const struct interface bluetooth_if; extern const struct interface av_if; +extern const struct interface rc_if; extern const struct interface gatt_if; extern const struct interface gatt_client_if; extern const struct interface gatt_server_if; diff --git a/android/client/if-audio.c b/android/client/if-rc.c similarity index 57% copy from android/client/if-audio.c copy to android/client/if-rc.c index 203e088..58fb892 100644 --- a/android/client/if-audio.c +++ b/android/client/if-rc.c @@ -18,41 +18,29 @@ #include "if-main.h" #include "../hal-utils.h" -audio_hw_device_t *if_audio = NULL; +const btrc_interface_t *if_rc = NULL; -static void init_p(int argc, const char **argv) -{ - int err; - const hw_module_t *module; - audio_hw_device_t *device; +static btrc_callbacks_t rc_cbacks = { + .size = sizeof(rc_cbacks), +}; - err = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, - AUDIO_HARDWARE_MODULE_ID_A2DP, &module); - if (err) { - haltest_error("hw_get_module_by_class returned %d\n", err); - return; - } +/* init */ - err = audio_hw_device_open(module, &device); - if (err) - haltest_error("audio_hw_device_open returned %d\n", err); +static void init_p(int argc, const char **argv) +{ + RETURN_IF_NULL(if_rc); - if_audio = device; + EXEC(if_rc->init, &rc_cbacks); } +/* cleanup */ + static void cleanup_p(int argc, const char **argv) { - int err; - - RETURN_IF_NULL(if_audio); - - err = audio_hw_device_close(if_audio); - if (err < 0) { - haltest_error("audio_hw_device_close returned %d\n", err); - return; - } + RETURN_IF_NULL(if_rc); - if_audio = NULL; + EXECV(if_rc->cleanup); + if_rc = NULL; } static struct method methods[] = { @@ -61,7 +49,7 @@ static struct method methods[] = { END_METHOD }; -const struct interface audio_if = { - .name = "audio", +const struct interface rc_if = { + .name = "rc", .methods = methods }; -- 1.8.4.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v2 6/8] android/AVRCP: Add implementation of SDP record 2014-01-24 13:24 [PATCH BlueZ v2 1/8] android: Add copy of current AVCTP implemention Luiz Augusto von Dentz ` (3 preceding siblings ...) 2014-01-24 13:24 ` [PATCH BlueZ v2 5/8] android/haltest: Add init and cleanup calls to rc methods Luiz Augusto von Dentz @ 2014-01-24 13:24 ` Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 7/8] android/AVCTP: Add avctp_set_destroy_cb Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 8/8] android/AVRCP: Add initial socket handling Luiz Augusto von Dentz 6 siblings, 0 replies; 8+ messages in thread From: Luiz Augusto von Dentz @ 2014-01-24 13:24 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> This adds the following record: Service Name: AVRCP TG Service RecHandle: 0x10002 Service Class ID List: "AV Remote Target" (0x110c) Protocol Descriptor List: "L2CAP" (0x0100) PSM: 23 "AVCTP" (0x0017) uint16: 0x103 Profile Descriptor List: "AV Remote" (0x110e) Version: 0x0100 --- android/avrcp.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/android/avrcp.c b/android/avrcp.c index 707506b..e06d136 100644 --- a/android/avrcp.c +++ b/android/avrcp.c @@ -29,22 +29,116 @@ #include <glib.h> #include "lib/bluetooth.h" +#include "lib/sdp.h" +#include "lib/sdp_lib.h" #include "log.h" +#include "bluetooth.h" #include "avrcp.h" #include "hal-msg.h" #include "ipc.h" +#define L2CAP_PSM_AVCTP 0x17 + +#define AVRCP_FEATURE_CATEGORY_1 0x0001 +#define AVRCP_FEATURE_CATEGORY_2 0x0002 +#define AVRCP_FEATURE_CATEGORY_3 0x0004 +#define AVRCP_FEATURE_CATEGORY_4 0x0008 + static bdaddr_t adapter_addr; +static uint32_t record_id = 0; static const struct ipc_handler cmd_handlers[] = { }; +static sdp_record_t *avrcp_record(void) +{ + sdp_list_t *svclass_id, *pfseq, *apseq, *root; + uuid_t root_uuid, l2cap, avctp, avrtg; + sdp_profile_desc_t profile[1]; + sdp_list_t *aproto_control, *proto_control[2]; + sdp_record_t *record; + sdp_data_t *psm, *version, *features; + uint16_t lp = L2CAP_PSM_AVCTP; + uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103; + uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 | + AVRCP_FEATURE_CATEGORY_2 | + AVRCP_FEATURE_CATEGORY_3 | + AVRCP_FEATURE_CATEGORY_4); + + record = sdp_record_alloc(); + if (!record) + return NULL; + + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); + root = sdp_list_append(NULL, &root_uuid); + sdp_set_browse_groups(record, root); + + /* Service Class ID List */ + sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID); + svclass_id = sdp_list_append(NULL, &avrtg); + sdp_set_service_classes(record, svclass_id); + + /* Protocol Descriptor List */ + sdp_uuid16_create(&l2cap, L2CAP_UUID); + proto_control[0] = sdp_list_append(NULL, &l2cap); + psm = sdp_data_alloc(SDP_UINT16, &lp); + proto_control[0] = sdp_list_append(proto_control[0], psm); + apseq = sdp_list_append(NULL, proto_control[0]); + + sdp_uuid16_create(&avctp, AVCTP_UUID); + proto_control[1] = sdp_list_append(NULL, &avctp); + version = sdp_data_alloc(SDP_UINT16, &avctp_ver); + proto_control[1] = sdp_list_append(proto_control[1], version); + apseq = sdp_list_append(apseq, proto_control[1]); + + aproto_control = sdp_list_append(NULL, apseq); + sdp_set_access_protos(record, aproto_control); + + /* Bluetooth Profile Descriptor List */ + sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID); + profile[0].version = avrcp_ver; + pfseq = sdp_list_append(NULL, &profile[0]); + sdp_set_profile_descs(record, pfseq); + + features = sdp_data_alloc(SDP_UINT16, &feat); + sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features); + + sdp_set_info_attr(record, "AVRCP TG", 0, 0); + + sdp_data_free(psm); + sdp_data_free(version); + sdp_list_free(proto_control[0], NULL); + sdp_list_free(proto_control[1], NULL); + sdp_list_free(apseq, NULL); + sdp_list_free(aproto_control, NULL); + sdp_list_free(pfseq, NULL); + sdp_list_free(root, NULL); + sdp_list_free(svclass_id, NULL); + + return record; +} + bool bt_avrcp_register(const bdaddr_t *addr) { + sdp_record_t *rec; + DBG(""); bacpy(&adapter_addr, addr); + rec = avrcp_record(); + if (!rec) { + error("Failed to allocate AVRCP record"); + return false; + } + + if (bt_adapter_add_record(rec, 0) < 0) { + error("Failed to register AVRCP record"); + sdp_record_free(rec); + return false; + } + record_id = rec->handle; + ipc_register(HAL_SERVICE_ID_AVRCP, cmd_handlers, G_N_ELEMENTS(cmd_handlers)); @@ -56,4 +150,7 @@ void bt_avrcp_unregister(void) DBG(""); ipc_unregister(HAL_SERVICE_ID_AVRCP); + + bt_adapter_remove_record(record_id); + record_id = 0; } -- 1.8.4.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v2 7/8] android/AVCTP: Add avctp_set_destroy_cb 2014-01-24 13:24 [PATCH BlueZ v2 1/8] android: Add copy of current AVCTP implemention Luiz Augusto von Dentz ` (4 preceding siblings ...) 2014-01-24 13:24 ` [PATCH BlueZ v2 6/8] android/AVRCP: Add implementation of SDP record Luiz Augusto von Dentz @ 2014-01-24 13:24 ` Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 8/8] android/AVRCP: Add initial socket handling Luiz Augusto von Dentz 6 siblings, 0 replies; 8+ messages in thread From: Luiz Augusto von Dentz @ 2014-01-24 13:24 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> This adds avctp_set_destroy_cb that can be use to set a callback when the AVCTP has been disconnected. --- android/avctp.c | 13 +++++++++++++ android/avctp.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/android/avctp.c b/android/avctp.c index 1255c3e..a88b7f7 100644 --- a/android/avctp.c +++ b/android/avctp.c @@ -174,6 +174,9 @@ struct avctp { uint8_t key_quirks[256]; struct key_pressed key; uint16_t version; + + avctp_destroy_cb_t destroy; + void *data; }; struct avctp_passthrough_handler { @@ -1445,6 +1448,13 @@ int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu, return 0; } +void avctp_set_destroy_cb(struct avctp *session, avctp_destroy_cb_t cb, + void *user_data) +{ + session->destroy = cb; + session->data = user_data; +} + void avctp_shutdown(struct avctp *session) { if (!session) @@ -1456,6 +1466,9 @@ void avctp_shutdown(struct avctp *session) if (session->control) avctp_channel_destroy(session->control); + if (session->destroy) + session->destroy(session->data); + if (session->key.timer > 0) g_source_remove(session->key.timer); diff --git a/android/avctp.h b/android/avctp.h index 99aaf95..a22bf13 100644 --- a/android/avctp.h +++ b/android/avctp.h @@ -103,6 +103,9 @@ typedef size_t (*avctp_browsing_pdu_cb) (struct avctp *session, typedef void (*avctp_destroy_cb_t) (void *user_data); struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version); +void avctp_set_destroy_cb(struct avctp *session, avctp_destroy_cb_t cb, + void *user_data); + int avctp_init_uinput(struct avctp *session, const char *name, const char *address); int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu, -- 1.8.4.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v2 8/8] android/AVRCP: Add initial socket handling 2014-01-24 13:24 [PATCH BlueZ v2 1/8] android: Add copy of current AVCTP implemention Luiz Augusto von Dentz ` (5 preceding siblings ...) 2014-01-24 13:24 ` [PATCH BlueZ v2 7/8] android/AVCTP: Add avctp_set_destroy_cb Luiz Augusto von Dentz @ 2014-01-24 13:24 ` Luiz Augusto von Dentz 6 siblings, 0 replies; 8+ messages in thread From: Luiz Augusto von Dentz @ 2014-01-24 13:24 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> This adds the initial socket listening and handling incoming connections. --- android/avctp.c | 5 +-- android/avrcp.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 4 deletions(-) diff --git a/android/avctp.c b/android/avctp.c index a88b7f7..80513e6 100644 --- a/android/avctp.c +++ b/android/avctp.c @@ -860,10 +860,7 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond, handler = find_handler(control->handlers, avc->opcode); if (!handler) { DBG("handler not found for 0x%02x", avc->opcode); - /* FIXME: - * packet_size += avrcp_handle_vendor_reject(&code, operands); - */ - avc->code = code; + avc->code = AVC_CTYPE_REJECTED; goto done; } diff --git a/android/avrcp.c b/android/avrcp.c index e06d136..807c109 100644 --- a/android/avrcp.c +++ b/android/avrcp.c @@ -28,6 +28,7 @@ #include <stdbool.h> #include <glib.h> +#include "btio/btio.h" #include "lib/bluetooth.h" #include "lib/sdp.h" #include "lib/sdp_lib.h" @@ -36,6 +37,7 @@ #include "avrcp.h" #include "hal-msg.h" #include "ipc.h" +#include "avctp.h" #define L2CAP_PSM_AVCTP 0x17 @@ -46,6 +48,13 @@ static bdaddr_t adapter_addr; static uint32_t record_id = 0; +static GSList *devices = NULL; +static GIOChannel *server = NULL; + +struct avrcp_device { + bdaddr_t dst; + struct avctp *session; +}; static const struct ipc_handler cmd_handlers[] = { }; @@ -118,14 +127,124 @@ static sdp_record_t *avrcp_record(void) return record; } +static void avrcp_device_free(void *data) +{ + struct avrcp_device *dev = data; + + if (dev->session) + avctp_shutdown(dev->session); + + devices = g_slist_remove(devices, dev); + g_free(dev); +} + +static struct avrcp_device *avrcp_device_new(const bdaddr_t *dst) +{ + struct avrcp_device *dev; + + dev = g_new0(struct avrcp_device, 1); + bacpy(&dev->dst, dst); + devices = g_slist_prepend(devices, dev); + + return dev; +} + +static int device_cmp(gconstpointer s, gconstpointer user_data) +{ + const struct avrcp_device *dev = s; + const bdaddr_t *dst = user_data; + + return bacmp(&dev->dst, dst); +} + +static void disconnect_cb(void *data) +{ + struct avrcp_device *dev = data; + + DBG(""); + + dev->session = NULL; + + avrcp_device_free(dev); +} + +static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data) +{ + struct avrcp_device *dev; + bdaddr_t src, dst; + char address[18]; + uint16_t imtu, omtu; + GError *gerr = NULL; + GSList *l; + int fd; + + if (err) { + error("%s", err->message); + return; + } + + bt_io_get(chan, &gerr, + BT_IO_OPT_SOURCE_BDADDR, &src, + BT_IO_OPT_DEST_BDADDR, &dst, + BT_IO_OPT_IMTU, &imtu, + BT_IO_OPT_OMTU, &omtu, + BT_IO_OPT_INVALID); + if (gerr) { + error("%s", gerr->message); + g_error_free(gerr); + g_io_channel_shutdown(chan, TRUE, NULL); + return; + } + + ba2str(&dst, address); + DBG("Incoming connection from %s", address); + + l = g_slist_find_custom(devices, &dst, device_cmp); + if (l) { + error("Unexpected connection"); + return; + } + + fd = g_io_channel_unix_get_fd(chan); + + dev = avrcp_device_new(&dst); + dev->session = avctp_new(fd, imtu, omtu, 0x0100); + + if (!dev->session) { + avrcp_device_free(dev); + return; + } + + avctp_set_destroy_cb(dev->session, disconnect_cb, dev); + + /* FIXME: get the real name of the device */ + avctp_init_uinput(dev->session, "bluetooth", address); + + g_io_channel_set_close_on_unref(chan, FALSE); + + DBG("%s connected", address); +} + bool bt_avrcp_register(const bdaddr_t *addr) { + GError *err = NULL; sdp_record_t *rec; DBG(""); bacpy(&adapter_addr, addr); + server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err, + BT_IO_OPT_SOURCE_BDADDR, &adapter_addr, + BT_IO_OPT_PSM, L2CAP_PSM_AVCTP, + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, + BT_IO_OPT_INVALID); + if (!server) { + error("Failed to listen on AVDTP channel: %s", err->message); + g_error_free(err); + return false; + } + rec = avrcp_record(); if (!rec) { error("Failed to allocate AVRCP record"); @@ -149,8 +268,17 @@ void bt_avrcp_unregister(void) { DBG(""); + g_slist_free_full(devices, avrcp_device_free); + devices = NULL; + ipc_unregister(HAL_SERVICE_ID_AVRCP); bt_adapter_remove_record(record_id); record_id = 0; + + if (server) { + g_io_channel_shutdown(server, TRUE, NULL); + g_io_channel_unref(server); + server = NULL; + } } -- 1.8.4.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2014-01-24 13:24 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-01-24 13:24 [PATCH BlueZ v2 1/8] android: Add copy of current AVCTP implemention Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 2/8] android/AVCTP: Strip dependencies Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 3/8] android: Add initial skeleton for AVRCP in the daemon Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 4/8] android: Add initial skeleton for AVRCP in the HAL Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 5/8] android/haltest: Add init and cleanup calls to rc methods Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 6/8] android/AVRCP: Add implementation of SDP record Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 7/8] android/AVCTP: Add avctp_set_destroy_cb Luiz Augusto von Dentz 2014-01-24 13:24 ` [PATCH BlueZ v2 8/8] android/AVRCP: Add initial socket handling Luiz Augusto von Dentz
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox