From 864d08b05a7d11fcb7b1b1bcd2b404914cdab7ee Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Tue, 6 Feb 2018 14:09:47 +0100 Subject: [PATCH] avrcp: set addressed player, get total num items --- src/classic/avrcp.h | 11 +++-- src/classic/avrcp_browsing_controller.c | 66 ++++++++++++++----------- src/classic/avrcp_browsing_controller.h | 7 ++- src/classic/avrcp_controller.c | 33 ++++++++++++- src/classic/avrcp_controller.h | 9 ++++ src/classic/avrcp_target.c | 2 +- 6 files changed, 90 insertions(+), 38 deletions(-) diff --git a/src/classic/avrcp.h b/src/classic/avrcp.h index 5688ec4bf..c9cb84287 100644 --- a/src/classic/avrcp.h +++ b/src/classic/avrcp.h @@ -110,7 +110,7 @@ typedef enum { AVRCP_MEDIA_ATTR_ARTIST, AVRCP_MEDIA_ATTR_ALBUM, AVRCP_MEDIA_ATTR_TRACK, - AVRCP_MEDIA_ATTR_TOTAL_TRACKS, + AVRCP_MEDIA_ATTR_TOTAL_NUM_ITEMS, AVRCP_MEDIA_ATTR_GENRE, AVRCP_MEDIA_ATTR_SONG_LENGTH_MS, AVRCP_MEDIA_ATTR_NONE = 0xFFFFFFFF @@ -130,7 +130,9 @@ typedef enum { AVRCP_PDU_ID_SET_BROWSED_PLAYER = 0x70, AVRCP_PDU_ID_GET_FOLDER_ITEMS = 0x71, AVRCP_PDU_ID_CHANGE_PATH = 0x72, + AVRCP_PDU_ID_GET_ITEM_ATTRIBUTES = 0x73, AVRCP_PDU_ID_PLAY_ITEM = 0x74, + AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS = 0x75, AVRCP_PDU_ID_SEARCH = 0x80, AVRCP_PDU_ID_UNDEFINED = 0xFF } avrcp_pdu_id_t; @@ -305,10 +307,7 @@ typedef struct { l2cap_ertm_config_t ertm_config; // players - uint8_t set_addressed_player_id; uint8_t set_browsed_player_id; - - uint16_t addressed_player_id; uint16_t browsed_player_id; uint16_t browsed_player_uid_counter; @@ -330,6 +329,10 @@ typedef struct { uint8_t search_str[20]; uint8_t search; + // get_item_attributes + uint8_t get_total_nr_items; + avrcp_browsing_scope_t get_total_nr_items_scope; + // fragmentation uint8_t fragmented; avrcp_pdu_id_t fragmented_pdu_id; diff --git a/src/classic/avrcp_browsing_controller.c b/src/classic/avrcp_browsing_controller.c index f01edddd3..7a8544e96 100644 --- a/src/classic/avrcp_browsing_controller.c +++ b/src/classic/avrcp_browsing_controller.c @@ -360,8 +360,8 @@ static int avrcp_browsing_controller_send_set_browsed_player_cmd(uint16_t cid, a return l2cap_send(cid, command, pos); } -static int avrcp_browsing_controller_send_set_addressed_player_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ - uint8_t command[100]; +static int avrcp_browsing_controller_send_get_total_nr_items_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ + uint8_t command[7]; int pos = 0; // transport header // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) @@ -369,12 +369,11 @@ static int avrcp_browsing_controller_send_set_addressed_player_cmd(uint16_t cid, // Profile IDentifier (PID) command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; - command[pos++] = AVRCP_PDU_ID_SET_ADDRESSED_PLAYER; + command[pos++] = AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS; - big_endian_store_16(command, pos, 2); - pos += 2; - big_endian_store_16(command, pos, connection->addressed_player_id); + big_endian_store_16(command, pos, 1); pos += 2; + command[pos++] = connection->get_total_nr_items_scope; return l2cap_send(cid, command, pos); } @@ -388,10 +387,10 @@ static void avrcp_browsing_controller_handle_can_send_now(avrcp_browsing_connect break; } - if (connection->set_addressed_player_id){ + if (connection->get_total_nr_items){ connection->state = AVCTP_W2_RECEIVE_RESPONSE; - connection->set_addressed_player_id = 0; - avrcp_browsing_controller_send_set_addressed_player_cmd(connection->l2cap_browsing_cid, connection); + connection->get_total_nr_items = 0; + avrcp_browsing_controller_send_get_total_nr_items_cmd(connection->l2cap_browsing_cid, connection); break; } @@ -495,6 +494,12 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16 case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER: printf("AVRCP_PDU_ID_SET_ADDRESSED_PLAYER \n"); break; + case AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS:{ + uint32_t num_items = big_endian_read_32(packet, pos); + pos += 4; + printf("TDO: send event, uid_counter %d, num_items %d\n", uid_counter, num_items); + break; + } case AVRCP_PDU_ID_SET_BROWSED_PLAYER:{ browsing_connection->browsed_player_uid_counter = uid_counter; // uint32_t num_items = big_endian_read_32(packet, pos); @@ -736,25 +741,6 @@ uint8_t avrcp_browsing_controller_set_browsed_player(uint16_t avrcp_browsing_cid return ERROR_CODE_SUCCESS; } -uint8_t avrcp_browsing_controller_set_addressed_player(uint16_t avrcp_browsing_cid, uint16_t addressed_player_id){ - avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid(avrcp_browsing_cid, &avrcp_controller_context); - if (!avrcp_connection){ - log_error("avrcp_browsing_controller_change_path: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - - avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; - if (!connection || connection->state != AVCTP_CONNECTION_OPENED){ - log_error("avrcp_browsing_controller_change_path: connection in wrong state."); - return ERROR_CODE_COMMAND_DISALLOWED; - } - - connection->set_addressed_player_id = 1; - connection->addressed_player_id = addressed_player_id; - avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); - return ERROR_CODE_SUCCESS; -} - /** * @brief Retrieve a listing of the contents of a folder. * @param direction 0-folder up, 1-folder down @@ -827,4 +813,28 @@ uint8_t avrcp_browsing_controller_search(uint16_t avrcp_browsing_cid, uint16_t s memcpy(connection->search_str, search_str, connection->search_str_len); avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); return ERROR_CODE_SUCCESS; +} + +uint8_t avrcp_browsing_controller_get_total_nr_items(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope){ + avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid(avrcp_browsing_cid, &avrcp_controller_context); + if (!avrcp_connection){ + log_error("avrcp_browsing_controller_change_path: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + + avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; + + if (!connection || connection->state != AVCTP_CONNECTION_OPENED){ + log_error("avrcp_browsing_controller_change_path: connection in wrong state."); + return ERROR_CODE_COMMAND_DISALLOWED; + } + + if (!connection->browsed_player_id){ + log_error("avrcp_browsing_controller_change_path: no browsed player set."); + return ERROR_CODE_COMMAND_DISALLOWED; + } + connection->get_total_nr_items = 1; + connection->get_total_nr_items_scope = scope; + avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); + return ERROR_CODE_SUCCESS; } \ No newline at end of file diff --git a/src/classic/avrcp_browsing_controller.h b/src/classic/avrcp_browsing_controller.h index 9c530502f..9a7b5215b 100644 --- a/src/classic/avrcp_browsing_controller.h +++ b/src/classic/avrcp_browsing_controller.h @@ -188,11 +188,10 @@ uint8_t avrcp_browsing_controller_browse_now_playing_list(uint16_t avrcp_browsin uint8_t avrcp_browsing_controller_set_browsed_player(uint16_t avrcp_browsing_cid, uint16_t browsed_player_id); /** - * @brief Set addressed player. - * @param avrcp_browsing_cid - * @param addressed_player_id + * @brief Get total num attributes + * @param scope */ -uint8_t avrcp_browsing_controller_set_addressed_player(uint16_t avrcp_browsing_cid, uint16_t addressed_player_id); +uint8_t avrcp_browsing_controller_get_total_nr_items(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope); /** * @brief Navigate one level up or down in thhe virtual filesystem. Requires that s browsed player is set. diff --git a/src/classic/avrcp_controller.c b/src/classic/avrcp_controller.c index cb32bcb65..e7f103001 100644 --- a/src/classic/avrcp_controller.c +++ b/src/classic/avrcp_controller.c @@ -283,7 +283,7 @@ static void avrcp_controller_emit_now_playing_info_event(btstack_packet_handler_ event[pos++] = 0; } break; - case AVRCP_MEDIA_ATTR_TOTAL_TRACKS: + case AVRCP_MEDIA_ATTR_TOTAL_NUM_ITEMS: event[subevent_type_pos] = AVRCP_SUBEVENT_NOW_PLAYING_TOTAL_TRACKS_INFO; if (value){ event[pos++] = btstack_atoi((char *)value); @@ -1034,6 +1034,37 @@ uint8_t avrcp_controller_disable_notification(uint16_t avrcp_cid, avrcp_notifica return ERROR_CODE_SUCCESS; } +uint8_t avrcp_controller_set_addressed_player(uint16_t avrcp_cid, uint16_t addressed_player_id){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_capabilities: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + connection->state = AVCTP_W2_SEND_COMMAND; + + connection->transaction_label++; + connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + connection->command_type = AVRCP_CTYPE_CONTROL; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + int pos = 0; + big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); + pos += 3; + connection->cmd_operands[pos++] = AVRCP_PDU_ID_SET_ADDRESSED_PLAYER; // PDU ID + connection->cmd_operands[pos++] = 0; + + // Parameter Length + big_endian_store_16(connection->cmd_operands, pos, 2); + pos += 2; + + big_endian_store_16(connection->cmd_operands, pos, addressed_player_id); + pos += 2; + + connection->cmd_operands_length = pos; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} uint8_t avrcp_controller_get_now_playing_info(uint16_t avrcp_cid){ avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); diff --git a/src/classic/avrcp_controller.h b/src/classic/avrcp_controller.h index 166782ced..3fd2593c8 100644 --- a/src/classic/avrcp_controller.h +++ b/src/classic/avrcp_controller.h @@ -294,6 +294,15 @@ uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t * @return status **/ uint8_t avrcp_controller_play_item(uint16_t avrcp_cid, avrcp_browsing_scope_t scope, uint8_t * uid, uint16_t uid_counter); + +/** + * @brief Set addressed player. + * @param avrcp_cid + * @param addressed_player_id + */ +uint8_t avrcp_controller_set_addressed_player(uint16_t avrcp_cid, uint16_t addressed_player_id); + + /* API_END */ // Used by AVRCP controller and AVRCP browsing controller diff --git a/src/classic/avrcp_target.c b/src/classic/avrcp_target.c index d7851c441..09ae1e82b 100644 --- a/src/classic/avrcp_target.c +++ b/src/classic/avrcp_target.c @@ -209,7 +209,7 @@ static int avrcp_target_send_now_playing_info(uint16_t cid, avrcp_connection_t * fragmented = 1; connection->attribute_value_offset = 0; break; - case AVRCP_MEDIA_ATTR_TOTAL_TRACKS: + case AVRCP_MEDIA_ATTR_TOTAL_NUM_ITEMS: num_bytes_to_write = AVRCP_ATTR_HEADER_LEN + MAX_NUMBER_ATTR_LEN; if (num_free_bytes >= num_bytes_to_write){ num_written_bytes = avrcp_target_pack_single_element_attribute_number(packet, pos, attr_id, connection->total_tracks);