diff --git a/audio/control.c b/audio/control.c
index 187c3f1..603659d 100644
--- a/audio/control.c
+++ b/audio/control.c
/* ctype entries */
#define CTYPE_CONTROL 0x0
#define CTYPE_STATUS 0x1
+#define CTYPE_NOTIFY 0x3
#define CTYPE_NOT_IMPLEMENTED 0x8
#define CTYPE_ACCEPTED 0x9
#define CTYPE_REJECTED 0xA
#define CTYPE_STABLE 0xC
+#define CTYPE_INTERIM 0xF
/* opcodes */
#define OP_VENDORDEP 0x00
#define AVRCP_DISPLAYABLE_CHARSET 0x17
#define AVRCP_CT_BATTERY_STATUS 0x18
#define AVRCP_GET_PLAY_STATUS 0x30
+#define AVRCP_REGISTER_NOTIFICATION 0x31
+
+/* Notification events */
+#define AVRCP_EVENT_PLAYBACK_STATUS_CHANGED 0x01
+#define AVRCP_EVENT_TRACK_CHANGED 0x02
/* Capabilities for AVRCP_GET_CAPABILITIES pdu */
#define CAP_COMPANY_ID 0x02
gboolean target;
uint8_t key_quirks[256];
+
+ uint16_t registered_events;
};
static struct {
return 9;
}
+static int avrcp_handle_register_notification(struct control *control,
+ struct avrcp_spec_avc_pdu *pdu)
+{
+ uint16_t len = ntohs(pdu->params_len);
+ uint8_t status;
+
+ /*
+ * 1 byte for EventID, 4 bytes for Playback interval but the latest
+ * one is applicable only for EVENT_PLAYBACK_POS_CHANGED. See AVRCP
+ * 1.3 spec, section 5.4.2.
+ */
+ if (len != 5)
+ goto err;
+
+ switch (pdu->params[0]) {
+ case AVRCP_EVENT_PLAYBACK_STATUS_CHANGED:
+ len = 2;
+ if (control->mp) {
+ mp_get_playback_status(control->mp, &status,
+ NULL, NULL);
+ pdu->params[1] = status;
+ } else {
+ pdu->params[1] = PLAY_STATUS_ERROR;
+ }
+
+ break;
+ case AVRCP_EVENT_TRACK_CHANGED:
+ len = 9;
+
+ if (!control->mp)
+ memset(&pdu->params[1], 0xFF, 8);
+ else
+ memset(&pdu->params[1], 0, 8);
+
+ break;
+ default:
+ /* All other events are not supported yet */
+ goto err;
+ }
+
+ /* Register event */
+ control->registered_events |= (1 << pdu->params[0]);
+
+ pdu->params_len = htons(len);
+
+ return len;
+
+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,
avrcp->code = CTYPE_STABLE;
break;
+ case AVRCP_REGISTER_NOTIFICATION:
+ if (avrcp->code != CTYPE_NOTIFY) {
+ pdu->params[0] = E_INVALID_COMMAND;
+ goto err_metadata;
+ }
+
+ len = avrcp_handle_register_notification(control, pdu);
+ if (len < 0)
+ goto err_metadata;
+
+ avrcp->code = CTYPE_INTERIM;
+
+ break;
default:
/* Invalid pdu_id */
pdu->params[0] = E_INVALID_COMMAND;