2014-02-06 16:06:11

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCH 1/4] android/avrcp: Decouple AVRCP logic from btio

From: Andrei Emeltchenko <[email protected]>

The patch makes AVRCP to be channel-agnostic so that it might be used in
unit tests. The idea is that all AVRCP logic would come to avrcp-lib and
channel stuff got to avrcp.
---
android/Android.mk | 1 +
android/Makefile.am | 1 +
android/avrcp-lib.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++
android/avrcp-lib.h | 34 +++++++++++++++++++++++
android/avrcp.c | 60 ++++++----------------------------------
5 files changed, 125 insertions(+), 51 deletions(-)
create mode 100644 android/avrcp-lib.c
create mode 100644 android/avrcp-lib.h

diff --git a/android/Android.mk b/android/Android.mk
index 20105e6..9b10cfe 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-lib.c \
bluez/android/avrcp.c \
bluez/android/pan.c \
bluez/android/handsfree.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 5baa8db..3032940 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -36,6 +36,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-lib.h android/avrcp-lib.c \
android/avrcp.h android/avrcp.c \
android/socket.h android/socket.c \
android/pan.h android/pan.c \
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
new file mode 100644
index 0000000..6dcc8ac
--- /dev/null
+++ b/android/avrcp-lib.c
@@ -0,0 +1,80 @@
+/*
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/log.h"
+
+#include "avctp.h"
+#include "avrcp-lib.h"
+
+static GSList *devices = NULL;
+
+void avrcp_device_remove(struct avrcp_device *dev)
+{
+ devices = g_slist_remove(devices, dev);
+ avrcp_device_free(dev);
+}
+
+void avrcp_free_all(void)
+{
+ g_slist_free_full(devices, avrcp_device_free);
+ devices = NULL;
+}
+
+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);
+}
+
+struct avrcp_device *avrcp_find(const bdaddr_t *dst)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(devices, dst, device_cmp);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
new file mode 100644
index 0000000..bf6872e
--- /dev/null
+++ b/android/avrcp-lib.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct avrcp_device {
+ bdaddr_t dst;
+ struct avctp *session;
+ GIOChannel *io;
+};
+
+struct avrcp_device *avrcp_device_new(const bdaddr_t *dst);
+void avrcp_device_free(void *data);
+void avrcp_device_remove(struct avrcp_device *dev);
+void avrcp_free_all(void);
+struct avrcp_device *avrcp_find(const bdaddr_t *dst);
diff --git a/android/avrcp.c b/android/avrcp.c
index 7ee5a8a..22f0a04 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -38,6 +38,7 @@
#include "hal-msg.h"
#include "ipc.h"
#include "avctp.h"
+#include "avrcp-lib.h"

#define L2CAP_PSM_AVCTP 0x17

@@ -48,15 +49,8 @@

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;
- GIOChannel *io;
-};
-
static const struct ipc_handler cmd_handlers[] = {
};

@@ -128,7 +122,7 @@ static sdp_record_t *avrcp_record(void)
return record;
}

-static void avrcp_device_free(void *data)
+void avrcp_device_free(void *data)
{
struct avrcp_device *dev = data;

@@ -143,31 +137,6 @@ static void avrcp_device_free(void *data)
g_free(dev);
}

-static void avrcp_device_remove(struct avrcp_device *dev)
-{
- devices = g_slist_remove(devices, dev);
- avrcp_device_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;
@@ -186,7 +155,6 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
char address[18];
uint16_t imtu, omtu;
GError *gerr = NULL;
- GSList *l;
int fd;

if (err) {
@@ -209,13 +177,9 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)

ba2str(&dst, address);

- l = g_slist_find_custom(devices, &dst, device_cmp);
- if (l) {
- dev = l->data;
- if (dev->session) {
- error("Unexpected connection");
- return;
- }
+ if (avrcp_find(&dst)) {
+ error("Unexpected connection");
+ return;
} else {
DBG("Incoming connection from %s", address);
dev = avrcp_device_new(&dst);
@@ -293,8 +257,7 @@ void bt_avrcp_unregister(void)
{
DBG("");

- g_slist_free_full(devices, avrcp_device_free);
- devices = NULL;
+ avrcp_free_all();

ipc_unregister(HAL_SERVICE_ID_AVRCP);

@@ -331,12 +294,10 @@ void bt_avrcp_connect(const bdaddr_t *dst)
{
struct avrcp_device *dev;
char addr[18];
- GSList *l;

DBG("");

- l = g_slist_find_custom(devices, dst, device_cmp);
- if (l)
+ if (avrcp_find(dst))
return;

dev = avrcp_device_new(dst);
@@ -352,16 +313,13 @@ void bt_avrcp_connect(const bdaddr_t *dst)
void bt_avrcp_disconnect(const bdaddr_t *dst)
{
struct avrcp_device *dev;
- GSList *l;

DBG("");

- l = g_slist_find_custom(devices, dst, device_cmp);
- if (!l)
+ dev = avrcp_find(dst);
+ if (!dev)
return;

- dev = l->data;
-
if (dev->session) {
avctp_shutdown(dev->session);
return;
--
1.8.3.2



2014-02-12 13:13:23

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFCV2] android/avrcp: Decouple AVRCP logic from btio

From: Andrei Emeltchenko <[email protected]>

The patch makes AVRCP to be channel-agnostic so that it might be used in
unit tests. The idea is that all AVRCP logic would come to avrcp-lib and
channel stuff got to avrcp.
---
android/Android.mk | 1 +
android/Makefile.am | 1 +
android/avrcp-lib.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++
android/avrcp-lib.h | 29 +++++++++++++++++++++++++
android/avrcp.c | 28 ++++++++++++++++--------
5 files changed, 112 insertions(+), 9 deletions(-)
create mode 100644 android/avrcp-lib.c
create mode 100644 android/avrcp-lib.h

diff --git a/android/Android.mk b/android/Android.mk
index 71d678b..fa9a86e 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -39,6 +39,7 @@ LOCAL_SRC_FILES := \
bluez/android/avdtp.c \
bluez/android/a2dp.c \
bluez/android/avctp.c \
+ bluez/android/avrcp-lib.c \
bluez/android/avrcp.c \
bluez/android/pan.c \
bluez/android/handsfree.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 1913b42..07cc851 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -36,6 +36,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-lib.h android/avrcp-lib.c \
android/avrcp.h android/avrcp.c \
android/socket.h android/socket.c \
android/pan.h android/pan.c \
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
new file mode 100644
index 0000000..080e37a
--- /dev/null
+++ b/android/avrcp-lib.c
@@ -0,0 +1,62 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/log.h"
+
+#include "avctp.h"
+#include "avrcp-lib.h"
+
+void avrcp_free(void *data)
+{
+ struct avrcp *session = data;
+
+ if (session->session)
+ avctp_shutdown(session->session);
+
+ g_free(session);
+}
+
+struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu,
+ uint16_t version)
+{
+ struct avrcp *session;
+
+ session = g_new0(struct avrcp, 1);
+
+ session->session = avctp_new(fd, imtu, omtu, version);
+ if (!session->session) {
+ g_free(session);
+ return NULL;
+ }
+
+ return session;
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
new file mode 100644
index 0000000..f1dbf0d
--- /dev/null
+++ b/android/avrcp-lib.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct avrcp {
+ struct avctp *session;
+};
+
+struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
+void avrcp_free(void *data);
diff --git a/android/avrcp.c b/android/avrcp.c
index b8304f5..3d3e323 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -38,6 +38,7 @@
#include "hal-msg.h"
#include "ipc.h"
#include "avctp.h"
+#include "avrcp-lib.h"

#define L2CAP_PSM_AVCTP 0x17

@@ -53,7 +54,7 @@ static GIOChannel *server = NULL;

struct avrcp_device {
bdaddr_t dst;
- struct avctp *session;
+ struct avrcp *session;
GIOChannel *io;
};

@@ -133,7 +134,7 @@ static void avrcp_device_free(void *data)
struct avrcp_device *dev = data;

if (dev->session)
- avctp_shutdown(dev->session);
+ avrcp_free(dev->session);

if (dev->io) {
g_io_channel_shutdown(dev->io, FALSE, NULL);
@@ -168,6 +169,17 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
return bacmp(&dev->dst, dst);
}

+static struct avrcp_device *avrcp_find(const bdaddr_t *dst)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(devices, dst, device_cmp);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
static void disconnect_cb(void *data)
{
struct avrcp_device *dev = data;
@@ -222,17 +234,17 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
}

fd = g_io_channel_unix_get_fd(chan);
- dev->session = avctp_new(fd, imtu, omtu, 0x0100);

+ dev->session = avrcp_new(fd, imtu, omtu, 0x0100);
if (!dev->session) {
avrcp_device_free(dev);
return;
}

- avctp_set_destroy_cb(dev->session, disconnect_cb, dev);
+ avctp_set_destroy_cb(dev->session->session, disconnect_cb, dev);

/* FIXME: get the real name of the device */
- avctp_init_uinput(dev->session, "bluetooth", address);
+ avctp_init_uinput(dev->session->session, "bluetooth", address);

