Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response
@ 2014-03-26 14:13 Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 02/12] android/avrcp-lib: Add support for parsing ListPlayerAttributes response Luiz Augusto von Dentz
                   ` (11 more replies)
  0 siblings, 12 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++------
 android/avrcp-lib.h |   6 ++-
 android/avrcp.c     |  40 ++++++++--------
 unit/test-avrcp.c   |   3 +-
 4 files changed, 138 insertions(+), 39 deletions(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index c7b8b6a..2128835 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -135,6 +135,27 @@ void avrcp_shutdown(struct avrcp *session)
 	g_free(session);
 }
 
+static struct avrcp_header *parse_pdu(uint8_t *operands, size_t operand_count)
+{
+	struct avrcp_header *pdu;
+
+	if (operands == NULL || operand_count < sizeof(*pdu)) {
+		error("AVRCP: packet too smal (%zu bytes)", operand_count);
+		return NULL;
+	}
+
+	pdu = (void *) operands;
+	pdu->params_len = ntohs(pdu->params_len);
+
+	if (operand_count != pdu->params_len + sizeof(*pdu)) {
+		error("AVRCP: invalid parameter length (%u bytes)",
+							pdu->params_len);
+		return NULL;
+	}
+
+	return pdu;
+}
+
 static ssize_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
 					uint8_t *code, uint8_t *subunit,
 					uint8_t *operands, size_t operand_count,
@@ -142,26 +163,27 @@ static ssize_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
 {
 	struct avrcp *session = user_data;
 	const struct avrcp_control_handler *handler;
-	struct avrcp_header *pdu = (void *) operands;
-	uint32_t company_id = ntoh24(pdu->company_id);
-	uint16_t params_len = ntohs(pdu->params_len);
+	struct avrcp_header *pdu;
+	uint32_t company_id;
 	ssize_t ret;
 
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		pdu->params[0] = AVRCP_STATUS_INVALID_COMMAND;
+		goto reject;
+	}
+
+	company_id = ntoh24(pdu->company_id);
 	if (company_id != IEEEID_BTSIG) {
 		*code = AVC_CTYPE_NOT_IMPLEMENTED;
 		return 0;
 	}
 
-	DBG("AVRCP PDU 0x%02X, len 0x%04X", pdu->pdu_id, params_len);
+	DBG("AVRCP PDU 0x%02X, len 0x%04X", pdu->pdu_id, pdu->params_len);
 
 	pdu->packet_type = 0;
 	pdu->rsvd = 0;
 
-	if (operand_count < AVRCP_HEADER_LENGTH) {
-		pdu->params[0] = AVRCP_STATUS_INVALID_COMMAND;
-		goto reject;
-	}
-
 	if (!session->control_handlers)
 		goto reject;
 
@@ -180,7 +202,7 @@ static ssize_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
 		goto reject;
 	}
 
-	ret = handler->func(session, transaction, params_len, pdu->params,
+	ret = handler->func(session, transaction, pdu->params_len, pdu->params,
 							session->control_data);
 	if (ret < 0) {
 		switch (ret) {
@@ -670,6 +692,31 @@ int avrcp_send(struct avrcp *session, uint8_t transaction, uint8_t code,
 							session->tx_buf, len);
 }
 
+static int parse_status(struct avrcp_header *pdu)
+{
+	if (pdu->params_len < 1)
+		return -EPROTO;
+
+	switch (pdu->params[0]) {
+	case AVRCP_STATUS_INVALID_COMMAND:
+		return -ENOSYS;
+	case AVRCP_STATUS_INVALID_PARAM:
+		return -EINVAL;
+	case AVRCP_STATUS_SUCCESS:
+		return 0;
+	case AVRCP_STATUS_OUT_OF_BOUNDS:
+		return -EOVERFLOW;
+	case AVRCP_STATUS_INTERNAL_ERROR:
+	case AVRCP_STATUS_INVALID_PLAYER_ID:
+	case AVRCP_STATUS_PLAYER_NOT_BROWSABLE:
+	case AVRCP_STATUS_NO_AVAILABLE_PLAYERS:
+	case AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED:
+		return -EPERM;
+	default:
+		return -EPROTO;
+	}
+}
+
 static int avrcp_send_req(struct avrcp *session, uint8_t code, uint8_t subunit,
 					uint8_t pdu_id, uint8_t *params,
 					size_t params_len, avctp_rsp_cb func,
@@ -698,12 +745,67 @@ static int avrcp_send_req(struct avrcp *session, uint8_t code, uint8_t subunit,
 					session->tx_buf, len, func, user_data);
 }
 
-int avrcp_get_capabilities(struct avrcp *session, uint8_t param,
-					avctp_rsp_cb func, void *user_data)
+static gboolean get_capabilities_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
+					void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu;
+	uint8_t number = 0;
+	uint8_t *params = NULL;
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->get_capabilities)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	if (pdu->params_len < 2) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	switch (pdu->params[0]) {
+	case CAP_COMPANY_ID:
+	case CAP_EVENTS_SUPPORTED:
+		break;
+	default:
+		err = -EPROTO;
+		goto done;
+	}
+
+	number = pdu->params[1];
+
+	if (number > 0)
+		params = &pdu->params[2];
+
+	err = 0;
+
+done:
+	player->cfm->get_capabilities(session, err, number, params,
+							player->user_data);
+
+	return FALSE;
+}
+
+int avrcp_get_capabilities(struct avrcp *session, uint8_t param)
 {
 	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
 				AVRCP_GET_CAPABILITIES, &param, sizeof(param),
-				func, user_data);
+				get_capabilities_rsp, session);
 }
 
 int avrcp_register_notification(struct avrcp *session, uint8_t event,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index d9acb7d..ab110cb 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -164,6 +164,9 @@ struct avrcp_control_ind {
 };
 
 struct avrcp_control_cfm {
+	void (*get_capabilities) (struct avrcp *session, int err,
+					uint8_t number, uint8_t *params,
+					void *user_data);
 };
 
 struct avrcp_passthrough_handler {
@@ -190,8 +193,7 @@ int avrcp_init_uinput(struct avrcp *session, const char *name,
 int avrcp_send(struct avrcp *session, uint8_t transaction, uint8_t code,
 					uint8_t subunit, uint8_t pdu_id,
 					uint8_t *params, size_t params_len);
-int avrcp_get_capabilities(struct avrcp *session, uint8_t param,
-					avctp_rsp_cb func, void *user_data);
+int avrcp_get_capabilities(struct avrcp *session, uint8_t param);
 int avrcp_register_notification(struct avrcp *session, uint8_t event,
 					uint32_t interval, avctp_rsp_cb func,
 					void *user_data);
diff --git a/android/avrcp.c b/android/avrcp.c
index ec98139..0995a06 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -759,38 +759,35 @@ static gboolean register_notification_rsp(struct avctp *conn,
 	return FALSE;
 }
 
-static gboolean get_capabilities_rsp(struct avctp *conn,
-					uint8_t code, uint8_t subunit,
-					uint8_t *operands, size_t operand_count,
+static void handle_get_capabilities_rsp(struct avrcp *session, int err,
+					uint8_t number, uint8_t *events,
 					void *user_data)
 {
 	struct avrcp_device *dev = user_data;
-	uint8_t *params;
-	uint8_t count;
-
-	if (operands == NULL || operand_count < 7)
-		return FALSE;
-
-	params = &operands[7];
-
-	if (params == NULL || params[0] != CAP_EVENTS_SUPPORTED)
-		return FALSE;
+	int i;
 
-	for (count = params[1]; count > 0; count--) {
-		uint8_t event = params[1 + count];
+	if (err < 0) {
+		error("AVRCP: %s", strerror(-err));
+		return;
+	}
 
-		if (event != AVRCP_EVENT_VOLUME_CHANGED)
+	for (i = 0; i < number; i++) {
+		if (events[i] != AVRCP_EVENT_VOLUME_CHANGED)
 			continue;
 
-		avrcp_register_notification(dev->session, event, 0,
+		avrcp_register_notification(dev->session, events[i], 0,
 						register_notification_rsp,
 						dev);
-		return FALSE;
+		break;
 	}
 
-	return FALSE;
+	return;
 }
 
+static const struct avrcp_control_cfm control_cfm = {
+	.get_capabilities = handle_get_capabilities_rsp,
+};
+
 static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
 						uint16_t imtu, uint16_t omtu)
 {
@@ -804,7 +801,7 @@ static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
 	avrcp_set_destroy_cb(dev->session, disconnect_cb, dev);
 	avrcp_set_passthrough_handlers(dev->session, passthrough_handlers,
 									dev);
-	avrcp_register_player(dev->session, &control_ind, NULL, dev);
+	avrcp_register_player(dev->session, &control_ind, &control_cfm, dev);
 
 	dev->queue = g_queue_new();
 
@@ -828,8 +825,7 @@ static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
 
 	ev.features |= HAL_AVRCP_FEATURE_ABSOLUTE_VOLUME;
 
-	avrcp_get_capabilities(dev->session, CAP_EVENTS_SUPPORTED,
-						get_capabilities_rsp, dev);
+	avrcp_get_capabilities(dev->session, CAP_EVENTS_SUPPORTED);
 
 done:
 	ipc_send_notif(hal_ipc, HAL_SERVICE_ID_AVRCP,
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index eb00238..d6be6a6 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -491,8 +491,7 @@ static void test_client(gconstpointer data)
 									NULL);
 
 	if (g_str_equal(context->data->test_name, "/TP/CFG/BV-01-C"))
-		avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED,
-								NULL, NULL);
+		avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED);
 
 	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-01-C"))
 		avrcp_list_player_attributes(context->session, NULL, NULL);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 02/12] android/avrcp-lib: Add support for parsing ListPlayerAttributes response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 03/12] android/avrcp-lib: Add support for parsing GetPlayerAttributeText response Luiz Augusto von Dentz
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 46 +++++++++++++++++++++++++++++++++++++++++++---
 android/avrcp-lib.h |  6 ++++--
 unit/test-avrcp.c   |  2 +-
 3 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 2128835..aca9241 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -823,12 +823,52 @@ int avrcp_register_notification(struct avrcp *session, uint8_t event,
 					func, user_data);
 }
 
-int avrcp_list_player_attributes(struct avrcp *session, avctp_rsp_cb func,
-								void *user_data)
+static gboolean list_attributes_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
+					void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu = (void *) operands;
+	uint8_t number = 0;
+	uint8_t *attrs = NULL;
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->list_attributes)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	number = pdu->params[0];
+	if (number > 0)
+		attrs = &pdu->params[1];
+
+	err = 0;
+
+done:
+	player->cfm->list_attributes(session, err, number, attrs,
+							player->user_data);
+
+	return FALSE;
+}
+
+int avrcp_list_player_attributes(struct avrcp *session)
 {
 	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
 				AVRCP_LIST_PLAYER_ATTRIBUTES, NULL, 0,
-				func, user_data);
+				list_attributes_rsp, session);
 }
 
 int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t *attributes,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index ab110cb..87397a3 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -167,6 +167,9 @@ struct avrcp_control_cfm {
 	void (*get_capabilities) (struct avrcp *session, int err,
 					uint8_t number, uint8_t *params,
 					void *user_data);
+	void (*list_attributes) (struct avrcp *session, int err,
+					uint8_t number, uint8_t *attrs,
+					void *user_data);
 };
 
 struct avrcp_passthrough_handler {
@@ -197,8 +200,7 @@ int avrcp_get_capabilities(struct avrcp *session, uint8_t param);
 int avrcp_register_notification(struct avrcp *session, uint8_t event,
 					uint32_t interval, avctp_rsp_cb func,
 					void *user_data);
-int avrcp_list_player_attributes(struct avrcp *session, avctp_rsp_cb func,
-							void *user_data);
+int avrcp_list_player_attributes(struct avrcp *session);
 int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t *attributes,
 					uint8_t attr_len, avctp_rsp_cb func,
 					void *user_data);
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index d6be6a6..88e457d 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -494,7 +494,7 @@ static void test_client(gconstpointer data)
 		avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED);
 
 	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-01-C"))
-		avrcp_list_player_attributes(context->session, NULL, NULL);
+		avrcp_list_player_attributes(context->session);
 
 	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-03-C"))
 		avrcp_get_player_attribute_text(context->session, NULL, 0,
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 03/12] android/avrcp-lib: Add support for parsing GetPlayerAttributeText response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 02/12] android/avrcp-lib: Add support for parsing ListPlayerAttributes response Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 04/12] android/avrcp-lib: Add avrcp_list_player_values Luiz Augusto von Dentz
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 android/avrcp-lib.h |  8 +++--
 unit/test-avrcp.c   |  3 +-
 3 files changed, 100 insertions(+), 9 deletions(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index aca9241..f394276 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -871,13 +871,103 @@ int avrcp_list_player_attributes(struct avrcp *session)
 				list_attributes_rsp, session);
 }
 
-int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t *attributes,
-					uint8_t attr_len, avctp_rsp_cb func,
+static int parse_text_rsp(struct avrcp_header *pdu, uint8_t *number,
+					uint8_t *attrs, char **text)
+{
+	uint8_t *ptr;
+	uint16_t params_len;
+	int i;
+
+	if (pdu->params_len < 1)
+		return -EPROTO;
+
+	*number = pdu->params[0];
+	if (*number > AVRCP_ATTRIBUTE_LAST) {
+		*number = 0;
+		return -EPROTO;
+	}
+
+	params_len = pdu->params_len - 1;
+	for (i = 0, ptr = &pdu->params[1]; i < *number && params_len > 0; i++) {
+		uint8_t len;
+
+		if (params_len < 4)
+			goto fail;
+
+		attrs[i] = ptr[0];
+		len = ptr[3];
+
+		params_len -= 4;
+		ptr += 4;
+
+		if (len > params_len)
+			goto fail;
+
+		if (len > 0) {
+			text[i] = g_strndup((const char *) &ptr[4], len);
+			params_len -= len;
+			ptr += len;
+		}
+	}
+
+	if (i != *number)
+		goto fail;
+
+	return 0;
+
+fail:
+	for (i -= 1; i >= 0; i--)
+		g_free(text[i]);
+
+	*number = 0;
+
+	return -EPROTO;
+}
+
+static gboolean get_attribute_text_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
 					void *user_data)
 {
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu;
+	uint8_t number = 0;
+	uint8_t attrs[AVRCP_ATTRIBUTE_LAST];
+	char *text[AVRCP_ATTRIBUTE_LAST];
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->get_attribute_text)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	err = parse_text_rsp(pdu, &number, attrs, text);
+
+done:
+	player->cfm->get_attribute_text(session, err, number, attrs, text,
+							player->user_data);
+
+	return FALSE;
+}
+
+int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t number,
+								uint8_t *attrs)
+{
 	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
-				AVRCP_GET_PLAYER_ATTRIBUTE_TEXT, attributes,
-				attr_len, func, user_data);
+				AVRCP_GET_PLAYER_ATTRIBUTE_TEXT, attrs, number,
+				get_attribute_text_rsp, session);
 }
 
 int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 87397a3..9ed172e 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -170,6 +170,9 @@ struct avrcp_control_cfm {
 	void (*list_attributes) (struct avrcp *session, int err,
 					uint8_t number, uint8_t *attrs,
 					void *user_data);
+	void (*get_attribute_text) (struct avrcp *session, int err,
+					uint8_t number, uint8_t *attrs,
+					char **text, void *user_data);
 };
 
 struct avrcp_passthrough_handler {
@@ -201,9 +204,8 @@ int avrcp_register_notification(struct avrcp *session, uint8_t event,
 					uint32_t interval, avctp_rsp_cb func,
 					void *user_data);
 int avrcp_list_player_attributes(struct avrcp *session);
-int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t *attributes,
-					uint8_t attr_len, avctp_rsp_cb func,
-					void *user_data);
+int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t number,
+							uint8_t *attrs);
 int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
 					uint8_t attr_count, uint8_t *values,
 					avctp_rsp_cb func, void *user_data);
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 88e457d..fe1d51f 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -497,8 +497,7 @@ static void test_client(gconstpointer data)
 		avrcp_list_player_attributes(context->session);
 
 	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-03-C"))
-		avrcp_get_player_attribute_text(context->session, NULL, 0,
-								NULL, NULL);
+		avrcp_get_player_attribute_text(context->session, 0, NULL);
 
 	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-09-C")) {
 		uint8_t attributes[2] = { AVRCP_ATTRIBUTE_EQUALIZER,
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 04/12] android/avrcp-lib: Add avrcp_list_player_values
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 02/12] android/avrcp-lib: Add support for parsing ListPlayerAttributes response Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 03/12] android/avrcp-lib: Add support for parsing GetPlayerAttributeText response Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 05/12] android/avrcp-lib: Add support for parsing ListPlayerValues response Luiz Augusto von Dentz
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This function can be used to send ListPlayerValues command PDUs.
---
 android/avrcp-lib.c | 7 +++++++
 android/avrcp-lib.h | 1 +
 2 files changed, 8 insertions(+)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index f394276..5178174 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -970,6 +970,13 @@ int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t number,
 				get_attribute_text_rsp, session);
 }
 
+int avrcp_list_player_values(struct avrcp *session, uint8_t attr)
+{
+	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
+				AVRCP_LIST_PLAYER_VALUES, &attr, sizeof(attr),
+				NULL, NULL);
+}
+
 int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
 					uint8_t attr_count, avctp_rsp_cb func,
 					void *user_data)
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 9ed172e..4a61948 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -206,6 +206,7 @@ int avrcp_register_notification(struct avrcp *session, uint8_t event,
 int avrcp_list_player_attributes(struct avrcp *session);
 int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t number,
 							uint8_t *attrs);
+int avrcp_list_player_values(struct avrcp *session, uint8_t attr);
 int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
 					uint8_t attr_count, uint8_t *values,
 					avctp_rsp_cb func, void *user_data);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 05/12] android/avrcp-lib: Add support for parsing ListPlayerValues response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2014-03-26 14:13 ` [PATCH BlueZ 04/12] android/avrcp-lib: Add avrcp_list_player_values Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 06/12] android/avrcp-lib: Add avrcp_get_player_value_text Luiz Augusto von Dentz
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 android/avrcp-lib.h |  3 +++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 5178174..43037dd 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -970,11 +970,52 @@ int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t number,
 				get_attribute_text_rsp, session);
 }
 
