From 0b578d060f4cb93103d2b8df7acbb3c77291858e Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Fri, 21 May 2021 16:20:44 +0200 Subject: [PATCH] avrcp: add all operation IDs, accept all valid operation IDs --- src/classic/avrcp.c | 10 +++--- src/classic/avrcp.h | 60 +++++++++++++++++++++++++++++--- src/classic/avrcp_target.c | 71 ++++++++++++++++++++------------------ 3 files changed, 99 insertions(+), 42 deletions(-) diff --git a/src/classic/avrcp.c b/src/classic/avrcp.c index 32cbe436f..ac943dc40 100644 --- a/src/classic/avrcp.c +++ b/src/classic/avrcp.c @@ -111,19 +111,19 @@ const char * avrcp_event2str(uint16_t index){ } static const char * avrcp_operation_name[] = { - NULL, // 0x3B "SKIP", NULL, NULL, NULL, NULL, "VOLUME_UP", "VOLUME_DOWN", "MUTE", "PLAY", "STOP", "PAUSE", NULL, "REWIND", "FAST_FORWARD", NULL, "FORWARD", "BACKWARD" // 0x4C }; -const char * avrcp_operation2str(uint8_t index){ + +const char * avrcp_operation2str(uint8_t operation_id){ char * name = NULL; - if ((index >= 0x3B) && (index <= 0x4C)){ - name = (char *)avrcp_operation_name[index - 0x3B]; + if ((operation_id >= AVRCP_OPERATION_ID_SKIP) && (operation_id <= AVRCP_OPERATION_ID_BACKWARD)){ + name = (char *)avrcp_operation_name[operation_id - AVRCP_OPERATION_ID_SKIP]; } if (name == NULL){ static char buffer[13]; - snprintf(buffer, sizeof(buffer), "Unknown 0x%02x", index); + snprintf(buffer, sizeof(buffer), "Unknown 0x%02x", operation_id); buffer[sizeof(buffer)-1] = 0; return buffer; } else { diff --git a/src/classic/avrcp.h b/src/classic/avrcp.h index 3b954fa7f..ea8da3b07 100644 --- a/src/classic/avrcp.h +++ b/src/classic/avrcp.h @@ -246,28 +246,80 @@ typedef enum { } avrcp_command_opcode_t; typedef enum { - AVRCP_OPERATION_ID_CHANNEL_UP = 0x30, - AVRCP_OPERATION_ID_CHANNEL_DOWN = 0x31, AVRCP_OPERATION_ID_SELECT = 0x00, AVRCP_OPERATION_ID_UP = 0x01, AVRCP_OPERATION_ID_DOWN = 0x02, AVRCP_OPERATION_ID_LEFT = 0x03, AVRCP_OPERATION_ID_RIGHT = 0x04, + AVRCP_OPERATION_ID_RIGHT_UP = 0x05, + AVRCP_OPERATION_ID_RIGHT_DOWN = 0x06, + AVRCP_OPERATION_ID_LEFT_UP = 0x07, + AVRCP_OPERATION_ID_LEFT_DOWN = 0x07, AVRCP_OPERATION_ID_ROOT_MENU = 0x09, + AVRCP_OPERATION_ID_SETUP_MENU = 0x0A, + AVRCP_OPERATION_ID_CONTENTS_MENU = 0x0B, + AVRCP_OPERATION_ID_FAVORITE_MENU = 0x0C, + AVRCP_OPERATION_ID_EXIT = 0x0D, + AVRCP_OPERATION_ID_RESERVED_1 = 0x0E, + + AVRCP_OPERATION_ID_0 = 0x20, + AVRCP_OPERATION_ID_1 = 0x21, + AVRCP_OPERATION_ID_2 = 0x22, + AVRCP_OPERATION_ID_3 = 0x23, + AVRCP_OPERATION_ID_4 = 0x24, + AVRCP_OPERATION_ID_5 = 0x25, + AVRCP_OPERATION_ID_6 = 0x26, + AVRCP_OPERATION_ID_7 = 0x27, + AVRCP_OPERATION_ID_8 = 0x28, + AVRCP_OPERATION_ID_9 = 0x29, + AVRCP_OPERATION_ID_DOT = 0x2A, + AVRCP_OPERATION_ID_ENTER = 0x2B, + AVRCP_OPERATION_ID_CLEAR = 0x2C, + + AVRCP_OPERATION_ID_RESERVED_2 = 0x2D, + + AVRCP_OPERATION_ID_CHANNEL_UP = 0x30, + AVRCP_OPERATION_ID_CHANNEL_DOWN = 0x31, + AVRCP_OPERATION_ID_PREVIOUS_CHANNEL = 0x32, + AVRCP_OPERATION_ID_SOUND_SELECT = 0x33, + AVRCP_OPERATION_ID_INPUT_SELECT = 0x34, + AVRCP_OPERATION_ID_DISPLAY_INFORMATION = 0x35, + AVRCP_OPERATION_ID_HELP = 0x36, + AVRCP_OPERATION_ID_PAGE_UP = 0x37, + AVRCP_OPERATION_ID_PAGE_DOWN = 0x38, + + AVRCP_OPERATION_ID_RESERVED_3 = 0x39, + AVRCP_OPERATION_ID_SKIP = 0x3C, + + AVRCP_OPERATION_ID_POWER = 0x40, AVRCP_OPERATION_ID_VOLUME_UP = 0x41, AVRCP_OPERATION_ID_VOLUME_DOWN = 0x42, AVRCP_OPERATION_ID_MUTE = 0x43, - AVRCP_OPERATION_ID_PLAY = 0x44, AVRCP_OPERATION_ID_STOP = 0x45, AVRCP_OPERATION_ID_PAUSE = 0x46, + AVRCP_OPERATION_ID_RECORD = 0x47, AVRCP_OPERATION_ID_REWIND = 0x48, AVRCP_OPERATION_ID_FAST_FORWARD = 0x49, + AVRCP_OPERATION_ID_EJECT = 0x4A, AVRCP_OPERATION_ID_FORWARD = 0x4B, AVRCP_OPERATION_ID_BACKWARD = 0x4C, - AVRCP_OPERATION_ID_UNDEFINED = 0xFF + + AVRCP_OPERATION_ID_RESERVED_4 = 0x4D, + + AVRCP_OPERATION_ID_ANGLE = 0x50, + AVRCP_OPERATION_ID_SUBPICTURE = 0x51, + + AVRCP_OPERATION_ID_RESERVED_5 = 0x3D, + + AVRCP_OPERATION_ID_F1 = 0xF1, + AVRCP_OPERATION_ID_F2 = 0xF2, + AVRCP_OPERATION_ID_F3 = 0xF3, + AVRCP_OPERATION_ID_F4 = 0xF4, + AVRCP_OPERATION_ID_F5 = 0xF5, + AVRCP_OPERATION_ID_RESERVED_6 = 0xF7 } avrcp_operation_id_t; typedef enum{ diff --git a/src/classic/avrcp_target.c b/src/classic/avrcp_target.c index a4a555cca..8819db08a 100644 --- a/src/classic/avrcp_target.c +++ b/src/classic/avrcp_target.c @@ -741,6 +741,33 @@ static uint8_t avrcp_target_get_transaction_label_for_notification(avrcp_connect return connection->notifications_transaction_label[notification]; } +static bool avcrp_operation_id_is_valid(avrcp_operation_id_t operation_id){ + if (operation_id < AVRCP_OPERATION_ID_RESERVED_1) return true; + + if (operation_id < AVRCP_OPERATION_ID_0) return false; + if (operation_id < AVRCP_OPERATION_ID_RESERVED_2) return true; + + if (operation_id < AVRCP_OPERATION_ID_CHANNEL_UP) return false; + if (operation_id < AVRCP_OPERATION_ID_RESERVED_3) return true; + + if (operation_id < AVRCP_OPERATION_ID_CHANNEL_UP) return false; + if (operation_id < AVRCP_OPERATION_ID_RESERVED_3) return true; + + if (operation_id < AVRCP_OPERATION_ID_SKIP) return false; + if (operation_id == AVRCP_OPERATION_ID_SKIP) return true; + + if (operation_id < AVRCP_OPERATION_ID_POWER) return false; + if (operation_id < AVRCP_OPERATION_ID_RESERVED_4) return true; + + if (operation_id < AVRCP_OPERATION_ID_ANGLE) return false; + if (operation_id < AVRCP_OPERATION_ID_RESERVED_5) return true; + + if (operation_id < AVRCP_OPERATION_ID_F1) return false; + if (operation_id < AVRCP_OPERATION_ID_RESERVED_6) return true; + + return false; +} + static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){ if (size < 6u) return; @@ -790,6 +817,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec avrcp_pdu_id_t pdu_id; connection->cmd_operands_length = 0; uint8_t offset; + uint8_t operand; switch (opcode){ case AVRCP_CMD_OPCODE_UNIT_INFO: @@ -804,49 +832,26 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec avrcp_target_subunit_info(connection, offset); break; - case AVRCP_CMD_OPCODE_PASS_THROUGH:{ + case AVRCP_CMD_OPCODE_PASS_THROUGH: if (size < 8) return; log_info("AVRCP_OPERATION_ID 0x%02x, operands length %d", packet[6], packet[7]); avrcp_operation_id_t operation_id = (avrcp_operation_id_t) (packet[6] & 0x7f); - bool button_pressed = (packet[6] & 0x80) == 0; - uint8_t operand = 0; + operand = 0; if ((packet[7] >= 1) && (size >= 9)){ operand = packet[8]; } - switch (operation_id){ - case AVRCP_OPERATION_ID_PLAY: - case AVRCP_OPERATION_ID_PAUSE: - case AVRCP_OPERATION_ID_STOP: - case AVRCP_OPERATION_ID_VOLUME_UP: - case AVRCP_OPERATION_ID_VOLUME_DOWN: - case AVRCP_OPERATION_ID_REWIND: - case AVRCP_OPERATION_ID_FAST_FORWARD: - case AVRCP_OPERATION_ID_FORWARD: - case AVRCP_OPERATION_ID_BACKWARD: - case AVRCP_OPERATION_ID_SKIP: - case AVRCP_OPERATION_ID_MUTE: - case AVRCP_OPERATION_ID_CHANNEL_UP: - case AVRCP_OPERATION_ID_CHANNEL_DOWN: - case AVRCP_OPERATION_ID_SELECT: - case AVRCP_OPERATION_ID_UP: - case AVRCP_OPERATION_ID_DOWN: - case AVRCP_OPERATION_ID_LEFT: - case AVRCP_OPERATION_ID_RIGHT: - case AVRCP_OPERATION_ID_ROOT_MENU: - avrcp_target_operation_accepted(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand); - avrcp_target_emit_operation(avrcp_target_context.avrcp_callback, connection->avrcp_cid, + if (avcrp_operation_id_is_valid(operation_id)){ + bool button_pressed = (packet[6] & 0x80) == 0; + + avrcp_target_operation_accepted(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand); + avrcp_target_emit_operation(avrcp_target_context.avrcp_callback, connection->avrcp_cid, operation_id, button_pressed, packet[7], operand); - break; - case AVRCP_OPERATION_ID_UNDEFINED: - avrcp_target_operation_not_implemented(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand); - return; - default: - avrcp_target_operation_not_implemented(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand); - return; + } else { + avrcp_target_operation_not_implemented(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand); } break; - } + case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: