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 1a2fa2a..393ab54 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -293,6 +293,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 0b867aa..ca7a57f 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -207,6 +207,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_register_player(struct avrcp *session,
const struct avrcp_control_ind *ind,
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Test verifies that GetItemAttributes command issued by the Controller.
---
unit/test-avrcp.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 733aff4..9005e4e 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -597,6 +597,11 @@ static void test_client(gconstpointer data)
avrcp_change_path(context->session, 0x01, 0x01, 0xaabb,
NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MCN/CB/BV-07-C"))
+ avrcp_get_item_attributes(context->session,
+ AVRCP_MEDIA_PLAYER_VFS, 0x01, 0xaabb,
+ 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);
@@ -704,6 +709,15 @@ int main(int argc, char *argv[])
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01 /* Folder UID */));
+ /* GetItemAttributes - CT */
+ define_test("/TP/MCN/CB/BV-07-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, AVRCP_GET_ITEM_ATTRIBUTES,
+ 0x00, 0x0c, AVRCP_MEDIA_PLAYER_VFS,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, /* uuid */
+ 0xaa, 0xbb, /* counter */
+ 0x00)); /* num attr */
+
/* Media Player Selection IOP tests */
/* Listing of available media players */
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
text[] needs to be of size number for get_value_text()
---
unit/test-avrcp.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index fdca98f..00fdaff 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -431,10 +431,15 @@ static int get_value_text(struct avrcp *session, uint8_t transaction,
uint8_t attr, uint8_t number, uint8_t *values,
void *user_data)
{
- const char *text[] = { "on" };
+ const char *text[number];
DBG("");
+ if (number) {
+ memset(text, 0, number);
+ text[0] = "on";
+ }
+
avrcp_get_player_values_text_rsp(session, transaction, number,
values, text);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/avrcp-lib.c | 20 ++++++++++++++++++++
android/avrcp-lib.h | 3 +++
2 files changed, 23 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index c7d44b5..3fca571 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1729,3 +1729,23 @@ int avrcp_get_folder_items(struct avrcp *session, uint8_t scope,
return avctp_send_browsing_req(session->conn, buf, sizeof(buf),
func, user_data);
}
+
+int avrcp_change_path(struct avrcp *session, uint8_t direction, uint64_t uid,
+ uint16_t counter, avctp_browsing_rsp_cb func,
+ void *user_data)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 11];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_CHANGE_PATH;
+ pdu->param_len = htons(11);
+
+ bt_put_be16(counter, &pdu->params[0]);
+ pdu->params[2] = direction;
+ bt_put_be64(uid, &pdu->params[3]);
+
+ 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 1254f6c..4399553 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -287,3 +287,6 @@ int avrcp_get_folder_items(struct avrcp *session, uint8_t scope,
uint32_t start, uint32_t end, uint32_t *attr,
size_t attr_count, avctp_browsing_rsp_cb func,
void *user_data);
+int avrcp_change_path(struct avrcp *session, uint8_t direction, uint64_t uid,
+ uint16_t counter, avctp_browsing_rsp_cb func,
+ void *user_data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Test verifies that Controller is able to request the list of available
Media Players.
---
unit/test-avrcp.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index f4aaaab..6eb2413 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -583,6 +583,11 @@ static void test_client(gconstpointer data)
AVRCP_MEDIA_PLAYER_LIST, 0, 2, NULL, 0,
NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-01-I"))
+ 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);
@@ -668,6 +673,16 @@ int main(int argc, char *argv[])
0x00, 0x00, 0x00, 0x02, /* end */
0x00));
+ /* Media Player Selection IOP tests */
+
+ /* Listing of available media players */
+ define_test("/TP/MPS/BV-01-I", 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 the ChangePath command 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 1bf54df..733aff4 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -593,6 +593,10 @@ static void test_client(gconstpointer data)
AVRCP_MEDIA_PLAYER_VFS, 0, 2, NULL, 0,
NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MCN/CB/BV-04-C"))
+ avrcp_change_path(context->session, 0x01, 0x01, 0xaabb,
+ NULL, NULL);
+
if (g_str_equal(context->data->test_name, "/TP/CFG/BV-01-C"))
avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED);
@@ -691,6 +695,15 @@ int main(int argc, char *argv[])
0x00, 0x00, 0x00, 0x02, /* end */
0x00));
+ /* ChangePath - CT */
+ define_test("/TP/MCN/CB/BV-04-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, AVRCP_CHANGE_PATH,
+ 0x00, 0x0b,
+ 0xaa, 0xbb, /* counter */
+ 0x01, /* direction */
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01 /* Folder UID */));
+
/* Media Player Selection IOP tests */
/* Listing of available media players */
--
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 858f5a0..f4aaaab 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -578,6 +578,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);
@@ -655,6 +660,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 the GetFolderItems command issued by the Controller
with VFS parameter.
---
unit/test-avrcp.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index a8a5c16..1bf54df 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -588,6 +588,11 @@ static void test_client(gconstpointer data)
AVRCP_MEDIA_PLAYER_LIST, 0, 2, NULL, 0,
NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MCN/CB/BV-01-C"))
+ avrcp_get_folder_items(context->session,
+ AVRCP_MEDIA_PLAYER_VFS, 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);
@@ -673,6 +678,19 @@ int main(int argc, char *argv[])
0x00, 0x00, 0x00, 0x02, /* end */
0x00));
+ /*
+ * Media Content Navigation Commands and Notifications for Content
+ * Browsing.
+ */
+
+ /* GetFolderItems - Virtual FS - CT */
+ define_test("/TP/MCN/CB/BV-01-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, AVRCP_GET_FOLDER_ITEMS,
+ 0x00, 0x0a, AVRCP_MEDIA_PLAYER_VFS,
+ 0x00, 0x00, 0x00, 0x00, /* start */
+ 0x00, 0x00, 0x00, 0x02, /* end */
+ 0x00));
+
/* Media Player Selection IOP tests */
/* Listing of available media players */
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/avrcp-lib.c | 23 +++++++++++++++++++++--
android/avrcp-lib.h | 4 ++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 5f7a626..28c2445 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -28,6 +28,7 @@
#include <stdbool.h>
#include <glib.h>
#include <errno.h>
+#include <string.h>
#include "lib/bluetooth.h"
@@ -44,8 +45,6 @@
#define AVRCP_PACKET_TYPE_CONTINUING 0x02
#define AVRCP_PACKET_TYPE_END 0x03
-#define AVRCP_CHARSET_UTF8 106
-
#if __BYTE_ORDER == __LITTLE_ENDIAN
struct avrcp_header {
@@ -1777,3 +1776,23 @@ int avrcp_get_item_attributes(struct avrcp *session, uint8_t scope,
return avctp_send_browsing_req(session->conn, buf, sizeof(buf),
func, user_data);
}
+
+int avrcp_search(struct avrcp *session, uint16_t charset, const char *string,
+ avctp_browsing_rsp_cb func, void *user_data)
+{
+ size_t str_len = strnlen(string, 255 - 4);
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + str_len + 4];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_SEARCH;
+ pdu->param_len = htons(str_len + 4);
+
+ bt_put_be16(charset, &pdu->params[0]);
+ bt_put_be16(str_len, &pdu->params[2]);
+ memcpy(&pdu->params[4], string, str_len);
+
+ 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 a6b10de..9470857 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -124,6 +124,8 @@
/* Company IDs for vendor dependent commands */
#define IEEEID_BTSIG 0x001958
+#define AVRCP_CHARSET_UTF8 0x006a
+
/* Parameters legths */
#define AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH 5
@@ -294,3 +296,5 @@ int avrcp_get_item_attributes(struct avrcp *session, uint8_t scope,
uint64_t uid, uint16_t counter, uint32_t *attr,
size_t attr_count, avctp_browsing_rsp_cb func,
void *user_data);
+int avrcp_search(struct avrcp *session, uint16_t charset, const char *string,
+ avctp_browsing_rsp_cb func, void *user_data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Tests are checking connection establishment and release for browsing
channel. Since we are connected through socketpair the tests are dummy.
---
unit/test-avrcp.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 6eb2413..a8a5c16 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -683,6 +683,19 @@ int main(int argc, char *argv[])
0x00, 0x00, 0x00, 0x02, /* end */
0x00));
+ /* Connection Establishment for Browsing tests */
+
+ /*
+ * Tests are checking connection establishment and release
+ * for browsing channel. Since we are connected through socketpair
+ * the tests are dummy
+ */
+ define_test("/TP/CON/BV-01-C", test_dummy, raw_pdu(0x00));
+ define_test("/TP/CON/BV-02-C", test_dummy, raw_pdu(0x00));
+ define_test("/TP/CON/BV-03-C", test_dummy, raw_pdu(0x00));
+ define_test("/TP/CON/BV-04-C", test_dummy, raw_pdu(0x00));
+ define_test("/TP/CON/BV-05-C", test_dummy, raw_pdu(0x00));
+
/* 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 393ab54..42e00de 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1682,3 +1682,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 ca7a57f..ed26220 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -121,6 +121,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 {
@@ -268,3 +275,5 @@ int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
int avrcp_set_addressed_player_rsp(struct avrcp *session, uint8_t transaction,
uint8_t status);
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]>
---
android/avrcp-lib.c | 29 +++++++++++++++++++++++++++++
android/avrcp-lib.h | 10 ++++++++++
2 files changed, 39 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 48c5221..c7d44b5 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1700,3 +1700,32 @@ 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, uint32_t *attr,
+ size_t attr_count, avctp_browsing_rsp_cb func,
+ void *user_data)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 10 +
+ attr_count * sizeof(uint32_t)];
+ 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 * sizeof(uint32_t));
+
+ /* 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 ed26220..1254f6c 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -115,6 +115,12 @@
#define AVRCP_MEDIA_ATTRIBUTE_DURATION 0x07
#define AVRCP_MEDIA_ATTRIBUTE_LAST AVRCP_MEDIA_ATTRIBUTE_DURATION
+/* 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
@@ -277,3 +283,7 @@ int avrcp_set_addressed_player_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, uint32_t *attr,
+ size_t attr_count, avctp_browsing_rsp_cb func,
+ void *user_data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Check len before memcpy(). Fixes:
...
android/avrcp-lib.c:885:3: warning: Null pointer passed as an argument
to a 'nonnull' parameter
memcpy(&ptr[4], text[i], len);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
---
android/avrcp-lib.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 28c2445..e99653c 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1543,7 +1543,10 @@ int avrcp_get_player_attribute_text_rsp(struct avrcp *session,
ptr[0] = attrs[i];
put_be16(AVRCP_CHARSET_UTF8, &ptr[1]);
ptr[3] = len;
- memcpy(&ptr[4], text[i], len);
+
+ if (len)
+ memcpy(&ptr[4], text[i], len);
+
ptr += 4 + len;
length += 4 + len;
}
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Test verifies that GetFolderItems is issued with parameter
AVRCP_MEDIA_SEARCH.
---
unit/test-avrcp.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 00fdaff..d901523 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -611,6 +611,10 @@ static void test_client(gconstpointer data)
avrcp_search(context->session, AVRCP_CHARSET_UTF8, "Country",
NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MCN/SRC/BV-03-C"))
+ avrcp_get_folder_items(context->session, AVRCP_MEDIA_SEARCH,
+ 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);
@@ -736,6 +740,13 @@ int main(int argc, char *argv[])
0x00, 0x07,
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79));
+ /* GetFolderItems - CT */
+ define_test("/TP/MCN/SRC/BV-03-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, AVRCP_GET_FOLDER_ITEMS,
+ 0x00, 0x0a, AVRCP_MEDIA_SEARCH,
+ 0x00, 0x00, 0x00, 0x00, /* start */
+ 0x00, 0x00, 0x00, 0x02, /* end */
+ 0x00));
/* Media Player Selection IOP tests */
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/avrcp-lib.c | 28 ++++++++++++++++++++++++++++
android/avrcp-lib.h | 4 ++++
2 files changed, 32 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 3fca571..5f7a626 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1749,3 +1749,31 @@ int avrcp_change_path(struct avrcp *session, uint8_t direction, uint64_t uid,
return avctp_send_browsing_req(session->conn, buf, sizeof(buf),
func, user_data);
}
+
+int avrcp_get_item_attributes(struct avrcp *session, uint8_t scope,
+ uint64_t uid, uint16_t counter, uint32_t *attr,
+ size_t attr_count, avctp_browsing_rsp_cb func,
+ void *user_data)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 12 +
+ attr_count * sizeof(uint32_t)];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_GET_ITEM_ATTRIBUTES;
+ pdu->param_len = htons(12 + attr_count * sizeof(uint32_t));
+
+ /* Scope */
+ pdu->params[0] = scope;
+
+ bt_put_be64(uid, &pdu->params[1]);
+ bt_put_be16(counter, &pdu->params[9]);
+
+ pdu->params[11] = attr_count;
+
+ memcpy(&pdu->params[12], attr, attr_count * sizeof(uint32_t));
+
+ 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 4399553..a6b10de 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -290,3 +290,7 @@ int avrcp_get_folder_items(struct avrcp *session, uint8_t scope,
int avrcp_change_path(struct avrcp *session, uint8_t direction, uint64_t uid,
uint16_t counter, avctp_browsing_rsp_cb func,
void *user_data);
+int avrcp_get_item_attributes(struct avrcp *session, uint8_t scope,
+ uint64_t uid, uint16_t counter, uint32_t *attr,
+ size_t attr_count, avctp_browsing_rsp_cb func,
+ void *user_data);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Test verifies that GetItemAttributes command issued by the Controller on
a Media Item in the Search folder.
---
unit/test-avrcp.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index d901523..d02cd2d 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -615,6 +615,11 @@ static void test_client(gconstpointer data)
avrcp_get_folder_items(context->session, AVRCP_MEDIA_SEARCH,
0, 2, NULL, 0, NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MCN/SRC/BV-05-C"))
+ avrcp_get_item_attributes(context->session,
+ AVRCP_MEDIA_SEARCH, 0x01, 0xaabb,
+ 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);
@@ -748,6 +753,15 @@ int main(int argc, char *argv[])
0x00, 0x00, 0x00, 0x02, /* end */
0x00));
+ /* GetItemAttributes - CT */
+ define_test("/TP/MCN/SRC/BV-05-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, AVRCP_GET_ITEM_ATTRIBUTES,
+ 0x00, 0x0c, AVRCP_MEDIA_SEARCH,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, /* uuid */
+ 0xaa, 0xbb, /* counter */
+ 0x00)); /* num attr */
+
/* Media Player Selection IOP tests */
/* Listing of available media players */
--
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 32b48b9..858f5a0 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -575,6 +575,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);
@@ -647,6 +650,11 @@ int main(int argc, char *argv[])
AVRCP_SET_ADDRESSED_PLAYER,
0x00, 0x00, 0x01, 0x04));
+ /* 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]>
---
.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 5b259bd..32b48b9 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]>
Test verifies that Search command issued by the Controller.
---
unit/test-avrcp.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 9005e4e..fdca98f 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -602,6 +602,10 @@ static void test_client(gconstpointer data)
AVRCP_MEDIA_PLAYER_VFS, 0x01, 0xaabb,
NULL, 0, NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/MCN/SRC/BV-01-C"))
+ avrcp_search(context->session, AVRCP_CHARSET_UTF8, "Country",
+ NULL, NULL);
+
if (g_str_equal(context->data->test_name, "/TP/CFG/BV-01-C"))
avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED);
@@ -718,6 +722,16 @@ int main(int argc, char *argv[])
0xaa, 0xbb, /* counter */
0x00)); /* num attr */
+ /* Media Content Navigation Commands and Notifications for Search */
+
+ /* Search - CT */
+ define_test("/TP/MCN/SRC/BV-01-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, AVRCP_SEARCH,
+ 0x00, 0x0b, 0x00, AVRCP_CHARSET_UTF8,
+ 0x00, 0x07,
+ 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79));
+
+
/* Media Player Selection IOP tests */
/* Listing of available media players */
--
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 42e00de..48c5221 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -908,7 +908,7 @@ done:
int avrcp_register_notification(struct avrcp *session, uint8_t event,
uint32_t interval)
{
- uint8_t params[5];
+ uint8_t params[AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH];
params[0] = event;
put_be32(interval, ¶ms[1]);
--
1.8.3.2
On Wed, Apr 02, 2014 at 03:37:32PM +0300, Andrei Emeltchenko wrote:
> Hi Luiz,
>
> On Wed, Apr 02, 2014 at 02:30:18PM +0300, Luiz Augusto von Dentz wrote:
> > Hi Andrei,
> >
> > On Mon, Mar 31, 2014 at 3:24 PM, Andrei Emeltchenko
> > <[email protected]> wrote:
> > > 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 1a2fa2a..393ab54 100644
> > > --- a/android/avrcp-lib.c
> > > +++ b/android/avrcp-lib.c
> > > @@ -293,6 +293,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 0b867aa..ca7a57f 100644
> > > --- a/android/avrcp-lib.h
> > > +++ b/android/avrcp-lib.h
> > > @@ -207,6 +207,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_register_player(struct avrcp *session,
> > > const struct avrcp_control_ind *ind,
> > > --
> > > 1.8.3.2
> >
> > This patch-set is now upstream, Ive end up redoing much of the API
> > though since it was not using the callback mechanism.
>
> Have you applied the last patch?
Sorry, my wrong rebase.
Best regards
Andrei Emeltchenko
>
> Best regards
> Andrei Emeltchenko
>
> --
> 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
Hi Luiz,
On Wed, Apr 02, 2014 at 02:30:18PM +0300, Luiz Augusto von Dentz wrote:
> Hi Andrei,
>
> On Mon, Mar 31, 2014 at 3:24 PM, Andrei Emeltchenko
> <[email protected]> wrote:
> > 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 1a2fa2a..393ab54 100644
> > --- a/android/avrcp-lib.c
> > +++ b/android/avrcp-lib.c
> > @@ -293,6 +293,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 0b867aa..ca7a57f 100644
> > --- a/android/avrcp-lib.h
> > +++ b/android/avrcp-lib.h
> > @@ -207,6 +207,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_register_player(struct avrcp *session,
> > const struct avrcp_control_ind *ind,
> > --
> > 1.8.3.2
>
> This patch-set is now upstream, Ive end up redoing much of the API
> though since it was not using the callback mechanism.
Have you applied the last patch?
Best regards
Andrei Emeltchenko
Hi Andrei,
On Mon, Mar 31, 2014 at 3:24 PM, Andrei Emeltchenko
<[email protected]> wrote:
> 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 1a2fa2a..393ab54 100644
> --- a/android/avrcp-lib.c
> +++ b/android/avrcp-lib.c
> @@ -293,6 +293,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 0b867aa..ca7a57f 100644
> --- a/android/avrcp-lib.h
> +++ b/android/avrcp-lib.h
> @@ -207,6 +207,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_register_player(struct avrcp *session,
> const struct avrcp_control_ind *ind,
> --
> 1.8.3.2
This patch-set is now upstream, Ive end up redoing much of the API
though since it was not using the callback mechanism.
--
Luiz Augusto von Dentz