+static gboolean list_values_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
+					void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu;
+	uint8_t number = 0;
+	uint8_t *values = NULL;
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->list_values)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	number = pdu->params[0];
+	if (number > 0)
+		values = &pdu->params[1];
+
+	err = 0;
+
+done:
+	player->cfm->list_values(session, err, number, values,
+							player->user_data);
+
+	return FALSE;
+}
+
 int avrcp_list_player_values(struct avrcp *session, uint8_t attr)
 {
 	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
 				AVRCP_LIST_PLAYER_VALUES, &attr, sizeof(attr),
-				NULL, NULL);
+				list_values_rsp, session);
 }
 
 int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 4a61948..5cbbed5 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -173,6 +173,9 @@ struct avrcp_control_cfm {
 	void (*get_attribute_text) (struct avrcp *session, int err,
 					uint8_t number, uint8_t *attrs,
 					char **text, void *user_data);
+	void (*list_values) (struct avrcp *session, int err,
+					uint8_t number, uint8_t *values,
+					void *user_data);
 };
 
 struct avrcp_passthrough_handler {
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 06/12] android/avrcp-lib: Add avrcp_get_player_value_text
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2014-03-26 14:13 ` [PATCH BlueZ 05/12] android/avrcp-lib: Add support for parsing ListPlayerValues response Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 07/12] android/avrcp-lib: Add support for parsing GetPlayerValueText response Luiz Augusto von Dentz
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This function can be used to send GetPlayerValueText command PDUs.
---
 android/avrcp-lib.c | 8 ++++++++
 android/avrcp-lib.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 43037dd..c901656 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1018,6 +1018,14 @@ int avrcp_list_player_values(struct avrcp *session, uint8_t attr)
 				list_values_rsp, session);
 }
 
+int avrcp_get_player_value_text(struct avrcp *session, uint8_t attr,
+					uint8_t number, uint8_t *values)
+{
+	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
+				AVRCP_GET_PLAYER_VALUE_TEXT, &attr,
+				sizeof(attr), NULL, NULL);
+}
+
 int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
 					uint8_t attr_count, avctp_rsp_cb func,
 					void *user_data)
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 5cbbed5..fea4f95 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -210,6 +210,8 @@ int avrcp_list_player_attributes(struct avrcp *session);
 int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t number,
 							uint8_t *attrs);
 int avrcp_list_player_values(struct avrcp *session, uint8_t attr);
+int avrcp_get_player_value_text(struct avrcp *session, uint8_t attr,
+					uint8_t number, uint8_t *values);
 int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
 					uint8_t attr_count, uint8_t *values,
 					avctp_rsp_cb func, void *user_data);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 07/12] android/avrcp-lib: Add support for parsing GetPlayerValueText response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2014-03-26 14:13 ` [PATCH BlueZ 06/12] android/avrcp-lib: Add avrcp_get_player_value_text Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 08/12] android/avrcp-lib: Add support for parsing GetCurrentPlayerValue response Luiz Augusto von Dentz
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 40 +++++++++++++++++++++++++++++++++++++++-
 android/avrcp-lib.h |  3 +++
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index c901656..5f36738 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1018,12 +1018,50 @@ int avrcp_list_player_values(struct avrcp *session, uint8_t attr)
 				list_values_rsp, session);
 }
 
+static gboolean get_value_text_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
+					void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu;
+	uint8_t number = 0;
+	uint8_t values[AVRCP_ATTRIBUTE_LAST];
+	char *text[AVRCP_ATTRIBUTE_LAST];
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->get_value_text)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	err = parse_text_rsp(pdu, &number, values, text);
+
+done:
+	player->cfm->get_value_text(session, err, number, values, text,
+							player->user_data);
+
+	return FALSE;
+}
+
 int avrcp_get_player_value_text(struct avrcp *session, uint8_t attr,
 					uint8_t number, uint8_t *values)
 {
 	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
 				AVRCP_GET_PLAYER_VALUE_TEXT, &attr,
-				sizeof(attr), NULL, NULL);
+				sizeof(attr), get_value_text_rsp, session);
 }
 
 int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index fea4f95..0929155 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -176,6 +176,9 @@ struct avrcp_control_cfm {
 	void (*list_values) (struct avrcp *session, int err,
 					uint8_t number, uint8_t *values,
 					void *user_data);
+	void (*get_value_text) (struct avrcp *session, int err,
+					uint8_t number, uint8_t *values,
+					char **text, void *user_data);
 };
 
 struct avrcp_passthrough_handler {
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 08/12] android/avrcp-lib: Add support for parsing GetCurrentPlayerValue response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
                   ` (5 preceding siblings ...)
  2014-03-26 14:13 ` [PATCH BlueZ 07/12] android/avrcp-lib: Add support for parsing GetPlayerValueText response Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-27 15:01   ` Szymon Janc
  2014-03-26 14:13 ` [PATCH BlueZ 09/12] android/avrcp-lib: Add support for parsing SetPlayerValue response Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++-------
 android/avrcp-lib.h |  8 +++---
 unit/test-avrcp.c   |  6 ++---
 3 files changed, 77 insertions(+), 15 deletions(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 5f36738..2c8d0f5 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1064,24 +1064,84 @@ int avrcp_get_player_value_text(struct avrcp *session, uint8_t attr,
 				sizeof(attr), get_value_text_rsp, session);
 }
 
-int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
-					uint8_t attr_count, avctp_rsp_cb func,
+static int parse_value(struct avrcp_header *pdu, uint8_t *number,
+					uint8_t *attrs, uint8_t *values)
+{
+	int i;
+
+	*number = pdu->params[0];
+	if (*number > AVRCP_ATTRIBUTE_LAST ||
+					1 + *number * 2 != pdu->params_len) {
+		number = 0;
+		return -EPROTO;
+	}
+
+	for (i = 0; i < *number; i++) {
+		attrs[i] = pdu->params[i * 2 + 1];
+		values[i] = pdu->params[i * 2 + 2];
+	}
+
+	return 0;
+}
+
+static gboolean get_value_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
 					void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu = (void *) operands;
