From 1270af140e27f629bf1c5ea0af4b72146ba239f1 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Mon, 6 Feb 2017 16:54:38 +0100 Subject: [PATCH] avrcp: get play status --- test/avrcp/avrcp.c | 70 ++++++++++++++++++++++++++++++++++++++--- test/avrcp/avrcp.h | 33 +++++++++++++++++++ test/avrcp/avrcp_test.c | 13 ++++++-- 3 files changed, 108 insertions(+), 8 deletions(-) diff --git a/test/avrcp/avrcp.c b/test/avrcp/avrcp.c index d6accb713..552eaf3c4 100644 --- a/test/avrcp/avrcp.c +++ b/test/avrcp/avrcp.c @@ -412,7 +412,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec avrcp_subunit_type_t subunit_type; avrcp_subunit_type_t subunit_id; - uint8_t operands[5]; + uint8_t operands[20]; uint8_t opcode; uint8_t value; int pos = 0; @@ -448,10 +448,48 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec break; } case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: + ctype = packet[pos++]; + value = packet[pos++]; + subunit_type = value >> 3; + subunit_id = value & 0x07; + opcode = packet[pos++]; + + if (size - pos < 7) { + log_error("avrcp: wrong packet size"); + return; + }; + // operands: + memcpy(operands, packet+pos, 7); + pos += 7; + // uint32_t company_id = operands[0] << 16 | operands[1] << 8 | operands[2]; + uint8_t pdu_id = operands[3]; + // uint8_t unit_type = operands[4] >> 3; + // uint8_t unit = operands[4] & 0x07; + uint16_t param_length = big_endian_read_16(operands, 5); + + // printf(" VENDOR DEPENDENT response: ctype 0x%02x (0C), subunit_type 0x%02x (1F), subunit_id 0x%02x (07), opcode 0x%02x (30), unit_type 0x%02x, unit %d, company_id 0x%06x\n", + // ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id ); + + printf(" VENDOR DEPENDENT response: pdu id 0x%02x, param_length %d\n", pdu_id, param_length); + switch (pdu_id){ + case AVRCP_PDU_ID_GET_PLAY_STATUS:{ + uint32_t song_length = big_endian_read_32(packet, pos); + pos += 32; + uint32_t song_position = big_endian_read_32(packet, pos); + pos += 32; + uint8_t status = packet[pos]; + printf_hexdump(packet+pos, size - pos); + printf(" GET_PLAY_STATUS length 0x%04X, position 0x%04X, status %d\n", song_length, song_position, status); + break; + } + default: + break; + } break; case AVRCP_CMD_OPCODE_PASS_THROUGH: if (connection->state == AVCTP_W2_SEND_RELEASE_COMMAND){ request_pass_through_release_control_cmd(connection); + break; } break; default: @@ -613,7 +651,7 @@ void avrcp_unit_info(uint16_t con_handle){ void avrcp_get_capabilities(uint16_t con_handle){ avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle); if (!connection){ - log_error("avrcp_unit_info: coud not find a connection."); + log_error("avrcp_get_capabilities: coud not find a connection."); return; } if (connection->state != AVCTP_CONNECTION_OPENED) return; @@ -625,7 +663,7 @@ void avrcp_get_capabilities(uint16_t con_handle){ connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; connection->subunit_id = 0; big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); - connection->cmd_operands[3] = 0x10; + connection->cmd_operands[3] = AVRCP_PDU_ID_GET_CAPABILITIES; // PDU ID connection->cmd_operands[4] = 0; big_endian_store_16(connection->cmd_operands, 5, 1); connection->cmd_operands[7] = 0x02; @@ -661,7 +699,7 @@ void avrcp_start_rewind(uint16_t con_handle){ void avrcp_stop_rewind(uint16_t con_handle){ avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle); if (!connection){ - log_error("avrcp_unit_info: coud not find a connection."); + log_error("avrcp_stop_rewind: coud not find a connection."); return; } if (connection->state != AVCTP_W4_STOP) return; @@ -675,9 +713,31 @@ void avrcp_start_fast_forward(uint16_t con_handle){ void avrcp_stop_fast_forward(uint16_t con_handle){ avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle); if (!connection){ - log_error("avrcp_unit_info: coud not find a connection."); + log_error("avrcp_stop_fast_forward: coud not find a connection."); return; } if (connection->state != AVCTP_W4_STOP) return; request_pass_through_release_control_cmd(connection); } + +void avrcp_get_play_status(uint16_t con_handle){ + avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle); + if (!connection){ + log_error("avrcp_get_play_status: coud not find a connection."); + return; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return; + connection->state = AVCTP_W2_SEND_COMMAND; + + connection->transaction_label++; + connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + connection->command_type = AVRCP_CTYPE_STATUS; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = 0; + big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); + connection->cmd_operands[3] = AVRCP_PDU_ID_GET_PLAY_STATUS; + connection->cmd_operands[4] = 0; // reserved(upper 6) | packet_type -> 0 + big_endian_store_16(connection->cmd_operands, 5, 0); // parameter length + connection->cmd_operands_lenght = 7; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); +} diff --git a/test/avrcp/avrcp.h b/test/avrcp/avrcp.h index 54b05b507..6bfb63b12 100644 --- a/test/avrcp/avrcp.h +++ b/test/avrcp/avrcp.h @@ -53,6 +53,23 @@ extern "C" { #define BT_SIG_COMPANY_ID 0x001958 /* API_START */ + + +typedef enum { + AVRCP_PDU_ID_GET_CAPABILITIES = 0x10, + AVRCP_PDU_ID_GET_PLAY_STATUS = 0x30, + AVRCP_PDU_ID_REGISTER_NOTIFICATION = 0x31 +} avrcp_pdu_id_t; + +typedef enum { + AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED , + AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED, + AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED, + AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED, + AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED, + AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED +} avrcp_notification_event_t; + typedef enum { AVRCP_CTYPE_CONTROL = 0, AVRCP_CTYPE_STATUS, @@ -153,6 +170,15 @@ typedef struct { btstack_timer_source_t press_and_hold_cmd_timer; } avrcp_connection_t; + typedef enum { + AVRCP_PLAY_STATUS_STOPPED = 0x00, + AVRCP_PLAY_STATUS_PLAYING, + AVRCP_PLAY_STATUS_PAUSED, + AVRCP_PLAY_STATUS_FWD_SEEK, + AVRCP_PLAY_STATUS_REV_SEEK, + AVRCP_PLAY_STATUS_ERROR = 0xFF + } avrcp_play_status_t; + /** * @brief AVDTP Sink service record. * @param service @@ -250,6 +276,13 @@ void avrcp_forward(uint16_t con_handle); void avrcp_backward(uint16_t con_handle); +/** + * @brief Get play status. Returns event of type AVRCP_SUBEVENT_PLAY_STATUS (length, position, play_status). + * If TG does not support SongLength And SongPosition on TG, then TG shall return 0xFFFFFFFF. + * @param con_handle + */ +void avrcp_get_play_status(uint16_t con_handle); + /** * @brief Register notification. * - EVENT_PLAYBACK_STATUS_CHANGED diff --git a/test/avrcp/avrcp_test.c b/test/avrcp/avrcp_test.c index 5b3ca74c8..10acb635e 100644 --- a/test/avrcp/avrcp_test.c +++ b/test/avrcp/avrcp_test.c @@ -61,11 +61,12 @@ static btstack_packet_callback_registration_t hci_event_callback_registration; // mac 2013: static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15}; // phone: static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15}; -static bd_addr_t remote = {0xD8, 0xBB, 0x2C, 0xDF, 0xF1, 0x08}; +// static bd_addr_t remote = {0xD8, 0xBB, 0x2C, 0xDF, 0xF1, 0x08}; + static uint16_t con_handle = 0; static uint8_t sdp_avrcp_controller_service_buffer[150]; - +static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15}; static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); UNUSED(size); @@ -91,6 +92,9 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe printf("AVRCP_SUBEVENT_CONNECTION_RELEASED: con_handle 0x%02x\n", avrcp_subevent_connection_closed_get_con_handle(packet)); con_handle = 0; break; + // case AVRCP_SUBEVENT_PLAY_STATUS: + // printf("AVRCP_SUBEVENT_PLAY_STATUS\n"); + // break; default: printf("--- avrcp_test: Not implemented\n"); break; @@ -123,6 +127,7 @@ static void show_usage(void){ printf("R - avrcp_stop_rewind\n"); printf("f - avrcp_forward\n"); printf("b - avrcp_backward\n"); + printf("S - get play status\n"); printf("Ctrl-c - exit\n"); printf("---\n"); } @@ -170,7 +175,9 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac case 'b': avrcp_backward(con_handle); break; - + case 'S': + avrcp_get_play_status(con_handle); + break; default: show_usage(); break;