avrcp: set addressed player, get total num items

This commit is contained in:
Milanka Ringwald 2018-02-06 14:09:47 +01:00
parent 73fba53895
commit 864d08b05a
6 changed files with 90 additions and 38 deletions

View File

@ -110,7 +110,7 @@ typedef enum {
AVRCP_MEDIA_ATTR_ARTIST, AVRCP_MEDIA_ATTR_ARTIST,
AVRCP_MEDIA_ATTR_ALBUM, AVRCP_MEDIA_ATTR_ALBUM,
AVRCP_MEDIA_ATTR_TRACK, AVRCP_MEDIA_ATTR_TRACK,
AVRCP_MEDIA_ATTR_TOTAL_TRACKS, AVRCP_MEDIA_ATTR_TOTAL_NUM_ITEMS,
AVRCP_MEDIA_ATTR_GENRE, AVRCP_MEDIA_ATTR_GENRE,
AVRCP_MEDIA_ATTR_SONG_LENGTH_MS, AVRCP_MEDIA_ATTR_SONG_LENGTH_MS,
AVRCP_MEDIA_ATTR_NONE = 0xFFFFFFFF AVRCP_MEDIA_ATTR_NONE = 0xFFFFFFFF
@ -130,7 +130,9 @@ typedef enum {
AVRCP_PDU_ID_SET_BROWSED_PLAYER = 0x70, AVRCP_PDU_ID_SET_BROWSED_PLAYER = 0x70,
AVRCP_PDU_ID_GET_FOLDER_ITEMS = 0x71, AVRCP_PDU_ID_GET_FOLDER_ITEMS = 0x71,
AVRCP_PDU_ID_CHANGE_PATH = 0x72, AVRCP_PDU_ID_CHANGE_PATH = 0x72,
AVRCP_PDU_ID_GET_ITEM_ATTRIBUTES = 0x73,
AVRCP_PDU_ID_PLAY_ITEM = 0x74, AVRCP_PDU_ID_PLAY_ITEM = 0x74,
AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS = 0x75,
AVRCP_PDU_ID_SEARCH = 0x80, AVRCP_PDU_ID_SEARCH = 0x80,
AVRCP_PDU_ID_UNDEFINED = 0xFF AVRCP_PDU_ID_UNDEFINED = 0xFF
} avrcp_pdu_id_t; } avrcp_pdu_id_t;
@ -305,10 +307,7 @@ typedef struct {
l2cap_ertm_config_t ertm_config; l2cap_ertm_config_t ertm_config;
// players // players
uint8_t set_addressed_player_id;
uint8_t set_browsed_player_id; uint8_t set_browsed_player_id;
uint16_t addressed_player_id;
uint16_t browsed_player_id; uint16_t browsed_player_id;
uint16_t browsed_player_uid_counter; uint16_t browsed_player_uid_counter;
@ -330,6 +329,10 @@ typedef struct {
uint8_t search_str[20]; uint8_t search_str[20];
uint8_t search; uint8_t search;
// get_item_attributes
uint8_t get_total_nr_items;
avrcp_browsing_scope_t get_total_nr_items_scope;
// fragmentation // fragmentation
uint8_t fragmented; uint8_t fragmented;
avrcp_pdu_id_t fragmented_pdu_id; avrcp_pdu_id_t fragmented_pdu_id;

View File

@ -360,8 +360,8 @@ static int avrcp_browsing_controller_send_set_browsed_player_cmd(uint16_t cid, a
return l2cap_send(cid, command, pos); return l2cap_send(cid, command, pos);
} }
static int avrcp_browsing_controller_send_set_addressed_player_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ static int avrcp_browsing_controller_send_get_total_nr_items_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){
uint8_t command[100]; uint8_t command[7];
int pos = 0; int pos = 0;
// transport header // transport header
// Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) // 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) // Profile IDentifier (PID)
command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8;
command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 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); big_endian_store_16(command, pos, 1);
pos += 2;
big_endian_store_16(command, pos, connection->addressed_player_id);
pos += 2; pos += 2;
command[pos++] = connection->get_total_nr_items_scope;
return l2cap_send(cid, command, pos); return l2cap_send(cid, command, pos);
} }
@ -388,10 +387,10 @@ static void avrcp_browsing_controller_handle_can_send_now(avrcp_browsing_connect
break; break;
} }
if (connection->set_addressed_player_id){ if (connection->get_total_nr_items){
connection->state = AVCTP_W2_RECEIVE_RESPONSE; connection->state = AVCTP_W2_RECEIVE_RESPONSE;
connection->set_addressed_player_id = 0; connection->get_total_nr_items = 0;
avrcp_browsing_controller_send_set_addressed_player_cmd(connection->l2cap_browsing_cid, connection); avrcp_browsing_controller_send_get_total_nr_items_cmd(connection->l2cap_browsing_cid, connection);
break; break;
} }
@ -495,6 +494,12 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER: case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER:
printf("AVRCP_PDU_ID_SET_ADDRESSED_PLAYER \n"); printf("AVRCP_PDU_ID_SET_ADDRESSED_PLAYER \n");
break; 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:{ case AVRCP_PDU_ID_SET_BROWSED_PLAYER:{
browsing_connection->browsed_player_uid_counter = uid_counter; browsing_connection->browsed_player_uid_counter = uid_counter;
// uint32_t num_items = big_endian_read_32(packet, pos); // 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; 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. * @brief Retrieve a listing of the contents of a folder.
* @param direction 0-folder up, 1-folder down * @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); memcpy(connection->search_str, search_str, connection->search_str_len);
avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid);
return ERROR_CODE_SUCCESS; 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;
} }

View File

@ -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); uint8_t avrcp_browsing_controller_set_browsed_player(uint16_t avrcp_browsing_cid, uint16_t browsed_player_id);
/** /**
* @brief Set addressed player. * @brief Get total num attributes
* @param avrcp_browsing_cid * @param scope
* @param addressed_player_id
*/ */
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. * @brief Navigate one level up or down in thhe virtual filesystem. Requires that s browsed player is set.

View File

@ -283,7 +283,7 @@ static void avrcp_controller_emit_now_playing_info_event(btstack_packet_handler_
event[pos++] = 0; event[pos++] = 0;
} }
break; 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; event[subevent_type_pos] = AVRCP_SUBEVENT_NOW_PLAYING_TOTAL_TRACKS_INFO;
if (value){ if (value){
event[pos++] = btstack_atoi((char *)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; 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){ 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); avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context);

View File

@ -294,6 +294,15 @@ uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t
* @return status * @return status
**/ **/
uint8_t avrcp_controller_play_item(uint16_t avrcp_cid, avrcp_browsing_scope_t scope, uint8_t * uid, uint16_t uid_counter); 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 */ /* API_END */
// Used by AVRCP controller and AVRCP browsing controller // Used by AVRCP controller and AVRCP browsing controller

View File

@ -209,7 +209,7 @@ static int avrcp_target_send_now_playing_info(uint16_t cid, avrcp_connection_t *
fragmented = 1; fragmented = 1;
connection->attribute_value_offset = 0; connection->attribute_value_offset = 0;
break; 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; num_bytes_to_write = AVRCP_ATTR_HEADER_LEN + MAX_NUMBER_ATTR_LEN;
if (num_free_bytes >= num_bytes_to_write){ 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); num_written_bytes = avrcp_target_pack_single_element_attribute_number(packet, pos, attr_id, connection->total_tracks);