[PATCH v4 17/22] avrcp: handle GetElementAttributes pdu

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Example responses for PTS test TC_TG_MDI_BV_04_C:

> ACL data: handle 11 flags 0x02 dlen 26
    L2CAP(d): cid 0x0042 len 22 [psm 23]
      AVCTP: Command : pt 0x00 transaction 2 pid 0x110e
        AV/C: Status: address 0x48 opcode 0x00
          Subunit: Panel
          Opcode: Vendor Dependent
          Company ID: 0x001958
          AVRCP: GetElementAttributes: pt 0x00 len 0x0009
            Identifier: 0x0 (PLAYING)
            AttributeCount: 0x00
< ACL data: handle 11 flags 0x02 dlen 70
    L2CAP(d): cid 0x0042 len 66 [psm 23]
      AVCTP: Response : pt 0x00 transaction 2 pid 0x110e
        AV/C: Stable: address 0x48 opcode 0x00
          Subunit: Panel
          Opcode: Vendor Dependent
          Company ID: 0x001958
          AVRCP: GetElementAttributes: pt 0x00 len 0x0035
            AttributeCount: 0x03
            Attribute: 0x00000001 (Title)
            CharsetID: 0x006a (UTF-8)
            AttributeValueLength: 0x0012
            AttributeValue: Walking on the Sun
            Attribute: 0x00000002 (Artist)
            CharsetID: 0x006a (UTF-8)
            AttributeValueLength: 0x0005
            AttributeValue: Lucas
            Attribute: 0x00000007 (Progress)
            CharsetID: 0x006a (UTF-8)
            AttributeValueLength: 0x0005
            AttributeValue: 32029

And TC_TG_MDI_BV_05_C:

> ACL data: handle 11 flags 0x02 dlen 30
    L2CAP(d): cid 0x0043 len 26 [psm 23]
      AVCTP: Command : pt 0x00 transaction 2 pid 0x110e
        AV/C: Status: address 0x48 opcode 0x00
          Subunit: Panel
          Opcode: Vendor Dependent
          Company ID: 0x001958
          AVRCP: GetElementAttributes: pt 0x00 len 0x000d
            Identifier: 0x0 (PLAYING)
            AttributeCount: 0x01
            Attribute: 0x00000001 (Title)
< ACL data: handle 11 flags 0x02 dlen 44
    L2CAP(d): cid 0x0043 len 40 [psm 23]
      AVCTP: Response : pt 0x00 transaction 2 pid 0x110e
        AV/C: Stable: address 0x48 opcode 0x00
          Subunit: Panel
          Opcode: Vendor Dependent
          Company ID: 0x001958
          AVRCP: GetElementAttributes: pt 0x00 len 0x001b
            AttributeCount: 0x01
            Attribute: 0x00000001 (Title)
            CharsetID: 0x006a (UTF-8)
            AttributeValueLength: 0x0012
            AttributeValue: Walking on the Sun
---
 audio/control.c |  189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 189 insertions(+), 0 deletions(-)

diff --git a/audio/control.c b/audio/control.c
index c5e175a..a29a392 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -123,6 +123,7 @@
 #define AVRCP_GET_PLAYER_VALUE_TEXT	0x16
 #define AVRCP_DISPLAYABLE_CHARSET	0x17
 #define AVRCP_CT_BATTERY_STATUS		0x18
+#define AVRCP_GET_ELEMENT_ATTRIBUTES	0x20
 #define AVRCP_GET_PLAY_STATUS		0x30
 #define AVRCP_REGISTER_NOTIFICATION	0x31
 
@@ -184,6 +185,16 @@ enum battery_status {
 	BATTERY_STATUS_FULL_CHARGE =	4,
 };
 
+enum media_info_id {
+	MEDIA_INFO_TITLE =		1,
+	MEDIA_INFO_ARTIST =		2,
+	MEDIA_INFO_ALBUM =		3,
+	MEDIA_INFO_TRACK =		4,
+	MEDIA_INFO_N_TRACKS =		5,
+	MEDIA_INFO_GENRE =		6,
+	MEDIA_INFO_CURRENT_POSITION =	7,
+};
+
 static DBusConnection *connection = NULL;
 
 static GSList *servers = NULL;
@@ -745,6 +756,103 @@ static void mp_set_playback_status(struct control *control, uint8_t status,
 	mp->status = status;
 }
 
+/*
+ * Copy media_info field to a buffer, intended to be used in a response to
+ * GetElementAttributes message.
+ *
+ * It assumes there's enough space in the buffer and on success it returns the
+ * size written.
+ *
+ * If @param id is not valid, -EINVAL is returned. If there's no such media
+ * attribute, -ENOENT is returned.
+ */
+static int mp_get_media_attribute(struct media_player *mp,
+						uint32_t id, uint8_t *buf)
+{
+	struct media_info_elem {
+		uint32_t id;
+		uint16_t charset;
+		uint16_t len;
+		uint8_t val[];
+	};
+	const struct media_info *mi = &mp->mi;
+	struct media_info_elem *elem = (void *)buf;
+	uint16_t len;
+	char valstr[20];
+
+	switch (id) {
+	case MEDIA_INFO_TITLE:
+		if (mi->title) {
+			len = strlen(mi->title);
+			memcpy(elem->val, mi->title, len);
+		} else {
+			len = 0;
+		}
+
+		break;
+	case MEDIA_INFO_ARTIST:
+		if (mi->artist == NULL)
+			return -ENOENT;
+
+		len = strlen(mi->artist);
+		memcpy(elem->val, mi->artist, len);
+		break;
+	case MEDIA_INFO_ALBUM:
+		if (mi->album == NULL)
+			return -ENOENT;
+
+		len = strlen(mi->album);
+		memcpy(elem->val, mi->album, len);
+		break;
+	case MEDIA_INFO_GENRE:
+		if (mi->genre == NULL)
+			return -ENOENT;
+
+		len = strlen(mi->genre);
+		memcpy(elem->val, mi->genre, len);
+		break;
+
+	case MEDIA_INFO_TRACK:
+		if (!mi->track)
+			return -ENOENT;
+
+		snprintf(valstr, 20, "%u", mi->track);
+		len = strlen(valstr);
+		memcpy(elem->val, valstr, len);
+		break;
+	case MEDIA_INFO_N_TRACKS:
+		if (!mi->ntracks)
+			return -ENOENT;
+
+		snprintf(valstr, 20, "%u", mi->ntracks);
+		len = strlen(valstr);
+		memcpy(elem->val, valstr, len);
+		break;
+	case MEDIA_INFO_CURRENT_POSITION:
+		if (mi->elapsed != 0xFFFFFFFF) {
+			uint32_t elapsed;
+
+			mp_get_playback_status(mp, NULL, &elapsed, NULL);
+
+			snprintf(valstr, 20, "%u", elapsed);
+			len = strlen(valstr);
+			memcpy(elem->val, valstr, len);
+		} else {
+			return -ENOENT;
+		}
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	elem->id = htonl(id);
+	elem->charset = htons(0x6A); /* Always use UTF-8 */
+	elem->len = htons(len);
+
+	return sizeof(struct media_info_elem) + len;
+}
+
 static void mp_set_attribute(struct media_player *mp,
 						uint8_t attr, uint8_t val)
 {
@@ -893,6 +1001,74 @@ err:
 	return -EINVAL;
 }
 
+static int avrcp_handle_get_element_attributes(struct control *control,
+						struct avrcp_spec_avc_pdu *pdu)
+{
+	uint16_t len = ntohs(pdu->params_len);
+	uint64_t *identifier = (void *) &pdu->params[0];
+	uint16_t pos;
+	uint8_t nattr;
+	int size;
+	unsigned int i;
+
+	if (len < 8 || *identifier != 0 || !control->mp)
+		goto err;
+
+	len = 0;
+	pos = 1; /* Keep track of current position in reponse */
+	nattr = pdu->params[8];
+
+	if (!control->mp)
+		goto done;
+
+	if (!nattr) {
+		/*
+		 * Return all available information, at least
+		 * title must be returned.
+		 */
+		for (i = 1; i <= MEDIA_INFO_CURRENT_POSITION; i++) {
+			size = mp_get_media_attribute(control->mp, i,
+							&pdu->params[pos]);
+
+			if (size > 0) {
+				len++;
+				pos += size;
+			}
+		}
+	} else {
+		uint32_t *attr_ids = g_malloc(sizeof(uint32_t) * nattr);
+
+		/* save a copy of requested attributes */
+		memcpy(&attr_ids[0], &pdu->params[9], nattr * 4);
+
+		for (i = 0; i < nattr; i++) {
+			uint32_t attr = ntohl(attr_ids[i]);
+
+			size = mp_get_media_attribute(control->mp, attr,
+							&pdu->params[pos]);
+
+			if (size > 0) {
+				len++;
+				pos += size;
+			}
+		}
+
+		g_free(attr_ids);
+
+		if (!len)
+			goto err;
+	}
+
+done:
+	pdu->params[0] = len;
+	pdu->params_len = htons(pos);
+
+	return pos;
+err:
+	pdu->params[0] = E_INVALID_PARAM;
+	return -EINVAL;
+}
+
 static int avrcp_handle_get_current_player_value(struct control *control,
 						struct avrcp_spec_avc_pdu *pdu)
 {
@@ -1181,6 +1357,19 @@ static int handle_vendordep_pdu(struct control *control,
 		avrcp->code = CTYPE_STABLE;
 
 		break;
+	case AVRCP_GET_ELEMENT_ATTRIBUTES:
+		if (avrcp->code != CTYPE_STATUS) {
+			pdu->params[0] = E_INVALID_COMMAND;
+			goto err_metadata;
+		}
+
+		len = avrcp_handle_get_element_attributes(control, pdu);
+		if (len < 0)
+			goto err_metadata;
+
+		avrcp->code = CTYPE_STABLE;
+
+		break;
 	case AVRCP_GET_CURRENT_PLAYER_VALUE:
 		if (avrcp->code != CTYPE_STATUS) {
 			pdu->params[0] = E_INVALID_COMMAND;
-- 
1.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux