2014-01-23 16:39:51

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 1/8] android: Add copy of current AVCTP implemention

From: Luiz Augusto von Dentz <[email protected]>

These files are not added to any makefile on purpose because they still
have external dependencies.
---
{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



2014-01-24 11:27:41

by Andrei Emeltchenko

[permalink] [raw]
Subject: Re: [PATCH BlueZ 6/8] android/AVRCP: Add implementation of SDP record

Hi Luiz,

On Thu, Jan 23, 2014 at 06:39:56PM +0200, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> 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..02dbb68 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(0, &root_uuid);

Should be NULL here and below.

Best regards
Andrei Emeltchenko


2014-01-24 11:22:48

by Andrei Emeltchenko

[permalink] [raw]
Subject: Re: [PATCH BlueZ 6/8] android/AVRCP: Add implementation of SDP record

Hi Luiz,

On Thu, Jan 23, 2014 at 06:39:56PM +0200, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> 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..02dbb68 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

Can we use the same name like in profiles?
AVCTP_CONTROL_PSM

Best regards
Andrei Emeltchenko


2014-01-23 16:39:56

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 6/8] android/AVRCP: Add implementation of SDP record

From: Luiz Augusto von Dentz <[email protected]>

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..02dbb68 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(0, &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(0, &avrtg);
+ sdp_set_service_classes(record, svclass_id);
+
+ /* Protocol Descriptor List */
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto_control[0] = sdp_list_append(0, &l2cap);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto_control[0] = sdp_list_append(proto_control[0], psm);
+ apseq = sdp_list_append(0, proto_control[0]);
+
+ sdp_uuid16_create(&avctp, AVCTP_UUID);
+ proto_control[1] = sdp_list_append(0, &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(0, 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(0, &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


2014-01-23 16:39:58

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 8/8] android/AVRCP: Add initial socket handling

From: Luiz Augusto von Dentz <[email protected]>

This adds the initial socket listening and handling incoming connections.
---
android/avrcp.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 128 insertions(+)

diff --git a/android/avrcp.c b/android/avrcp.c
index 02dbb68..a230ab8 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


2014-01-23 16:39:52

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 2/8] android/AVCTP: Strip dependencies

From: Luiz Augusto von Dentz <[email protected]>

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 | 793 ++++++++--------------------------------------------
android/avctp.h | 40 +--
4 files changed, 134 insertions(+), 701 deletions(-)

diff --git a/android/Android.mk b/android/Android.mk
index 43e6036..b43119e 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -28,6 +28,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 910beb5..41694ee 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..a31dcc6 100644
--- a/android/avctp.c
+++ b/android/avctp.c
@@ -34,27 +34,20 @@
#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 +108,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 +136,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 +152,7 @@ struct avctp_channel {
GQueue *queue;
GSList *processed;
guint process_id;
- GDestroyNotify destroy;
+ avctp_destroy_cb_t destroy;
};

struct key_pressed {
@@ -182,14 +161,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 +174,7 @@ struct avctp {

uint8_t key_quirks[256];
struct key_pressed key;
- bool initiator;
+ uint16_t version;
};

struct avctp_passthrough_handler {
@@ -221,7 +194,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 +232,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 +457,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 +766,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 +786,6 @@ send:

failed:
DBG("AVCTP Browsing: disconnected");
- avctp_set_state(session, AVCTP_STATE_CONNECTED);

if (session->browsing) {
avctp_channel_destroy(session->browsing);
@@ -966,7 +858,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 +884,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 +943,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 +953,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 +999,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 +1257,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 +1278,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 +1321,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 +1344,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->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);
+
+ session->control = control;
+ 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


2014-01-23 16:39:54

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 4/8] android: Add initial skeleton for AVRCP in the HAL

From: Luiz Augusto von Dentz <[email protected]>

---
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 45ceeb2..1e1b60c 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -96,6 +96,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 47e7551..9e96d55 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


2014-01-23 16:39:57

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 7/8] android/AVCTP: Add avctp_set_destroy_cb

From: Luiz Augusto von Dentz <[email protected]>

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 a31dcc6..87e26be 100644
--- a/android/avctp.c
+++ b/android/avctp.c
@@ -175,6 +175,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 {
@@ -1446,6 +1449,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)
@@ -1457,6 +1467,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


2014-01-23 16:39:55

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 5/8] android/haltest: Add init and cleanup calls to rc methods

From: Luiz Augusto von Dentz <[email protected]>

---
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 1e1b60c..99dda1a 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -130,6 +130,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 9e96d55..57e8518 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


2014-01-23 16:39:53

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 3/8] android: Add initial skeleton for AVRCP in the daemon

From: Luiz Augusto von Dentz <[email protected]>

---
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 b43119e..45ceeb2 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -29,6 +29,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 41694ee..47e7551 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