diff --git a/audio/control.c b/audio/control.c
index 7fe4af5..87dcdbf 100644
--- a/audio/control.c
+++ b/audio/control.c
#define FORWARD_OP 0x4b
#define BACKWARD_OP 0x4c
+/* Company IDs for vendor dependent commands */
+#define IEEEID_BTSIG 0x001958
+
+/* Error codes for metadata transfer */
+#define E_INVALID_COMMAND 0x00
+#define E_INVALID_PARAM 0x01
+#define E_PARAM_NOT_FOUND 0x02
+#define E_INTERNAL 0x03
+
+/* PDU types for metadata transfer */
+#define AVRCP_GET_CAPABILITIES 0x10
+
+/* Capabilities for AVRCP_GET_CAPABILITIES pdu */
+#define CAP_COMPANY_ID 0x02
+
#define QUIRK_NO_RELEASE 1 << 0
enum player_setting {
{ NULL }
};
+/* Company IDs supported by this device */
+static uint32_t company_ids[] = {
+ IEEEID_BTSIG,
+};
+
static GSList *avctp_callbacks = NULL;
static void auth_cb(DBusError *derr, void *user_data);
mi->ntracks, mi->track, mi->track_len);
}
+static int avrcp_handle_get_capabilities(struct control *control,
+ struct avrcp_spec_avc_pdu *pdu)
+{
+ uint16_t len = ntohs(pdu->params_len);
+ unsigned int i;
+
+ if (len != 1)
+ goto err;
+
+ DBG("id=%u", pdu->params[0]);
+
+ switch (pdu->params[0]) {
+ case CAP_COMPANY_ID:
+ for (i = 0; i < G_N_ELEMENTS(company_ids); i++) {
+ pdu->params[2 + i * 3] = company_ids[i] >> 16;
+ pdu->params[3 + i * 3] = (company_ids[i] >> 8) & 0xFF;
+ pdu->params[4 + i * 3] = company_ids[i] & 0xFF;
+ }
+
+ pdu->params_len = htons(2 + (3 * G_N_ELEMENTS(company_ids)));
+ pdu->params[1] = G_N_ELEMENTS(company_ids);
+
+ return 2 + (3 * G_N_ELEMENTS(company_ids));
+ }
+
+err:
+ pdu->params[0] = E_INVALID_PARAM;
+ return -EINVAL;
+}
+
/* handle vendordep pdu inside an avctp packet */
static int handle_vendordep_pdu(struct control *control,
struct avrcp_header *avrcp,
int operand_count)
{
- avrcp->code = CTYPE_NOT_IMPLEMENTED;
- return AVRCP_HEADER_LENGTH;
+ struct avrcp_spec_avc_pdu *pdu = (void *) avrcp + AVRCP_HEADER_LENGTH;
+ uint32_t company_id = (pdu->company_id[0] << 16) |
+ (pdu->company_id[1] << 8) |
+ (pdu->company_id[2]);
+ int len;
+
+ if (company_id != IEEEID_BTSIG ||
+ pdu->packet_type != AVCTP_PACKET_SINGLE) {
+ avrcp->code = CTYPE_NOT_IMPLEMENTED;
+ return AVRCP_HEADER_LENGTH;
+ }
+
+ pdu->packet_type = 0;
+ pdu->rsvd = 0;
+
+ if (operand_count + 3 < AVRCP_SPECAVCPDU_HEADER_LENGTH) {
+ pdu->params[0] = E_INVALID_COMMAND;
+ goto err_metadata;
+ }
+
+ switch (pdu->pdu_id) {
+ case AVRCP_GET_CAPABILITIES:
+ if (avrcp->code != CTYPE_STATUS) {
+ pdu->params[0] = E_INVALID_COMMAND;
+ goto err_metadata;
+ }
+
+ len = avrcp_handle_get_capabilities(control, pdu);
+ if (len < 0)
+ goto err_metadata;
+
+ avrcp->code = CTYPE_STABLE;
+
+ break;
+ default:
+ /* Invalid pdu_id */
+ pdu->params[0] = E_INVALID_COMMAND;
+ goto err_metadata;
+ }
+
+ return AVRCP_HEADER_LENGTH + AVRCP_SPECAVCPDU_HEADER_LENGTH + len;
+
+err_metadata:
+ avrcp->code = CTYPE_REJECTED;
+ pdu->params_len = htons(1);
+
+ return AVRCP_HEADER_LENGTH + AVRCP_SPECAVCPDU_HEADER_LENGTH + 1;
}
static void avctp_disconnected(struct audio_device *dev)