g_io_channel_set_close_on_unref(chan, FALSE);

@@ -331,12 +343,10 @@ void bt_avrcp_connect(const bdaddr_t *dst)
{
struct avrcp_device *dev;
char addr[18];
- GSList *l;

DBG("");

- l = g_slist_find_custom(devices, dst, device_cmp);
- if (l)
+ if (avrcp_find(dst))
return;

dev = avrcp_device_new(dst);
@@ -363,7 +373,7 @@ void bt_avrcp_disconnect(const bdaddr_t *dst)
dev = l->data;

if (dev->session) {
- avctp_shutdown(dev->session);
+ avrcp_free(dev->session);
return;
}

--
1.8.3.2


2014-02-11 14:37:12

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 1/4] android/avrcp: Decouple AVRCP logic from btio

Hi Andrei,

On Tuesday 11 of February 2014 15:03:07 Andrei Emeltchenko wrote:
> Hi All
>
> On Thu, Feb 06, 2014 at 06:06:11PM +0200, Andrei Emeltchenko wrote:
> > From: Andrei Emeltchenko <[email protected]>
> >
> > The patch makes AVRCP to be channel-agnostic so that it might be used in
> > unit tests. The idea is that all AVRCP logic would come to avrcp-lib and
> > channel stuff got to avrcp.
>
> Any comments regarding this patch?

Waiting for V2 as discussed offline.

--
BR
Szymon Janc

2014-02-11 13:03:07

by Andrei Emeltchenko

[permalink] [raw]
Subject: Re: [PATCH 1/4] android/avrcp: Decouple AVRCP logic from btio

Hi All

On Thu, Feb 06, 2014 at 06:06:11PM +0200, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <[email protected]>
>
> The patch makes AVRCP to be channel-agnostic so that it might be used in
> unit tests. The idea is that all AVRCP logic would come to avrcp-lib and
> channel stuff got to avrcp.

Any comments regarding this patch?

Best regards
Andrei Emeltchenko


> ---
> android/Android.mk | 1 +
> android/Makefile.am | 1 +
> android/avrcp-lib.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> android/avrcp-lib.h | 34 +++++++++++++++++++++++
> android/avrcp.c | 60 ++++++----------------------------------
> 5 files changed, 125 insertions(+), 51 deletions(-)
> create mode 100644 android/avrcp-lib.c
> create mode 100644 android/avrcp-lib.h
>
> diff --git a/android/Android.mk b/android/Android.mk
> index 20105e6..9b10cfe 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-lib.c \
> bluez/android/avrcp.c \
> bluez/android/pan.c \
> bluez/android/handsfree.c \
> diff --git a/android/Makefile.am b/android/Makefile.am
> index 5baa8db..3032940 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -36,6 +36,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-lib.h android/avrcp-lib.c \
> android/avrcp.h android/avrcp.c \
> android/socket.h android/socket.c \
> android/pan.h android/pan.c \
> diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
> new file mode 100644
> index 0000000..6dcc8ac
> --- /dev/null
> +++ b/android/avrcp-lib.c
> @@ -0,0 +1,80 @@
> +/*
> + *
> + * 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
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdbool.h>
> +#include <glib.h>
> +
> +#include "lib/bluetooth.h"
> +
> +#include "src/log.h"
> +
> +#include "avctp.h"
> +#include "avrcp-lib.h"
> +
> +static GSList *devices = NULL;
> +
> +void avrcp_device_remove(struct avrcp_device *dev)
> +{
> + devices = g_slist_remove(devices, dev);
> + avrcp_device_free(dev);
> +}
> +
> +void avrcp_free_all(void)
> +{
> + g_slist_free_full(devices, avrcp_device_free);
> + devices = NULL;
> +}
> +
> +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);
> +}
> +
> +struct avrcp_device *avrcp_find(const bdaddr_t *dst)
> +{
> + GSList *l;
> +
> + l = g_slist_find_custom(devices, dst, device_cmp);
> + if (!l)
> + return NULL;
> +
> + return l->data;
> +}
> diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
> new file mode 100644
> index 0000000..bf6872e
> --- /dev/null
> +++ b/android/avrcp-lib.h
> @@ -0,0 +1,34 @@
> +/*
> + *
> + * 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
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +struct avrcp_device {
> + bdaddr_t dst;
> + struct avctp *session;
> + GIOChannel *io;
> +};
> +
> +struct avrcp_device *avrcp_device_new(const bdaddr_t *dst);
> +void avrcp_device_free(void *data);
> +void avrcp_device_remove(struct avrcp_device *dev);
> +void avrcp_free_all(void);
> +struct avrcp_device *avrcp_find(const bdaddr_t *dst);
> diff --git a/android/avrcp.c b/android/avrcp.c
> index 7ee5a8a..22f0a04 100644
> --- a/android/avrcp.c
> +++ b/android/avrcp.c
> @@ -38,6 +38,7 @@
> #include "hal-msg.h"
> #include "ipc.h"
> #include "avctp.h"
> +#include "avrcp-lib.h"
>
> #define L2CAP_PSM_AVCTP 0x17
>
> @@ -48,15 +49,8 @@
>
> 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;
> - GIOChannel *io;
> -};
> -
> static const struct ipc_handler cmd_handlers[] = {
> };
>
> @@ -128,7 +122,7 @@ static sdp_record_t *avrcp_record(void)
> return record;
> }
>
> -static void avrcp_device_free(void *data)
> +void avrcp_device_free(void *data)
> {
> struct avrcp_device *dev = data;
>
> @@ -143,31 +137,6 @@ static void avrcp_device_free(void *data)
> g_free(dev);
> }
>
> -static void avrcp_device_remove(struct avrcp_device *dev)
> -{
> - devices = g_slist_remove(devices, dev);
> - avrcp_device_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;
> @@ -186,7 +155,6 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
> char address[18];
> uint16_t imtu, omtu;
> GError *gerr = NULL;
> - GSList *l;
> int fd;
>
> if (err) {
> @@ -209,13 +177,9 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
>
> ba2str(&dst, address);
>
> - l = g_slist_find_custom(devices, &dst, device_cmp);
> - if (l) {
> - dev = l->data;
> - if (dev->session) {
> - error("Unexpected connection");
> - return;
> - }
> + if (avrcp_find(&dst)) {
> + error("Unexpected connection");
> + return;
> } else {
> DBG("Incoming connection from %s", address);
> dev = avrcp_device_new(&dst);
> @@ -293,8 +257,7 @@ void bt_avrcp_unregister(void)
> {
> DBG("");
>
> - g_slist_free_full(devices, avrcp_device_free);
> - devices = NULL;
> + avrcp_free_all();
>
> ipc_unregister(HAL_SERVICE_ID_AVRCP);
>
> @@ -331,12 +294,10 @@ void bt_avrcp_connect(const bdaddr_t *dst)
> {
> struct avrcp_device *dev;
> char addr[18];
> - GSList *l;
>
> DBG("");
>
> - l = g_slist_find_custom(devices, dst, device_cmp);
> - if (l)
> + if (avrcp_find(dst))
> return;
>
> dev = avrcp_device_new(dst);
> @@ -352,16 +313,13 @@ void bt_avrcp_connect(const bdaddr_t *dst)
> void bt_avrcp_disconnect(const bdaddr_t *dst)
> {
> struct avrcp_device *dev;
> - GSList *l;
>
> DBG("");
>
> - l = g_slist_find_custom(devices, dst, device_cmp);
> - if (!l)
> + dev = avrcp_find(dst);
> + if (!dev)
> return;
>
> - dev = l->data;
> -
> if (dev->session) {
> avctp_shutdown(dev->session);
> return;
> --
> 1.8.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2014-02-06 16:06:12

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCH 2/4] unit/avrcp: First unit test for AVRCP profile

From: Andrei Emeltchenko <[email protected]>

Test TP/MPS/BV-01-C [SetAddressedPlayer – CT] verifies
SetAddressedPlayer command.
---
Makefile.am | 9 ++
unit/test-avrcp.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 340 insertions(+)
create mode 100644 unit/test-avrcp.c

diff --git a/Makefile.am b/Makefile.am
index 1a44a9f..67b7167 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -281,6 +281,15 @@ unit_test_avctp_SOURCES = unit/test-avctp.c \
android/avctp.c android/avctp.h
unit_test_avctp_LDADD = @GLIB_LIBS@

+unit_tests += unit/test-avrcp
+
+unit_test_avrcp_SOURCES = unit/test-avrcp.c \
+ src/shared/util.h src/shared/util.c \
+ src/log.h src/log.c \
+ android/avctp.c android/avctp.h \
+ android/avrcp-lib.c android/avrcp-lib.h
+unit_test_avrcp_LDADD = @GLIB_LIBS@ lib/libbluetooth-internal.la
+
unit_tests += unit/test-gdbus-client

unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
new file mode 100644
index 0000000..7efdaea
--- /dev/null
+++ b/unit/test-avrcp.c
@@ -0,0 +1,331 @@
+/*
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "src/log.h"
+#include "lib/bluetooth.h"
+
+#include "android/avctp.h"
+#include "android/avrcp-lib.h"
+
+#define IEEEID_BTSIG 0x001958
+
+struct test_pdu {
+ bool valid;
+ bool fragmented;
+ const uint8_t *data;
+ size_t size;
+};
+
+struct test_data {
+ char *test_name;
+ struct test_pdu *pdu_list;
+};
+
+struct context {
+ GMainLoop *main_loop;
+ struct avrcp_device *dev;
+ guint source;
+ guint process;
+ int fd;
+ unsigned int pdu_offset;
+ const struct test_data *data;
+};
+
+#define data(args...) ((const unsigned char[]) { args })
+
+#define raw_pdu(args...) \
+ { \
+ .valid = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define frg_pdu(args...) \
+ { \
+ .valid = true, \
+ .fragmented = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define define_test(name, function, args...) \
+ do { \
+ const struct test_pdu pdus[] = { \
+ args, { } \
+ }; \
+ static struct test_data data; \
+ data.test_name = g_strdup(name); \
+ data.pdu_list = g_malloc(sizeof(pdus)); \
+ memcpy(data.pdu_list, pdus, sizeof(pdus)); \
+ g_test_add_data_func(name, &data, function); \
+ } while (0)
+
+static void test_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ g_print("%s%s\n", prefix, str);
+}
+
+static void test_free(gconstpointer user_data)
+{
+ const struct test_data *data = user_data;
+
+ g_free(data->test_name);
+ g_free(data->pdu_list);
+}
+
+static gboolean context_quit(gpointer user_data)
+{
+ struct context *context = user_data;
+
+ if (context->process > 0)
+ g_source_remove(context->process);
+
+ g_main_loop_quit(context->main_loop);
+
+ return FALSE;
+}
+
+static gboolean send_pdu(gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ ssize_t len;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ len = write(context->fd, pdu->data, pdu->size);
+
+ if (g_test_verbose())
+ util_hexdump('<', pdu->data, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ if (pdu->fragmented)
+ return send_pdu(user_data);
+
+ context->process = 0;
+ return FALSE;
+}
+
+static void context_process(struct context *context)
+{
+ if (!context->data->pdu_list[context->pdu_offset].valid) {
+ context_quit(context);
+ return;
+ }
+
+ context->process = g_idle_add(send_pdu, context);
+}
+
+static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ unsigned char buf[512];
+ ssize_t len;
+ int fd;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ context->source = 0;
+ g_print("%s: cond %x\n", __func__, cond);
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ len = read(fd, buf, sizeof(buf));
+
+ g_assert(len > 0);
+
+ if (g_test_verbose())
+ util_hexdump('>', buf, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+ if (!pdu->fragmented)
+ context_process(context);
+
+ return TRUE;
+}
+
+static struct context *create_context(uint16_t version, gconstpointer data)
+{
+ struct context *context = g_new0(struct context, 1);
+ GIOChannel *channel;
+ int err, sv[2];
+ bdaddr_t dst = {};
+
+ context->main_loop = g_main_loop_new(NULL, FALSE);
+ g_assert(context->main_loop);
+
+ err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+ g_assert(err == 0);
+
+ context->dev = avrcp_device_new(&dst);
+ context->dev->session = avctp_new(sv[0], 672, 672, version);
+ g_assert(context->dev->session != NULL);
+
+ channel = g_io_channel_unix_new(sv[1]);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ context->source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ test_handler, context);
+ g_assert(context->source > 0);
+
+ g_io_channel_unref(channel);
+
+ context->fd = sv[1];
+ context->data = data;
+
+ return context;
+}
+
+static void execute_context(struct context *context)
+{
+ g_main_loop_run(context->main_loop);
+
+ if (context->source > 0)
+ g_source_remove(context->source);
+
+ avrcp_device_free(context->dev);
+
+ g_main_loop_unref(context->main_loop);
+
+ test_free(context->data);
+ g_free(context);
+}
+
+#define AVRCP_SET_ADDRESSED_PLAYER 0x60
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avrcp_header {
+ uint8_t company_id[3];
+ uint8_t pdu_id;
+ uint8_t packet_type:2;
+ uint8_t rsvd:6;
+ uint16_t params_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avrcp_header {
+ uint8_t company_id[3];
+ uint8_t pdu_id;
+ uint8_t rsvd:6;
+ uint8_t packet_type:2;
+ uint16_t params_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#else
+#error "Unknown byte order"
+#endif
+
+static void set_company_id(uint8_t cid[3], const uint32_t cid_in)
+{
+ cid[0] = cid_in >> 16;
+ cid[1] = cid_in >> 8;
+ cid[2] = cid_in;
+}
+
+static int avrcp_set_addr_player(struct context *context)
+{
+ uint8_t buf[AVRCP_HEADER_LENGTH + 2];
+ struct avrcp_header *pdu = (void *) buf;
+ struct avctp *session = context->dev->session;
+
+ memset(buf, 0, sizeof(buf));
+
+ set_company_id(pdu->company_id, IEEEID_BTSIG);
+
+ pdu->pdu_id = AVRCP_SET_ADDRESSED_PLAYER;
+ pdu->params[0] = 0xab;
+ pdu->params[1] = 0xcd;
+ pdu->params_len = htons(2);
+
+ return avctp_send_vendordep_req(session, AVC_CTYPE_CONTROL,
+ AVC_SUBUNIT_PANEL, buf, sizeof(buf),
+ NULL, NULL);
+}
+
+static void test_client(gconstpointer data)
+{
+ struct context *context = create_context(0x0100, data);
+ int ret = 0;
+
+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-01-C"))
+ ret = avrcp_set_addr_player(context);
+
+ DBG("ret = %d", ret);
+
+ g_assert(!ret);
+
+ execute_context(context);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ if (g_test_verbose())
+ __btd_log_init("*", 0);
+
+ /* Media Player Selection Commands and Notifications tests */
+
+ define_test("/TP/MPS/BV-01-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48, 0x00,
+ 0x00, 0x19, 0x58, 0x60, 0x00, 0x00,
+ 0x02, 0xab, 0xcd));
+
+ return g_test_run();
+}
--
1.8.3.2


2014-02-06 16:06:13

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCH 3/4] unit/avrcp: Add support for browsing AVCTP channel

From: Andrei Emeltchenko <[email protected]>

---
unit/test-avrcp.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 92 insertions(+), 4 deletions(-)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 7efdaea..58e4c15 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -47,6 +47,7 @@
struct test_pdu {
bool valid;
bool fragmented;
+ bool browse;
const uint8_t *data;
size_t size;
};
@@ -60,8 +61,10 @@ struct context {
GMainLoop *main_loop;
struct avrcp_device *dev;
guint source;
+ guint browse_source;
guint process;
int fd;
+ int browse_fd;
unsigned int pdu_offset;
const struct test_data *data;
};
@@ -75,6 +78,14 @@ struct context {
.size = sizeof(data(args)), \
}

+#define brs_pdu(args...) \
+ { \
+ .valid = true, \
+ .browse = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
#define frg_pdu(args...) \
{ \
.valid = true, \
@@ -130,7 +141,10 @@ static gboolean send_pdu(gpointer user_data)

pdu = &context->data->pdu_list[context->pdu_offset++];

- len = write(context->fd, pdu->data, pdu->size);
+ if (pdu->browse)
+ len = write(context->browse_fd, pdu->data, pdu->size);
+ else
+ len = write(context->fd, pdu->data, pdu->size);

if (g_test_verbose())
util_hexdump('<', pdu->data, len, test_debug, "AVCTP: ");
@@ -163,6 +177,8 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
ssize_t len;
int fd;

+ DBG("");
+
pdu = &context->data->pdu_list[context->pdu_offset++];

if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
@@ -190,23 +206,68 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
return TRUE;
}

+static gboolean browse_test_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ unsigned char buf[512];
+ ssize_t len;
+ int fd;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ context->browse_source = 0;
+ g_print("%s: cond %x\n", __func__, cond);
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ len = read(fd, buf, sizeof(buf));
+
+ g_assert(len > 0);
+
+ if (g_test_verbose())
+ util_hexdump('>', buf, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+ if (!pdu->fragmented)
+ context_process(context);
+
+ return TRUE;
+}
+
static struct context *create_context(uint16_t version, gconstpointer data)
{
struct context *context = g_new0(struct context, 1);
+ struct avctp *session;
GIOChannel *channel;
int err, sv[2];
bdaddr_t dst = {};
+ int ret;
+
+ DBG("");

context->main_loop = g_main_loop_new(NULL, FALSE);
g_assert(context->main_loop);

+ /* Control channel setup */
+
err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
- g_assert(err == 0);
+ g_assert(!err);

context->dev = avrcp_device_new(&dst);
- context->dev->session = avctp_new(sv[0], 672, 672, version);
- g_assert(context->dev->session != NULL);
+ g_assert(context->dev);

+ session = avctp_new(sv[0], 672, 672, version);
+ g_assert(session);
+
+ context->dev->session = session;
channel = g_io_channel_unix_new(sv[1]);

g_io_channel_set_close_on_unref(channel, TRUE);
@@ -221,6 +282,30 @@ static struct context *create_context(uint16_t version, gconstpointer data)
g_io_channel_unref(channel);

context->fd = sv[1];
+
+ /* Browsing channel setup */
+
+ err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+ g_assert(!err);
+
+ ret = avctp_connect_browsing(session, sv[0], 672, 672);
+ g_assert(!ret);
+
+ channel = g_io_channel_unix_new(sv[1]);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ context->browse_source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ browse_test_handler, context);
+ g_assert(context->browse_source > 0);
+
+ g_io_channel_unref(channel);
+
+ context->browse_fd = sv[1];
+
context->data = data;

return context;
@@ -233,6 +318,9 @@ static void execute_context(struct context *context)
if (context->source > 0)
g_source_remove(context->source);

+ if (context->browse_source > 0)
+ g_source_remove(context->browse_source);
+
avrcp_device_free(context->dev);

g_main_loop_unref(context->main_loop);
--
1.8.3.2


2014-02-06 16:06:14

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCH 4/4] unit/avrcp: Add TP/MPS/BV-03-C test case

From: Andrei Emeltchenko <[email protected]>

Test verifies that the Set Browsed Player command issued by the
AVRCP controller.
---
unit/test-avrcp.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 58e4c15..211ea36 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -330,6 +330,7 @@ static void execute_context(struct context *context)
}

#define AVRCP_SET_ADDRESSED_PLAYER 0x60
+#define AVRCP_SET_BROWSED_PLAYER 0x70

#if __BYTE_ORDER == __LITTLE_ENDIAN

@@ -359,6 +360,13 @@ struct avrcp_header {
#error "Unknown byte order"
#endif

+struct avrcp_browsing_header {
+ uint8_t pdu_id;
+ uint16_t param_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_BROWSING_HEADER_LENGTH 3
+
static void set_company_id(uint8_t cid[3], const uint32_t cid_in)
{
cid[0] = cid_in >> 16;
@@ -386,6 +394,35 @@ static int avrcp_set_addr_player(struct context *context)
NULL, NULL);
}

+static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
+ uint8_t *operands,
+ size_t operand_count,
+ void *user_data)
+{
+ DBG("");
+
+ return FALSE;
+}
+
+static int avrcp_set_browsed_player(struct context *context)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 2];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+ struct avctp *session = context->dev->session;
+
+ DBG("");
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_SET_BROWSED_PLAYER;
+ pdu->params[0] = 0xab;
+ pdu->params[1] = 0xcd;
+ pdu->param_len = htons(2);
+
+ return avctp_send_browsing_req(session, buf, sizeof(buf),
+ avrcp_set_browsed_player_rsp, session);
+}
+
static void test_client(gconstpointer data)
{
struct context *context = create_context(0x0100, data);
@@ -394,6 +431,9 @@ static void test_client(gconstpointer data)
if (g_str_equal(context->data->test_name, "/TP/MPS/BV-01-C"))
ret = avrcp_set_addr_player(context);

+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-03-C"))
+ ret = avrcp_set_browsed_player(context);
+
DBG("ret = %d", ret);

g_assert(!ret);
@@ -415,5 +455,8 @@ int main(int argc, char *argv[])
0x00, 0x19, 0x58, 0x60, 0x00, 0x00,
0x02, 0xab, 0xcd));

+ define_test("/TP/MPS/BV-03-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x70, 0x00, 0x02,
+ 0xab, 0xcd));
return g_test_run();
}
--
1.8.3.2