+	uint8_t number = 0;
+	uint8_t attrs[AVRCP_ATTRIBUTE_LAST];
+	uint8_t values[AVRCP_ATTRIBUTE_LAST];
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->get_value)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	err = parse_value(pdu, &number, attrs, values);
+
+done:
+	player->cfm->get_value(session, err, number, attrs, values,
+							player->user_data);
+
+	return FALSE;
+}
+
+int avrcp_get_current_player_value(struct avrcp *session, uint8_t number,
+							uint8_t *attrs)
 
 {
-	uint8_t buf[AVRCP_ATTRIBUTE_LAST + 1];
+	uint8_t pdu[AVRCP_ATTRIBUTE_LAST + 1];
 
-	if (attr_count > AVRCP_ATTRIBUTE_LAST)
+	if (number > AVRCP_ATTRIBUTE_LAST)
 		return -EINVAL;
 
-	if (attrs && attr_count) {
-		buf[0] = attr_count;
-		memcpy(buf + 1, attrs, attr_count);
+	if (number > 0) {
+		if (!attrs)
+			return -EINVAL;
+
+		pdu[0] = number;
+		memcpy(&pdu[1], attrs, number);
 	}
 
 	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
-				AVRCP_GET_CURRENT_PLAYER_VALUE, buf,
-				attr_count + 1, func, user_data);
+				AVRCP_GET_CURRENT_PLAYER_VALUE, pdu,
+				number + 1, get_value_rsp, session);
 }
 
 int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 0929155..30ceda0 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -179,6 +179,9 @@ struct avrcp_control_cfm {
 	void (*get_value_text) (struct avrcp *session, int err,
 					uint8_t number, uint8_t *values,
 					char **text, void *user_data);
+	void (*get_value) (struct avrcp *session, int err,
+					uint8_t number, uint8_t *attrs,
+					uint8_t *values, void *user_data);
 };
 
 struct avrcp_passthrough_handler {
@@ -218,9 +221,8 @@ int avrcp_get_player_value_text(struct avrcp *session, uint8_t attr,
 int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
 					uint8_t attr_count, uint8_t *values,
 					avctp_rsp_cb func, void *user_data);
-int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
-					uint8_t attr_count, avctp_rsp_cb func,
-					void *user_data);
+int avrcp_get_current_player_value(struct avrcp *session, uint8_t number,
+							uint8_t *attrs);
 int avrcp_get_play_status(struct avrcp *session, avctp_rsp_cb func,
 							void *user_data);
 int avrcp_set_volume(struct avrcp *session, uint8_t volume, avctp_rsp_cb func,
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index fe1d51f..016c80c 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -500,11 +500,11 @@ static void test_client(gconstpointer data)
 		avrcp_get_player_attribute_text(context->session, 0, NULL);
 
 	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-09-C")) {
-		uint8_t attributes[2] = { AVRCP_ATTRIBUTE_EQUALIZER,
+		uint8_t attrs[2] = { AVRCP_ATTRIBUTE_EQUALIZER,
 						AVRCP_ATTRIBUTE_REPEAT_MODE };
 
-		avrcp_get_current_player_value(context->session, attributes,
-						sizeof(attributes), NULL, NULL);
+		avrcp_get_current_player_value(context->session, sizeof(attrs),
+									attrs);
 	}
 
 	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-11-C")) {
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 09/12] android/avrcp-lib: Add support for parsing SetPlayerValue response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
                   ` (6 preceding siblings ...)
  2014-03-26 14:13 ` [PATCH BlueZ 08/12] android/avrcp-lib: Add support for parsing GetCurrentPlayerValue response Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 10/12] android/avrcp-lib: Add support for parsing GetPlayStatus response Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 59 +++++++++++++++++++++++++++++++++++++++++++----------
 android/avrcp-lib.h |  8 +++++---
 unit/test-avrcp.c   |  9 ++++----
 3 files changed, 57 insertions(+), 19 deletions(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 2c8d0f5..9ce0aa2 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1144,26 +1144,63 @@ int avrcp_get_current_player_value(struct avrcp *session, uint8_t number,
 				number + 1, get_value_rsp, session);
 }
 
-int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
-					uint8_t attr_count, uint8_t *values,
-					avctp_rsp_cb func, void *user_data)
+static gboolean set_value_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
+					void *user_data)
 {
-	uint8_t buf[2 * AVRCP_ATTRIBUTE_LAST + 1];
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu;
+	uint8_t number = 0;
+	uint8_t attrs[AVRCP_ATTRIBUTE_LAST];
+	uint8_t values[AVRCP_ATTRIBUTE_LAST];
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->set_value)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	err = parse_value(pdu, &number, attrs, values);
+
+done:
+	player->cfm->set_value(session, err, number, attrs, values,
+							player->user_data);
+
+	return FALSE;
+}
+
+int avrcp_set_player_value(struct avrcp *session, uint8_t number,
+					uint8_t *attrs, uint8_t *values)
+{
+	uint8_t pdu[2 * AVRCP_ATTRIBUTE_LAST + 1];
 	int i;
 
-	if (attr_count > AVRCP_ATTRIBUTE_LAST)
+	if (number > AVRCP_ATTRIBUTE_LAST)
 		return -EINVAL;
 
-	buf[0] = attr_count;
+	pdu[0] = number;
 
-	for (i = 0; i < attr_count; i++) {
-		buf[i * 2 + 1] = attributes[i];
-		buf[i * 2 + 2] = values[i];
+	for (i = 0; i < number; i++) {
+		pdu[i * 2 + 1] = attrs[i];
+		pdu[i * 2 + 2] = values[i];
 	}
 
 	return avrcp_send_req(session, AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL,
-				AVRCP_SET_PLAYER_VALUE, buf, 2 * attr_count + 1,
-				func, user_data);
+				AVRCP_SET_PLAYER_VALUE, pdu, 2 * number + 1,
+				set_value_rsp, session);
 }
 
 int avrcp_get_play_status(struct avrcp *session, avctp_rsp_cb func,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 30ceda0..2a65f16 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -182,6 +182,9 @@ struct avrcp_control_cfm {
 	void (*get_value) (struct avrcp *session, int err,
 					uint8_t number, uint8_t *attrs,
 					uint8_t *values, void *user_data);
+	void (*set_value) (struct avrcp *session, int err,
+					uint8_t number, uint8_t *attrs,
+					uint8_t *values, void *user_data);
 };
 
 struct avrcp_passthrough_handler {
@@ -218,9 +221,8 @@ int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t number,
 int avrcp_list_player_values(struct avrcp *session, uint8_t attr);
 int avrcp_get_player_value_text(struct avrcp *session, uint8_t attr,
 					uint8_t number, uint8_t *values);
-int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
-					uint8_t attr_count, uint8_t *values,
-					avctp_rsp_cb func, void *user_data);
+int avrcp_set_player_value(struct avrcp *session, uint8_t number,
+					uint8_t *attrs, uint8_t *values);
 int avrcp_get_current_player_value(struct avrcp *session, uint8_t number,
 							uint8_t *attrs);
 int avrcp_get_play_status(struct avrcp *session, avctp_rsp_cb func,
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 016c80c..8f74e9c 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -508,13 +508,12 @@ static void test_client(gconstpointer data)
 	}
 
 	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-11-C")) {
-		uint8_t attributes[2] = { AVRCP_ATTRIBUTE_EQUALIZER,
+		uint8_t attrs[2] = { AVRCP_ATTRIBUTE_EQUALIZER,
 						AVRCP_ATTRIBUTE_REPEAT_MODE };
-		uint8_t values[] = { 0xaa, 0xff };
+		uint8_t values[2] = { 0xaa, 0xff };
 
-		avrcp_set_player_value(context->session, attributes,
-						sizeof(attributes), values,
-						NULL, NULL);
+		avrcp_set_player_value(context->session, sizeof(attrs), attrs,
+								values);
 	}
 
 	if (g_str_equal(context->data->test_name, "/TP/MDI/BV-01-C"))
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 10/12] android/avrcp-lib: Add support for parsing GetPlayStatus response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
                   ` (7 preceding siblings ...)
  2014-03-26 14:13 ` [PATCH BlueZ 09/12] android/avrcp-lib: Add support for parsing SetPlayerValue response Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 11/12] android/avrcp-lib: Add support for parsing GetElementAttributes response Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++----
 android/avrcp-lib.h |  6 ++++--
 unit/test-avrcp.c   |  2 +-
 3 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 9ce0aa2..3412354 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1203,12 +1203,57 @@ int avrcp_set_player_value(struct avrcp *session, uint8_t number,
 				set_value_rsp, session);
 }
 
-int avrcp_get_play_status(struct avrcp *session, avctp_rsp_cb func,
-								void *user_data)
+static gboolean get_play_status_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
+					void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu;
+	uint8_t status = 0;
+	uint32_t position = 0;
+	uint32_t duration = 0;
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->get_play_status)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	if (pdu->params_len < 5) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	duration = bt_get_be32(&pdu->params[0]);
+	position = bt_get_be32(&pdu->params[4]);
+	status = pdu->params[8];
+	err = 0;
+
+done:
+	player->cfm->get_play_status(session, err, status, position, duration,
+							player->user_data);
+
+	return FALSE;
+}
+
+int avrcp_get_play_status(struct avrcp *session)
 {
 	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
-				AVRCP_GET_PLAY_STATUS, NULL, 0, func,
-				user_data);
+				AVRCP_GET_PLAY_STATUS, NULL, 0,
+				get_play_status_rsp, session);
 }
 
 int avrcp_set_volume(struct avrcp *session, uint8_t volume, avctp_rsp_cb func,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 2a65f16..f5666eb 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -185,6 +185,9 @@ struct avrcp_control_cfm {
 	void (*set_value) (struct avrcp *session, int err,
 					uint8_t number, uint8_t *attrs,
 					uint8_t *values, void *user_data);
+	void (*get_play_status) (struct avrcp *session, int err,
+					uint8_t status, uint32_t position,
+					uint32_t duration, void *user_data);
 };
 
 struct avrcp_passthrough_handler {
@@ -225,8 +228,7 @@ int avrcp_set_player_value(struct avrcp *session, uint8_t number,
 					uint8_t *attrs, uint8_t *values);
 int avrcp_get_current_player_value(struct avrcp *session, uint8_t number,
 							uint8_t *attrs);
-int avrcp_get_play_status(struct avrcp *session, avctp_rsp_cb func,
-							void *user_data);
+int avrcp_get_play_status(struct avrcp *session);
 int avrcp_set_volume(struct avrcp *session, uint8_t volume, avctp_rsp_cb func,
 							void *user_data);
 int avrcp_get_element_attributes(struct avrcp *session, avctp_rsp_cb func,
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 8f74e9c..ad15bb9 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -517,7 +517,7 @@ static void test_client(gconstpointer data)
 	}
 
 	if (g_str_equal(context->data->test_name, "/TP/MDI/BV-01-C"))
-		avrcp_get_play_status(context->session, NULL, NULL);
+		avrcp_get_play_status(context->session);
 
 	if (g_str_equal(context->data->test_name, "/TP/MDI/BV-03-C"))
 		avrcp_get_element_attributes(context->session, NULL, NULL);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 11/12] android/avrcp-lib: Add support for parsing GetElementAttributes response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
                   ` (8 preceding siblings ...)
  2014-03-26 14:13 ` [PATCH BlueZ 10/12] android/avrcp-lib: Add support for parsing GetPlayStatus response Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-26 14:13 ` [PATCH BlueZ 12/12] android/avrcp-lib: Add support for parsing RegisterNotification response Luiz Augusto von Dentz
  2014-03-27 14:55 ` [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Szymon Janc
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++----
 android/avrcp-lib.h |   6 ++--
 unit/test-avrcp.c   |   2 +-
 3 files changed, 101 insertions(+), 9 deletions(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 3412354..33717e0 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -1265,17 +1265,107 @@ int avrcp_set_volume(struct avrcp *session, uint8_t volume, avctp_rsp_cb func,
 						func, user_data);
 }
 
-int avrcp_get_element_attributes(struct avrcp *session, avctp_rsp_cb func,
-								void *user_data)
+static int parse_attribute_list(struct avrcp_header *pdu, uint8_t *number,
+						uint32_t *attrs, char **text)
 {
-	uint8_t buf[9];
+	uint8_t *ptr;
+	uint16_t params_len;
+	int i;
+
+	if (pdu->params_len < 1)
+		return -EPROTO;
+
+	*number = pdu->params[0];
+	if (*number > AVRCP_MEDIA_ATTRIBUTE_LAST) {
+		*number = 0;
+		return -EPROTO;
+	}
+
+	params_len = pdu->params_len - 1;
+	for (i = 0, ptr = &pdu->params[1]; i < *number && params_len > 0; i++) {
+		uint16_t len;
+
+		if (params_len < 8)
+			goto fail;
+
+		attrs[i] = bt_get_be32(&ptr[0]);
+		len = bt_get_be16(&ptr[6]);
+
+		params_len -= 8;
+		ptr += 8;
+
+		if (len > params_len)
+			goto fail;
+
+		if (len > 0) {
+			text[i] = g_strndup((const char *) &ptr[8], len);
+			params_len -= len;
+			ptr += len;
+		}
+	}
+
+	if (i != *number)
+		goto fail;
+
+	return 0;
+
+fail:
+	for (i -= 1; i >= 0; i--)
+		g_free(text[i]);
+
+	*number = 0;
+
+	return -EPROTO;
+}
+
+static gboolean get_element_attributes_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
+					void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu;
+	uint8_t number = 0;
+	uint32_t attrs[AVRCP_MEDIA_ATTRIBUTE_LAST];
+	char *text[AVRCP_MEDIA_ATTRIBUTE_LAST];
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->get_element_attributes)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	err = parse_attribute_list(pdu, &number, attrs, text);
+
+done:
+	player->cfm->get_element_attributes(session, err, number, attrs, text,
+							player->user_data);
+
+	return FALSE;
+}
+
+int avrcp_get_element_attributes(struct avrcp *session)
+{
+	uint8_t pdu[9];
 
 	/* This returns all attributes */
-	memset(buf, 0, sizeof(buf));
+	memset(pdu, 0, sizeof(pdu));
 
 	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
-				AVRCP_GET_ELEMENT_ATTRIBUTES, buf, sizeof(buf),
-				func, user_data);
+				AVRCP_GET_ELEMENT_ATTRIBUTES, pdu, sizeof(pdu),
+				get_element_attributes_rsp, session);
 }
 
 int avrcp_set_addressed_player(struct avrcp *session, uint16_t player_id,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index f5666eb..2f35e90 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -188,6 +188,9 @@ struct avrcp_control_cfm {
 	void (*get_play_status) (struct avrcp *session, int err,
 					uint8_t status, uint32_t position,
 					uint32_t duration, void *user_data);
+	void (*get_element_attributes) (struct avrcp *session, int err,
+					uint8_t number, uint32_t *attrs,
+					char **text, void *user_data);
 };
 
 struct avrcp_passthrough_handler {
@@ -231,8 +234,7 @@ int avrcp_get_current_player_value(struct avrcp *session, uint8_t number,
 int avrcp_get_play_status(struct avrcp *session);
 int avrcp_set_volume(struct avrcp *session, uint8_t volume, avctp_rsp_cb func,
 							void *user_data);
-int avrcp_get_element_attributes(struct avrcp *session, avctp_rsp_cb func,
-							void *user_data);
+int avrcp_get_element_attributes(struct avrcp *session);
 int avrcp_set_addressed_player(struct avrcp *session, uint16_t player_id,
 					avctp_rsp_cb func, void *user_data);
 
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index ad15bb9..a0b009a 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -520,7 +520,7 @@ static void test_client(gconstpointer data)
 		avrcp_get_play_status(context->session);
 
 	if (g_str_equal(context->data->test_name, "/TP/MDI/BV-03-C"))
-		avrcp_get_element_attributes(context->session, NULL, NULL);
+		avrcp_get_element_attributes(context->session);
 
 	if (g_str_equal(context->data->test_name, "/TP/NFY/BV-01-C"))
 		avrcp_register_notification(context->session,
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH BlueZ 12/12] android/avrcp-lib: Add support for parsing RegisterNotification response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
                   ` (9 preceding siblings ...)
  2014-03-26 14:13 ` [PATCH BlueZ 11/12] android/avrcp-lib: Add support for parsing GetElementAttributes response Luiz Augusto von Dentz
@ 2014-03-26 14:13 ` Luiz Augusto von Dentz
  2014-03-27 14:55 ` [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Szymon Janc
  11 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2014-03-26 14:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp-lib.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 android/avrcp-lib.h |  6 ++--
 android/avrcp.c     | 39 ++++++++++------------
 unit/test-avrcp.c   |  3 +-
 4 files changed, 114 insertions(+), 28 deletions(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 33717e0..dc3fb34 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -801,6 +801,7 @@ done:
 	return FALSE;
 }
 
+
 int avrcp_get_capabilities(struct avrcp *session, uint8_t param)
 {
 	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
@@ -808,10 +809,97 @@ int avrcp_get_capabilities(struct avrcp *session, uint8_t param)
 				get_capabilities_rsp, session);
 }
 
-int avrcp_register_notification(struct avrcp *session, uint8_t event,
-					uint32_t interval, avctp_rsp_cb func,
+static gboolean register_notification_rsp(struct avctp *conn,
+					uint8_t code, uint8_t subunit,
+					uint8_t *operands, size_t operand_count,
 					void *user_data)
 {
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu;
+	uint8_t event = 0;
+	uint16_t value16;
+	uint32_t value32;
+	uint64_t value64;
+	uint8_t *params = NULL;
+	int err;
+
+	DBG("");
+
+	if (!player || !player->cfm || !player->cfm->register_notification)
+		return FALSE;
+
+	pdu = parse_pdu(operands, operand_count);
+	if (!pdu) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	if (code == AVC_CTYPE_REJECTED) {
+		err = parse_status(pdu);
+		goto done;
+	}
+
+	if (pdu->params_len < 1) {
+		err = -EPROTO;
+		goto done;
+	}
+
+	event = pdu->params[0];
+
+	switch (event) {
+	case AVRCP_EVENT_STATUS_CHANGED:
+	case AVRCP_EVENT_VOLUME_CHANGED:
+		if (pdu->params_len != 2) {
+			err = -EPROTO;
+			goto done;
+		}
+		params = &pdu->params[1];
+		break;
+	case AVRCP_EVENT_TRACK_CHANGED:
+		if (pdu->params_len != 9) {
+			err = -EPROTO;
+			goto done;
+		}
+		value64 = bt_get_be64(&pdu->params[1]);
+		params = (uint8_t *) &value64;
+		break;
+	case AVRCP_EVENT_PLAYBACK_POS_CHANGED:
+		if (pdu->params_len != 5) {
+			err = -EPROTO;
+			goto done;
+		}
+		value32 = bt_get_be32(&pdu->params[1]);
+		params = (uint8_t *) &value32;
+		break;
+	case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+	case AVRCP_EVENT_SETTINGS_CHANGED:
+		if (pdu->params_len < 2) {
+			err = -EPROTO;
+			goto done;
+		}
+		params = &pdu->params[1];
+		break;
+	case AVRCP_EVENT_UIDS_CHANGED:
+		if (pdu->params_len != 3) {
+			err = -EPROTO;
+			goto done;
+		}
+		value16 = bt_get_be16(&pdu->params[1]);
+		params = (uint8_t *) &value16;
+		break;
+	}
+
+	err = 0;
+
+done:
+	return player->cfm->register_notification(session, err, code, event,
+						params, player->user_data);
+}
+
+int avrcp_register_notification(struct avrcp *session, uint8_t event,
+							uint32_t interval)
+{
 	uint8_t params[5];
 
 	params[0] = event;
@@ -820,7 +908,7 @@ int avrcp_register_notification(struct avrcp *session, uint8_t event,
 	return avrcp_send_req(session, AVC_CTYPE_NOTIFY, AVC_SUBUNIT_PANEL,
 					AVRCP_REGISTER_NOTIFICATION,
 					params, sizeof(params),
-					func, user_data);
+					register_notification_rsp, session);
 }
 
 static gboolean list_attributes_rsp(struct avctp *conn,
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 2f35e90..0b867aa 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -191,6 +191,9 @@ struct avrcp_control_cfm {
 	void (*get_element_attributes) (struct avrcp *session, int err,
 					uint8_t number, uint32_t *attrs,
 					char **text, void *user_data);
+	bool (*register_notification) (struct avrcp *session, int err,
+					uint8_t code, uint8_t event,
+					uint8_t *params, void *user_data);
 };
 
 struct avrcp_passthrough_handler {
@@ -219,8 +222,7 @@ int avrcp_send(struct avrcp *session, uint8_t transaction, uint8_t code,
 					uint8_t *params, size_t params_len);
 int avrcp_get_capabilities(struct avrcp *session, uint8_t param);
 int avrcp_register_notification(struct avrcp *session, uint8_t event,
-					uint32_t interval, avctp_rsp_cb func,
-					void *user_data);
+							uint32_t interval);
 int avrcp_list_player_attributes(struct avrcp *session);
 int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t number,
 							uint8_t *attrs);
diff --git a/android/avrcp.c b/android/avrcp.c
index 0995a06..add069b 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -724,39 +724,37 @@ static const struct avrcp_control_ind control_ind = {
 	.register_notification = handle_register_notification_cmd,
 };
 
-static gboolean register_notification_rsp(struct avctp *conn,
-					uint8_t code, uint8_t subunit,
-					uint8_t *operands, size_t operand_count,
-					void *user_data)
+static bool handle_register_notification_rsp(struct avrcp *session, int err,
+						uint8_t code, uint8_t event,
+						uint8_t *params,
+						void *user_data)
 {
 	struct avrcp_device *dev = user_data;
 	struct hal_ev_avrcp_volume_changed ev;
-	uint8_t *params;
 
-	if (code != AVC_CTYPE_INTERIM && code != AVC_CTYPE_CHANGED)
-		return FALSE;
-
-	if (operands == NULL || operand_count < 7)
-		return FALSE;
+	if (err < 0) {
+		error("AVRCP: %s", strerror(-err));
+		return false;
+	}
 
-	params = &operands[7];
+	if (code != AVC_CTYPE_INTERIM && code != AVC_CTYPE_CHANGED)
+		return false;
 
-	if (params == NULL || params[0] != AVRCP_EVENT_VOLUME_CHANGED)
-		return FALSE;
+	if (event != AVRCP_EVENT_VOLUME_CHANGED)
+		return false;
 
 	ev.type = code;
-	ev.volume = params[1] & 0x7F;
+	ev.volume = params[0] & 0x7f;
 
 	ipc_send_notif(hal_ipc, HAL_SERVICE_ID_AVRCP,
 					HAL_EV_AVRCP_VOLUME_CHANGED,
 					sizeof(ev), &ev);
 
 	if (code == AVC_CTYPE_INTERIM)
-		return TRUE;
+		return true;
 
-	avrcp_register_notification(dev->session, params[0], 0,
-					register_notification_rsp, dev);
-	return FALSE;
+	avrcp_register_notification(dev->session, event, 0);
+	return false;
 }
 
 static void handle_get_capabilities_rsp(struct avrcp *session, int err,
@@ -775,9 +773,7 @@ static void handle_get_capabilities_rsp(struct avrcp *session, int err,
 		if (events[i] != AVRCP_EVENT_VOLUME_CHANGED)
 			continue;
 
-		avrcp_register_notification(dev->session, events[i], 0,
-						register_notification_rsp,
-						dev);
+		avrcp_register_notification(dev->session, events[i], 0);
 		break;
 	}
 
@@ -786,6 +782,7 @@ static void handle_get_capabilities_rsp(struct avrcp *session, int err,
 
 static const struct avrcp_control_cfm control_cfm = {
 	.get_capabilities = handle_get_capabilities_rsp,
+	.register_notification = handle_register_notification_rsp,
 };
 
 static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index a0b009a..5b259bd 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -524,8 +524,7 @@ static void test_client(gconstpointer data)
 
 	if (g_str_equal(context->data->test_name, "/TP/NFY/BV-01-C"))
 		avrcp_register_notification(context->session,
-						AVRCP_EVENT_STATUS_CHANGED, 0,
-						NULL, NULL);
+						AVRCP_EVENT_STATUS_CHANGED, 0);
 
 	if (g_str_equal(context->data->test_name, "/TP/BGN/BV-01-I"))
 		avrcp_send_passthrough(context->session, IEEEID_BTSIG,
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response
  2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
                   ` (10 preceding siblings ...)
  2014-03-26 14:13 ` [PATCH BlueZ 12/12] android/avrcp-lib: Add support for parsing RegisterNotification response Luiz Augusto von Dentz
@ 2014-03-27 14:55 ` Szymon Janc
  11 siblings, 0 replies; 14+ messages in thread
From: Szymon Janc @ 2014-03-27 14:55 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hi Luiz,

On Wednesday 26 of March 2014 16:13:41 Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> ---
>  android/avrcp-lib.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++------
>  android/avrcp-lib.h |   6 ++-
>  android/avrcp.c     |  40 ++++++++--------
>  unit/test-avrcp.c   |   3 +-
>  4 files changed, 138 insertions(+), 39 deletions(-)
> 
> diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
> index c7b8b6a..2128835 100644
> --- a/android/avrcp-lib.c
> +++ b/android/avrcp-lib.c
> @@ -135,6 +135,27 @@ void avrcp_shutdown(struct avrcp *session)
>  	g_free(session);
>  }
>  
> +static struct avrcp_header *parse_pdu(uint8_t *operands, size_t operand_count)
> +{
> +	struct avrcp_header *pdu;
> +
> +	if (operands == NULL || operand_count < sizeof(*pdu)) {

Use ! instead of '== NULL'

> +		error("AVRCP: packet too smal (%zu bytes)", operand_count);

typo: smal -> small

> +		return NULL;
> +	}
> +
> +	pdu = (void *) operands;
> +	pdu->params_len = ntohs(pdu->params_len);
> +
> +	if (operand_count != pdu->params_len + sizeof(*pdu)) {
> +		error("AVRCP: invalid parameter length (%u bytes)",
> +							pdu->params_len);
> +		return NULL;
> +	}
> +
> +	return pdu;
> +}
> +
>  static ssize_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
>  					uint8_t *code, uint8_t *subunit,
>  					uint8_t *operands, size_t operand_count,
> @@ -142,26 +163,27 @@ static ssize_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
>  {
>  	struct avrcp *session = user_data;
>  	const struct avrcp_control_handler *handler;
> -	struct avrcp_header *pdu = (void *) operands;
> -	uint32_t company_id = ntoh24(pdu->company_id);
> -	uint16_t params_len = ntohs(pdu->params_len);
> +	struct avrcp_header *pdu;
> +	uint32_t company_id;
>  	ssize_t ret;
>  
> +	pdu = parse_pdu(operands, operand_count);
> +	if (!pdu) {
> +		pdu->params[0] = AVRCP_STATUS_INVALID_COMMAND;
> +		goto reject;
> +	}
> +
> +	company_id = ntoh24(pdu->company_id);
>  	if (company_id != IEEEID_BTSIG) {
>  		*code = AVC_CTYPE_NOT_IMPLEMENTED;
>  		return 0;
>  	}
>  
> -	DBG("AVRCP PDU 0x%02X, len 0x%04X", pdu->pdu_id, params_len);
> +	DBG("AVRCP PDU 0x%02X, len 0x%04X", pdu->pdu_id, pdu->params_len);
>  
>  	pdu->packet_type = 0;
>  	pdu->rsvd = 0;
>  
> -	if (operand_count < AVRCP_HEADER_LENGTH) {
> -		pdu->params[0] = AVRCP_STATUS_INVALID_COMMAND;
> -		goto reject;
> -	}
> -
>  	if (!session->control_handlers)
>  		goto reject;
>  
> @@ -180,7 +202,7 @@ static ssize_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
>  		goto reject;
>  	}
>  
> -	ret = handler->func(session, transaction, params_len, pdu->params,
> +	ret = handler->func(session, transaction, pdu->params_len, pdu->params,
>  							session->control_data);
>  	if (ret < 0) {
>  		switch (ret) {
> @@ -670,6 +692,31 @@ int avrcp_send(struct avrcp *session, uint8_t transaction, uint8_t code,
>  							session->tx_buf, len);
>  }
>  
> +static int parse_status(struct avrcp_header *pdu)
> +{
> +	if (pdu->params_len < 1)
> +		return -EPROTO;
> +
> +	switch (pdu->params[0]) {
> +	case AVRCP_STATUS_INVALID_COMMAND:
> +		return -ENOSYS;
> +	case AVRCP_STATUS_INVALID_PARAM:
> +		return -EINVAL;
> +	case AVRCP_STATUS_SUCCESS:
> +		return 0;
> +	case AVRCP_STATUS_OUT_OF_BOUNDS:
> +		return -EOVERFLOW;
> +	case AVRCP_STATUS_INTERNAL_ERROR:
> +	case AVRCP_STATUS_INVALID_PLAYER_ID:
> +	case AVRCP_STATUS_PLAYER_NOT_BROWSABLE:
> +	case AVRCP_STATUS_NO_AVAILABLE_PLAYERS:
> +	case AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED:
> +		return -EPERM;
> +	default:
> +		return -EPROTO;
> +	}
> +}
> +
>  static int avrcp_send_req(struct avrcp *session, uint8_t code, uint8_t subunit,
>  					uint8_t pdu_id, uint8_t *params,
>  					size_t params_len, avctp_rsp_cb func,
> @@ -698,12 +745,67 @@ static int avrcp_send_req(struct avrcp *session, uint8_t code, uint8_t subunit,
>  					session->tx_buf, len, func, user_data);
>  }
>  
> -int avrcp_get_capabilities(struct avrcp *session, uint8_t param,
> -					avctp_rsp_cb func, void *user_data)
> +static gboolean get_capabilities_rsp(struct avctp *conn,
> +					uint8_t code, uint8_t subunit,
> +					uint8_t *operands, size_t operand_count,
> +					void *user_data)
> +{
> +	struct avrcp *session = user_data;
> +	struct avrcp_player *player = session->player;
> +	struct avrcp_header *pdu;
> +	uint8_t number = 0;
> +	uint8_t *params = NULL;
> +	int err;
> +
> +	DBG("");
> +
> +	if (!player || !player->cfm || !player->cfm->get_capabilities)
> +		return FALSE;
> +
> +	pdu = parse_pdu(operands, operand_count);
> +	if (!pdu) {
> +		err = -EPROTO;
> +		goto done;
> +	}
> +
> +	if (code == AVC_CTYPE_REJECTED) {
> +		err = parse_status(pdu);
> +		goto done;
> +	}
> +
> +	if (pdu->params_len < 2) {
> +		err = -EPROTO;
> +		goto done;
> +	}
> +
> +	switch (pdu->params[0]) {
> +	case CAP_COMPANY_ID:
> +	case CAP_EVENTS_SUPPORTED:
> +		break;
> +	default:
> +		err = -EPROTO;
> +		goto done;
> +	}
> +
> +	number = pdu->params[1];
> +
> +	if (number > 0)
> +		params = &pdu->params[2];
> +
> +	err = 0;
> +
> +done:
> +	player->cfm->get_capabilities(session, err, number, params,
> +							player->user_data);
> +
> +	return FALSE;
> +}
> +
> +int avrcp_get_capabilities(struct avrcp *session, uint8_t param)
>  {
>  	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
>  				AVRCP_GET_CAPABILITIES, &param, sizeof(param),
> -				func, user_data);
> +				get_capabilities_rsp, session);
>  }
>  
>  int avrcp_register_notification(struct avrcp *session, uint8_t event,
> diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
> index d9acb7d..ab110cb 100644
> --- a/android/avrcp-lib.h
> +++ b/android/avrcp-lib.h
> @@ -164,6 +164,9 @@ struct avrcp_control_ind {
>  };
>  
>  struct avrcp_control_cfm {
> +	void (*get_capabilities) (struct avrcp *session, int err,
> +					uint8_t number, uint8_t *params,
> +					void *user_data);
>  };
>  
>  struct avrcp_passthrough_handler {
> @@ -190,8 +193,7 @@ int avrcp_init_uinput(struct avrcp *session, const char *name,
>  int avrcp_send(struct avrcp *session, uint8_t transaction, uint8_t code,
>  					uint8_t subunit, uint8_t pdu_id,
>  					uint8_t *params, size_t params_len);
> -int avrcp_get_capabilities(struct avrcp *session, uint8_t param,
> -					avctp_rsp_cb func, void *user_data);
> +int avrcp_get_capabilities(struct avrcp *session, uint8_t param);
>  int avrcp_register_notification(struct avrcp *session, uint8_t event,
>  					uint32_t interval, avctp_rsp_cb func,
>  					void *user_data);
> diff --git a/android/avrcp.c b/android/avrcp.c
> index ec98139..0995a06 100644
> --- a/android/avrcp.c
> +++ b/android/avrcp.c
> @@ -759,38 +759,35 @@ static gboolean register_notification_rsp(struct avctp *conn,
>  	return FALSE;
>  }
>  
> -static gboolean get_capabilities_rsp(struct avctp *conn,
> -					uint8_t code, uint8_t subunit,
> -					uint8_t *operands, size_t operand_count,
> +static void handle_get_capabilities_rsp(struct avrcp *session, int err,
> +					uint8_t number, uint8_t *events,
>  					void *user_data)
>  {
>  	struct avrcp_device *dev = user_data;
> -	uint8_t *params;
> -	uint8_t count;
> -
> -	if (operands == NULL || operand_count < 7)
> -		return FALSE;
> -
> -	params = &operands[7];
> -
> -	if (params == NULL || params[0] != CAP_EVENTS_SUPPORTED)
> -		return FALSE;
> +	int i;
>  
> -	for (count = params[1]; count > 0; count--) {
> -		uint8_t event = params[1 + count];
> +	if (err < 0) {
> +		error("AVRCP: %s", strerror(-err));
> +		return;
> +	}
>  
> -		if (event != AVRCP_EVENT_VOLUME_CHANGED)
> +	for (i = 0; i < number; i++) {
> +		if (events[i] != AVRCP_EVENT_VOLUME_CHANGED)
>  			continue;
>  
> -		avrcp_register_notification(dev->session, event, 0,
> +		avrcp_register_notification(dev->session, events[i], 0,
>  						register_notification_rsp,
>  						dev);
> -		return FALSE;
> +		break;
>  	}
>  
> -	return FALSE;
> +	return;
>  }
>  
> +static const struct avrcp_control_cfm control_cfm = {
> +	.get_capabilities = handle_get_capabilities_rsp,
> +};
> +
>  static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
>  						uint16_t imtu, uint16_t omtu)
>  {
> @@ -804,7 +801,7 @@ static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
>  	avrcp_set_destroy_cb(dev->session, disconnect_cb, dev);
>  	avrcp_set_passthrough_handlers(dev->session, passthrough_handlers,
>  									dev);
> -	avrcp_register_player(dev->session, &control_ind, NULL, dev);
> +	avrcp_register_player(dev->session, &control_ind, &control_cfm, dev);
>  
>  	dev->queue = g_queue_new();
>  
> @@ -828,8 +825,7 @@ static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
>  
>  	ev.features |= HAL_AVRCP_FEATURE_ABSOLUTE_VOLUME;
>  
> -	avrcp_get_capabilities(dev->session, CAP_EVENTS_SUPPORTED,
> -						get_capabilities_rsp, dev);
> +	avrcp_get_capabilities(dev->session, CAP_EVENTS_SUPPORTED);
>  
>  done:
>  	ipc_send_notif(hal_ipc, HAL_SERVICE_ID_AVRCP,
> diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
> index eb00238..d6be6a6 100644
> --- a/unit/test-avrcp.c
> +++ b/unit/test-avrcp.c
> @@ -491,8 +491,7 @@ static void test_client(gconstpointer data)
>  									NULL);
>  
>  	if (g_str_equal(context->data->test_name, "/TP/CFG/BV-01-C"))
> -		avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED,
> -								NULL, NULL);
> +		avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED);
>  
>  	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-01-C"))
>  		avrcp_list_player_attributes(context->session, NULL, NULL);
> 

-- 
Best regards, 
Szymon Janc

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH BlueZ 08/12] android/avrcp-lib: Add support for parsing GetCurrentPlayerValue response
  2014-03-26 14:13 ` [PATCH BlueZ 08/12] android/avrcp-lib: Add support for parsing GetCurrentPlayerValue response Luiz Augusto von Dentz
@ 2014-03-27 15:01   ` Szymon Janc
  0 siblings, 0 replies; 14+ messages in thread
From: Szymon Janc @ 2014-03-27 15:01 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hi Luiz,

On Wednesday 26 of March 2014 16:13:48 Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> ---
>  android/avrcp-lib.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++-------
>  android/avrcp-lib.h |  8 +++---
>  unit/test-avrcp.c   |  6 ++---
>  3 files changed, 77 insertions(+), 15 deletions(-)
> 
> diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
> index 5f36738..2c8d0f5 100644
> --- a/android/avrcp-lib.c
> +++ b/android/avrcp-lib.c
> @@ -1064,24 +1064,84 @@ int avrcp_get_player_value_text(struct avrcp *session, uint8_t attr,
>  				sizeof(attr), get_value_text_rsp, session);
>  }
>  
> -int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
> -					uint8_t attr_count, avctp_rsp_cb func,
> +static int parse_value(struct avrcp_header *pdu, uint8_t *number,
> +					uint8_t *attrs, uint8_t *values)
> +{
> +	int i;
> +
> +	*number = pdu->params[0];
> +	if (*number > AVRCP_ATTRIBUTE_LAST ||
> +					1 + *number * 2 != pdu->params_len) {

At least comment would nice here, or macro maybe?

> +		number = 0;
> +		return -EPROTO;
> +	}
> +
> +	for (i = 0; i < *number; i++) {
> +		attrs[i] = pdu->params[i * 2 + 1];
> +		values[i] = pdu->params[i * 2 + 2];
> +	}

ditto.

> +
> +	return 0;
> +}
> +
> +static gboolean get_value_rsp(struct avctp *conn,
> +					uint8_t code, uint8_t subunit,
> +					uint8_t *operands, size_t operand_count,
>  					void *user_data)
> +{
> +	struct avrcp *session = user_data;
> +	struct avrcp_player *player = session->player;
> +	struct avrcp_header *pdu = (void *) operands;
> +	uint8_t number = 0;
> +	uint8_t attrs[AVRCP_ATTRIBUTE_LAST];
> +	uint8_t values[AVRCP_ATTRIBUTE_LAST];
> +	int err;
> +
> +	DBG("");
> +
> +	if (!player || !player->cfm || !player->cfm->get_value)
> +		return FALSE;
> +
> +	pdu = parse_pdu(operands, operand_count);
> +	if (!pdu) {
> +		err = -EPROTO;
> +		goto done;
> +	}
> +
> +	if (code == AVC_CTYPE_REJECTED) {
> +		err = parse_status(pdu);
> +		goto done;
> +	}
> +
> +	err = parse_value(pdu, &number, attrs, values);
> +
> +done:
> +	player->cfm->get_value(session, err, number, attrs, values,
> +							player->user_data);
> +
> +	return FALSE;
> +}
> +
> +int avrcp_get_current_player_value(struct avrcp *session, uint8_t number,
> +							uint8_t *attrs)
>  
>  {
> -	uint8_t buf[AVRCP_ATTRIBUTE_LAST + 1];
> +	uint8_t pdu[AVRCP_ATTRIBUTE_LAST + 1];
>  
> -	if (attr_count > AVRCP_ATTRIBUTE_LAST)
> +	if (number > AVRCP_ATTRIBUTE_LAST)
>  		return -EINVAL;
>  
> -	if (attrs && attr_count) {
> -		buf[0] = attr_count;
> -		memcpy(buf + 1, attrs, attr_count);
> +	if (number > 0) {
> +		if (!attrs)
> +			return -EINVAL;
> +
> +		pdu[0] = number;
> +		memcpy(&pdu[1], attrs, number);
>  	}
>  
>  	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
> -				AVRCP_GET_CURRENT_PLAYER_VALUE, buf,
> -				attr_count + 1, func, user_data);
> +				AVRCP_GET_CURRENT_PLAYER_VALUE, pdu,
> +				number + 1, get_value_rsp, session);
>  }
>  
>  int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
> diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
> index 0929155..30ceda0 100644
> --- a/android/avrcp-lib.h
> +++ b/android/avrcp-lib.h
> @@ -179,6 +179,9 @@ struct avrcp_control_cfm {
>  	void (*get_value_text) (struct avrcp *session, int err,
>  					uint8_t number, uint8_t *values,
>  					char **text, void *user_data);
> +	void (*get_value) (struct avrcp *session, int err,
> +					uint8_t number, uint8_t *attrs,
> +					uint8_t *values, void *user_data);
>  };
>  
>  struct avrcp_passthrough_handler {
> @@ -218,9 +221,8 @@ int avrcp_get_player_value_text(struct avrcp *session, uint8_t attr,
>  int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
>  					uint8_t attr_count, uint8_t *values,
>  					avctp_rsp_cb func, void *user_data);
> -int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
> -					uint8_t attr_count, avctp_rsp_cb func,
> -					void *user_data);
> +int avrcp_get_current_player_value(struct avrcp *session, uint8_t number,
> +							uint8_t *attrs);
>  int avrcp_get_play_status(struct avrcp *session, avctp_rsp_cb func,
>  							void *user_data);
>  int avrcp_set_volume(struct avrcp *session, uint8_t volume, avctp_rsp_cb func,
> diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
> index fe1d51f..016c80c 100644
> --- a/unit/test-avrcp.c
> +++ b/unit/test-avrcp.c
> @@ -500,11 +500,11 @@ static void test_client(gconstpointer data)
>  		avrcp_get_player_attribute_text(context->session, 0, NULL);
>  
>  	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-09-C")) {
> -		uint8_t attributes[2] = { AVRCP_ATTRIBUTE_EQUALIZER,
> +		uint8_t attrs[2] = { AVRCP_ATTRIBUTE_EQUALIZER,
>  						AVRCP_ATTRIBUTE_REPEAT_MODE };
>  
> -		avrcp_get_current_player_value(context->session, attributes,
> -						sizeof(attributes), NULL, NULL);
> +		avrcp_get_current_player_value(context->session, sizeof(attrs),
> +									attrs);
>  	}
>  
>  	if (g_str_equal(context->data->test_name, "/TP/PAS/BV-11-C")) {
> 

-- 
Best regards, 
Szymon Janc

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2014-03-27 15:01 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-26 14:13 [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 02/12] android/avrcp-lib: Add support for parsing ListPlayerAttributes response Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 03/12] android/avrcp-lib: Add support for parsing GetPlayerAttributeText response Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 04/12] android/avrcp-lib: Add avrcp_list_player_values Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 05/12] android/avrcp-lib: Add support for parsing ListPlayerValues response Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 06/12] android/avrcp-lib: Add avrcp_get_player_value_text Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 07/12] android/avrcp-lib: Add support for parsing GetPlayerValueText response Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 08/12] android/avrcp-lib: Add support for parsing GetCurrentPlayerValue response Luiz Augusto von Dentz
2014-03-27 15:01   ` Szymon Janc
2014-03-26 14:13 ` [PATCH BlueZ 09/12] android/avrcp-lib: Add support for parsing SetPlayerValue response Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 10/12] android/avrcp-lib: Add support for parsing GetPlayStatus response Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 11/12] android/avrcp-lib: Add support for parsing GetElementAttributes response Luiz Augusto von Dentz
2014-03-26 14:13 ` [PATCH BlueZ 12/12] android/avrcp-lib: Add support for parsing RegisterNotification response Luiz Augusto von Dentz
2014-03-27 14:55 ` [PATCH BlueZ 01/12] android/avrcp-lib: Add support for parsing GetCapabilities response Szymon Janc

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox