From: Andrei Emeltchenko <[email protected]>
Support for browsing unit tests
Andrei Emeltchenko (4):
android/avrcp: Add avrcp_connect_browsing()
android/avrcp: Add avrcp_set_browsed_player() function
unit/avrcp: Add browsing channel support in unit testing
unit/avrcp: Add /TP/MPS/BV-03-C test
.gitignore | 2 ++
android/avrcp-lib.c | 24 +++++++++++++
android/avrcp-lib.h | 11 ++++++
unit/test-avrcp.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 132 insertions(+), 2 deletions(-)
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/avrcp-lib.c | 28 ++++++++++++++++++++++++++++
android/avrcp-lib.h | 10 ++++++++++
2 files changed, 38 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index fe6d7b4..969c519 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -521,3 +521,31 @@ int avrcp_set_browsed_player(struct avrcp *session, uint16_t player_id,
return avctp_send_browsing_req(session->conn, buf, sizeof(buf),
func, user_data);
}
+
+int avrcp_get_folder_items(struct avrcp *session, uint8_t scope,
+ uint32_t start, uint32_t end, uint8_t *attr,
+ size_t attr_count, avctp_browsing_rsp_cb func,
+ void *user_data)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 10 + attr_count];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_GET_FOLDER_ITEMS;
+ pdu->param_len = htons(10 + attr_count);
+
+ /* Scope */
+ pdu->params[0] = scope;
+
+ bt_put_be32(start, &pdu->params[1]);
+ bt_put_be32(end, &pdu->params[5]);
+
+ /* attr count */
+ pdu->params[9] = attr_count;
+
+ memcpy(&pdu->params[10], attr, attr_count);
+
+ return avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+ func, user_data);
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 88d2126..803f877 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -84,6 +84,12 @@
#define AVRCP_ATTRIBUTE_SCAN 0x04
#define AVRCP_ATTRIBUTE_LAST AVRCP_ATTRIBUTE_SCAN
+/* Media Scope */
+#define AVRCP_MEDIA_PLAYER_LIST 0x00
+#define AVRCP_MEDIA_PLAYER_VFS 0x01
+#define AVRCP_MEDIA_SEARCH 0x02
+#define AVRCP_MEDIA_NOW_PLAYING 0x03
+
/* Company IDs for vendor dependent commands */
#define IEEEID_BTSIG 0x001958
@@ -179,3 +185,7 @@ int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op);
int avrcp_set_browsed_player(struct avrcp *session, uint16_t player_id,
avctp_browsing_rsp_cb func, void *user_data);
+int avrcp_get_folder_items(struct avrcp *session, uint8_t scope,
+ uint32_t start, uint32_t end, uint8_t *attr,
+ size_t attr_count, avctp_browsing_rsp_cb func,
+ void *user_data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
.gitignore | 2 ++
unit/test-avrcp.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 89 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7a2af5a..0a66fec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -127,3 +127,5 @@ android/bluetoothd-snoop
android/test-ipc
android/test-*.log
android/test-*.trs
+
+patches/
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index b86d572..623e62e 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -46,6 +46,7 @@
struct test_pdu {
bool valid;
bool fragmented;
+ bool browse;
const uint8_t *data;
size_t size;
};
@@ -59,8 +60,10 @@ struct context {
GMainLoop *main_loop;
struct avrcp *session;
guint source;
+ guint browse_source;
guint process;
int fd;
+ int browse_fd;
unsigned int pdu_offset;
const struct test_data *data;
};
@@ -74,6 +77,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, \
@@ -129,7 +140,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, "AVRCP: ");
@@ -162,6 +176,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)) {
@@ -189,17 +205,59 @@ 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;
+
+ DBG("");
+
+ 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);
GIOChannel *channel;
int err, sv[2];
+ 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->session = avrcp_new(sv[0], 672, 672, version);
g_assert(context->session != NULL);
@@ -218,6 +276,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);
+
+ err = avrcp_connect_browsing(context->session, sv[0], 672, 672);
+ g_assert(!err);
+
+ 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;
@@ -230,6 +312,9 @@ static void destroy_context(struct context *context)
avrcp_shutdown(context->session);
+ if (context->browse_source > 0)
+ g_source_remove(context->browse_source);
+
g_main_loop_unref(context->main_loop);
test_free(context->data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Add support for browsing channel
---
android/avrcp-lib.c | 6 ++++++
android/avrcp-lib.h | 2 ++
2 files changed, 8 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index f5ae5a3..39fc748 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -244,6 +244,12 @@ struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
return session;
}
+int avrcp_connect_browsing(struct avrcp *session, int fd, size_t imtu,
+ size_t omtu)
+{
+ return avctp_connect_browsing(session->conn, fd, imtu, omtu);
+}
+
void avrcp_set_destroy_cb(struct avrcp *session, avrcp_destroy_cb_t cb,
void *user_data)
{
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 4adf4bf..7f82d7d 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -123,6 +123,8 @@ struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
void avrcp_shutdown(struct avrcp *session);
void avrcp_set_destroy_cb(struct avrcp *session, avrcp_destroy_cb_t cb,
void *user_data);
+int avrcp_connect_browsing(struct avrcp *session, int fd, size_t imtu,
+ size_t omtu);
void avrcp_set_control_handlers(struct avrcp *session,
const struct avrcp_control_handler *handlers,
void *user_data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/avrcp-lib.c | 18 ++++++++++++++++++
android/avrcp-lib.h | 9 +++++++++
2 files changed, 27 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 39fc748..0e9f0df 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -503,3 +503,21 @@ int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op)
return avctp_send_passthrough(session->conn, AVC_VENDOR_UNIQUE, params,
sizeof(params));
}
+
+int avrcp_set_browsed_player(struct avrcp *session, uint16_t player_id,
+ avctp_browsing_rsp_cb func, void *user_data)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 2];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+
+ DBG("");
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_SET_BROWSED_PLAYER;
+ bt_put_be16(player_id, pdu->params);
+ pdu->param_len = htons(2);
+
+ return avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+ func, user_data);
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 7f82d7d..88d2126 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -90,6 +90,13 @@
/* Parameters legths */
#define AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH 5
+struct avrcp_browsing_header {
+ uint8_t pdu_id;
+ uint16_t param_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_BROWSING_HEADER_LENGTH 3
+
struct avrcp;
struct avrcp_control_handler {
@@ -170,3 +177,5 @@ int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
uint8_t code, uint8_t *params,
size_t params_len);
int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op);
+int avrcp_set_browsed_player(struct avrcp *session, uint16_t player_id,
+ avctp_browsing_rsp_cb func, void *user_data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Test verifies that GetFolderItems cmd for the Media Player List
issued by the Controller.
---
unit/test-avrcp.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 22b3e4a..b173e8d 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -713,6 +713,11 @@ static void test_client(gconstpointer data)
if (g_str_equal(context->data->test_name, "/TP/MPS/BV-03-C"))
avrcp_set_browsed_player(context->session, 0xabcd, NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-08-C"))
+ avrcp_get_folder_items(context->session,
+ AVRCP_MEDIA_PLAYER_LIST, 0, 2, NULL, 0,
+ NULL, NULL);
+
if (g_str_equal(context->data->test_name, "/TP/CFG/BV-01-C"))
avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED,
NULL, NULL);
@@ -794,6 +799,14 @@ int main(int argc, char *argv[])
raw_pdu(0x00, 0x11, 0x0e, 0x70, 0x00, 0x02,
0xab, 0xcd));
+ /* GetFolderItems - CT */
+ define_test("/TP/MPS/BV-08-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, AVRCP_GET_FOLDER_ITEMS,
+ 0x00, 0x0a, AVRCP_MEDIA_PLAYER_LIST,
+ 0x00, 0x00, 0x00, 0x00, /* start */
+ 0x00, 0x00, 0x00, 0x02, /* end */
+ 0x00));
+
/* Connection Establishment for Control tests */
/*
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Test verifies that SetBrowsedPlayer command issued by the Controller.
---
unit/test-avrcp.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 623e62e..22b3e4a 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -710,6 +710,9 @@ static void test_client(gconstpointer data)
avrcp_set_addressed_player(context->session, 0xabcd, NULL,
NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-03-C"))
+ avrcp_set_browsed_player(context->session, 0xabcd, NULL, NULL);
+
if (g_str_equal(context->data->test_name, "/TP/CFG/BV-01-C"))
avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED,
NULL, NULL);
@@ -786,6 +789,11 @@ int main(int argc, char *argv[])
AVRCP_SET_ADDRESSED_PLAYER,
0x00, 0x00, 0x01, 0x00));
+ /* SetBrowsedPlayer - CT */
+ define_test("/TP/MPS/BV-03-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x70, 0x00, 0x02,
+ 0xab, 0xcd));
+
/* Connection Establishment for Control tests */
/*
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/avrcp-lib.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 0e9f0df..fe6d7b4 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -346,7 +346,7 @@ int avrcp_register_notification(struct avrcp *session, uint8_t event,
uint32_t interval, avctp_rsp_cb func,
void *user_data)
{
- uint8_t params[5];
+ uint8_t params[AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH];
params[0] = event;
bt_put_be32(interval, ¶ms[1]);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Test verifies that SetBrowsedPlayer command issued by the Controller.
---
unit/test-avrcp.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 917945d..6a4a2e1 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -709,6 +709,9 @@ static void test_client(gconstpointer data)
if (g_str_equal(context->data->test_name, "/TP/MPS/BV-01-C"))
avrcp_set_addr_player(context->session, 0xabcd, NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-03-C"))
+ avrcp_set_browsed_player(context->session, 0xabcd, NULL, NULL);
+
if (g_str_equal(context->data->test_name, "/TP/CFG/BV-01-C"))
avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED,
NULL, NULL);
@@ -785,6 +788,11 @@ int main(int argc, char *argv[])
AVRCP_SET_ADDRESSED_PLAYER,
0x00, 0x00, 0x01, 0x00));
+ /* SetBrowsedPlayer - CT */
+ define_test("/TP/MPS/BV-03-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x70, 0x00, 0x02,
+ 0xab, 0xcd));
+
/* Connection Establishment for Control tests */
/*
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/avrcp-lib.c | 18 ++++++++++++++++++
android/avrcp-lib.h | 9 +++++++++
2 files changed, 27 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 8385b1b..04cd88e 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -500,3 +500,21 @@ int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op)
return avctp_send_passthrough(session->conn, AVC_VENDOR_UNIQUE, params,
sizeof(params));
}
+
+int avrcp_set_browsed_player(struct avrcp *session, uint16_t player_id,
+ avctp_browsing_rsp_cb func, void *user_data)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 2];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+
+ DBG("");
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_SET_BROWSED_PLAYER;
+ bt_put_be16(player_id, pdu->params);
+ pdu->param_len = htons(2);
+
+ return avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+ func, user_data);
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 3f24a82..3fabbbe 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -90,6 +90,13 @@
/* Parameters legths */
#define AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH 5
+struct avrcp_browsing_header {
+ uint8_t pdu_id;
+ uint16_t param_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_BROWSING_HEADER_LENGTH 3
+
struct avrcp;
struct avrcp_control_handler {
@@ -170,3 +177,5 @@ int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
uint8_t code, uint8_t *params,
size_t params_len);
int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op);
+int avrcp_set_browsed_player(struct avrcp *session, uint16_t player_id,
+ avctp_browsing_rsp_cb func, void *user_data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
.gitignore | 2 ++
unit/test-avrcp.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 89 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7a2af5a..0a66fec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -127,3 +127,5 @@ android/bluetoothd-snoop
android/test-ipc
android/test-*.log
android/test-*.trs
+
+patches/
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 75e8036..917945d 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -46,6 +46,7 @@
struct test_pdu {
bool valid;
bool fragmented;
+ bool browse;
const uint8_t *data;
size_t size;
};
@@ -59,8 +60,10 @@ struct context {
GMainLoop *main_loop;
struct avrcp *session;
guint source;
+ guint browse_source;
guint process;
int fd;
+ int browse_fd;
unsigned int pdu_offset;
const struct test_data *data;
};
@@ -74,6 +77,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, \
@@ -129,7 +140,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, "AVRCP: ");
@@ -162,6 +176,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)) {
@@ -189,17 +205,59 @@ 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;
+
+ DBG("");
+
+ 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);
GIOChannel *channel;
int err, sv[2];
+ 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->session = avrcp_new(sv[0], 672, 672, version);
g_assert(context->session != NULL);
@@ -218,6 +276,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);
+
+ err = avrcp_connect_browsing(context->session, sv[0], 672, 672);
+ g_assert(!err);
+
+ 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;
@@ -230,6 +312,9 @@ static void destroy_context(struct context *context)
avrcp_shutdown(context->session);
+ if (context->browse_source > 0)
+ g_source_remove(context->browse_source);
+
g_main_loop_unref(context->main_loop);
test_free(context->data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Add support for browsing channel
---
android/avrcp-lib.c | 6 ++++++
android/avrcp-lib.h | 2 ++
2 files changed, 8 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 68c2df4..8385b1b 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -244,6 +244,12 @@ struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
return session;
}
+int avrcp_connect_browsing(struct avrcp *session, int fd, size_t imtu,
+ size_t omtu)
+{
+ return avctp_connect_browsing(session->conn, fd, imtu, omtu);
+}
+
void avrcp_set_destroy_cb(struct avrcp *session, avrcp_destroy_cb_t cb,
void *user_data)
{
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 17072fb..3f24a82 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -123,6 +123,8 @@ struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
void avrcp_shutdown(struct avrcp *session);
void avrcp_set_destroy_cb(struct avrcp *session, avrcp_destroy_cb_t cb,
void *user_data);
+int avrcp_connect_browsing(struct avrcp *session, int fd, size_t imtu,
+ size_t omtu);
void avrcp_set_control_handlers(struct avrcp *session,
const struct avrcp_control_handler *handlers,
void *user_data);
--
1.8.3.2