2011-08-11 14:14:45

by David Stockwell

[permalink] [raw]
Subject: [PATCH 3/5] Add Passthrough signal to handle_panel_passthrough

Add Passthrough signal to handle_panel_passthrough,
rename avrcp->code to avrcp->ctype for consistency,
correct sense of Key State flag field.

Based on Release 4.96
---
audio/control.c | 121
+++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 99 insertions(+), 22 deletions(-)

diff --git a/audio/control.c b/audio/control.c
index 8ddcc10..472cab2 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -230,7 +230,7 @@ struct avctp_header {
#define AVCTP_HEADER_LENGTH 3

struct avrcp_header {
- uint8_t code:4;
+ uint8_t ctype:4;
uint8_t _hdr0:4;
uint8_t subunit_id:3;
uint8_t subunit_type:5;
@@ -261,7 +261,7 @@ struct avctp_header {

struct avrcp_header {
uint8_t _hdr0:4;
- uint8_t code:4;
+ uint8_t ctype:4;
uint8_t subunit_type:5;
uint8_t subunit_id:3;
uint8_t opcode;
@@ -551,6 +551,23 @@ static sdp_record_t *avrcp_tg_record(void)
return record;
}

+/**
+ * @brief get_company_id: Three-byte Company_ID from AVRCP message
+ *
+ * AVRCP uses three-byte company_ids, which must be converted from
+ * BT/network big-endian order to internal form.
+ */
+static gint32 get_company_id(unsigned char *cid)
+{
+ gint32 company_id = 0;
+ company_id = *cid;
+ company_id <<= 8;
+ company_id |= *(cid+1);
+ company_id <<= 8;
+ company_id |= *(cid+2);
+ return company_id;
+}
+
static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
{
struct uinput_event event;
@@ -572,17 +589,74 @@ static void send_key(int fd, uint16_t key, int pressed)
send_event(fd, EV_SYN, SYN_REPORT, 0);
}

+/**
+ * @brief: handle_panel_passthrough: Handles AVRCP 1.0+ PASSTHROUGH command.
+ *
+ * Original version only passed the keystroke to uinput.
+ *
+ * Added a Passthrough signal, with the key state AND the optional
+ * following company_id and vendor-unique message.
+ */
+
static void handle_panel_passthrough(struct control *control,
- const unsigned char *operands,
- int operand_count)
+ struct avrcp_passthru *avrcp,
+ int avrcp_length)
{
const char *status;
int pressed, i;
+ guchar key_pressed;
+ gboolean key_status;
+ gint32 pass_company_id;
+ gchar *pass_string;

- if (operand_count == 0)
+ if ((unsigned int) avrcp_length < sizeof(struct avrcp_passthru) - 5)
return;

- if (operands[0] & 0x80) {
+ /*
+ * Following creates the Passthrough signal.
+ * Key_state is zero if key is pressed (AVRCP v14r00 sect 22.3, p119)
+ */
+
+ key_pressed = avrcp->key;
+ key_status = !avrcp->key_state;
+ DBG("Passthrough Key: %x Pressed: %s",
+ key_pressed, key_status ? "true" : "false");
+ if (key_pressed == VENDOR_UNIQUE_OP) {
+ if ((unsigned int) avrcp_length >
+ sizeof(struct avrcp_passthru)) {
+ pass_company_id = get_company_id(avrcp->company_id);
+ pass_string = g_strndup((const char *) avrcp->op_data,
+ (gsize) avrcp->op_len - 3);
+ DBG("Passthrough Company_ID: %06X String: %s",
+ pass_company_id, pass_string);
+ } else if (avrcp_length == sizeof(struct avrcp_passthru)) {
+ pass_company_id = get_company_id(avrcp->company_id);
+ pass_string = (gchar *) g_malloc0(1);
+ DBG("Passthrough Company_ID: %06X String: <none>",
+ pass_company_id);
+ } else {
+ pass_company_id = -1;
+ pass_string = (gchar *) g_malloc0(1);
+ DBG("Passthrough: No Company_ID or String!");
+ };
+ } else {
+ pass_company_id = -1;
+ pass_string = (gchar *) g_malloc0(1);
+ };
+
+ g_dbus_emit_signal(control->dev->conn, control->dev->path,
+ AUDIO_CONTROL_INTERFACE, "Passthrough",
+ DBUS_TYPE_BYTE, &key_pressed,
+ DBUS_TYPE_BOOLEAN, &key_status,
+ DBUS_TYPE_INT32, &pass_company_id,
+ DBUS_TYPE_STRING, &pass_string,
+ DBUS_TYPE_INVALID);
+
+ g_free(pass_string);
+
+ /* From here on, we are doing the equivalent of "SendKeys" */
+
+ if (avrcp->key_state) {
status = "released";
pressed = 0;
} else {
@@ -593,7 +667,7 @@ static void handle_panel_passthrough(struct control
*control,
for (i = 0; key_map[i].name != NULL; i++) {
uint8_t key_quirks;

- if ((operands[0] & 0x7F) != key_map[i].avrcp)
+ if (avrcp->key != key_map[i].avrcp)
continue;

DBG("AVRCP: %s %s", key_map[i].name, status);
@@ -616,9 +690,12 @@ static void handle_panel_passthrough(struct control
*control,
break;
}

+ /* Note that the following will flag Vendor Dependent keypresses
+ and any others not in the key_map. However, this does not affect
+ the functionality. */
+
if (key_map[i].name == NULL)
- DBG("AVRCP: unknown button 0x%02X %s",
- operands[0] & 0x7F, status);
+ DBG("AVRCP: unknown button 0x%02X %s", avrcp->key, status);
}

/* handle vendordep pdu inside an avctp packet */
@@ -626,7 +703,7 @@ static int handle_vendordep_pdu(struct control *control,
struct avrcp_header *avrcp,
int operand_count)
{
- avrcp->code = CTYPE_NOT_IMPLEMENTED;
+ avrcp->ctype = CTYPE_NOT_IMPLEMENTED;
return AVRCP_HEADER_LENGTH;
}

@@ -760,37 +837,36 @@ static gboolean control_cb(GIOChannel *chan,
GIOCondition cond,

avrcp = (struct avrcp_header *) (buf + sizeof(struct avctp_header));

- ret -= sizeof(struct avrcp_header);
-
operands = buf + sizeof(struct avctp_header) + sizeof(struct
avrcp_header);
- operand_count = ret;
+ operand_count = ret - sizeof(struct avrcp_header);

DBG("AVRCP %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "
"opcode 0x%02X, %d operands",
avctp->cr ? "response" : "command",
- avrcp->code, avrcp->subunit_type, avrcp->subunit_id,
+ avrcp->ctype, avrcp->subunit_type, avrcp->subunit_id,
avrcp->opcode, operand_count);

if (avctp->packet_type != AVCTP_PACKET_SINGLE) {
avctp->cr = AVCTP_RESPONSE;
- avrcp->code = CTYPE_NOT_IMPLEMENTED;
+ avrcp->ctype = CTYPE_NOT_IMPLEMENTED;
} else if (avctp->pid != htons(AV_REMOTE_SVCLASS_ID)) {
avctp->ipid = 1;
avctp->cr = AVCTP_RESPONSE;
packet_size = sizeof(*avctp);
} else if (avctp->cr == AVCTP_COMMAND &&
- avrcp->code == CTYPE_CONTROL &&
+ avrcp->ctype == CTYPE_CONTROL &&
avrcp->subunit_type == SUBUNIT_PANEL &&
avrcp->opcode == OP_PASSTHROUGH) {
- handle_panel_passthrough(control, operands, operand_count);
+ handle_panel_passthrough(control,
+ (struct avrcp_passthru *) avrcp, ret);
avctp->cr = AVCTP_RESPONSE;
- avrcp->code = CTYPE_ACCEPTED;
+ avrcp->ctype = CTYPE_ACCEPTED;
} else if (avctp->cr == AVCTP_COMMAND &&
- avrcp->code == CTYPE_STATUS &&
+ avrcp->ctype == CTYPE_STATUS &&
(avrcp->opcode == OP_UNITINFO
|| avrcp->opcode == OP_SUBUNITINFO)) {
avctp->cr = AVCTP_RESPONSE;
- avrcp->code = CTYPE_STABLE;
+ avrcp->ctype = CTYPE_STABLE;
/* The first operand should be 0x07 for the UNITINFO response.
* Neither AVRCP (section 22.1, page 117) nor AVC Digital
* Interface Command Set (section 9.2.1, page 45) specs
@@ -810,7 +886,7 @@ static gboolean control_cb(GIOChannel *chan, GIOCondition
cond,
packet_size = AVCTP_HEADER_LENGTH + r_size;
} else {
avctp->cr = AVCTP_RESPONSE;
- avrcp->code = CTYPE_REJECTED;
+ avrcp->ctype = CTYPE_REJECTED;
}
ret = write(sock, buf, packet_size);
if (ret != packet_size)
@@ -1222,7 +1298,7 @@ static int avctp_send_passthrough(struct control
*control, uint8_t op)
avctp->cr = AVCTP_COMMAND;
avctp->pid = htons(AV_REMOTE_SVCLASS_ID);

- avrcp->code = CTYPE_CONTROL;
+ avrcp->ctype = CTYPE_CONTROL;
avrcp->subunit_type = SUBUNIT_PANEL;
avrcp->opcode = OP_PASSTHROUGH;

@@ -1324,6 +1400,7 @@ static GDBusSignalTable control_signals[] = {
{ "Connected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED},
{ "Disconnected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED},
{ "PropertyChanged", "sv" },
+ { "Passthrough", "ybis" },
{ NULL, NULL }
};

--
1.7.4.4