avrcp: fix reading packet type from vendor specific responses

This commit is contained in:
Milanka Ringwald 2020-11-17 14:26:12 +01:00
parent 2686781a2a
commit 619205264f
5 changed files with 55 additions and 18 deletions

View File

@ -132,6 +132,7 @@ typedef enum {
AVRCP_MEDIA_ATTR_GENRE,
AVRCP_MEDIA_ATTR_SONG_LENGTH_MS,
AVRCP_MEDIA_ATTR_DEFAULT_COVER_ART,
AVRCP_MEDIA_ATTR_RESERVED = 0x0009,
AVRCP_MEDIA_ATTR_NONE = 0x7FFF
} avrcp_media_attribute_id_t;

View File

@ -680,7 +680,8 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
uint16_t pos = 3;
uint8_t pdu_id;
uint8_t vendor_dependent_packet_type;
connection->last_confirmed_transaction_id = packet[0] >> 4;
avrcp_frame_type_t frame_type = (avrcp_frame_type_t)((packet[0] >> 1) & 0x01);
@ -741,8 +742,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
// Company ID (3)
pos += 3;
pdu_id = packet[pos++];
// packet type (1)
pos++;
vendor_dependent_packet_type = (avrcp_packet_type_t)(packet[pos++] & 0x03);
param_length = big_endian_read_16(packet, pos);
pos += 2;
log_info("operands length %d, remaining size %d", param_length, size - pos);
@ -916,31 +916,32 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
}
case AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES:{
switch (packet_type){
switch (vendor_dependent_packet_type){
case AVRCP_START_PACKET:
case AVRCP_SINGLE_PACKET:
avrcp_parser_reset(connection);
connection->list_size = param_length;
connection->num_attributes = packet[pos++];
avrcp_controller_parse_and_emit_element_attrs(packet+pos, size-pos, connection, ctype);
if (packet_type == AVRCP_START_PACKET){
if (vendor_dependent_packet_type == AVRCP_START_PACKET){
avrcp_controller_request_continue_response(connection);
}
break;
case AVRCP_CONTINUE_PACKET:
case AVRCP_END_PACKET:
connection->num_received_fragments++;
if (connection->num_received_fragments < connection->max_num_fragments){
avrcp_controller_parse_and_emit_element_attrs(packet+pos, size-pos, connection, ctype);
if (packet_type == AVRCP_CONTINUE_PACKET){
if (vendor_dependent_packet_type == AVRCP_CONTINUE_PACKET){
avrcp_controller_request_continue_response(connection);
}
}
} else {
avrcp_controller_request_abort_continuation(connection);
avrcp_controller_emit_now_playing_info_event_done(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, 1);
avrcp_parser_reset(connection);
avrcp_controller_request_abort_continuation(connection);
}
break;
default:
@ -1308,15 +1309,20 @@ uint8_t avrcp_controller_set_addressed_player(uint16_t avrcp_cid, uint16_t addre
return ERROR_CODE_SUCCESS;
}
uint8_t avrcp_controller_get_now_playing_info(uint16_t avrcp_cid){
uint8_t avrcp_controller_get_element_attributes(uint16_t avrcp_cid, uint8_t num_attributes, avrcp_media_attribute_id_t * attributes){
avrcp_connection_t * connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid);
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;
if (num_attributes >= AVRCP_MEDIA_ATTR_RESERVED) {
return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
}
connection->state = AVCTP_W2_SEND_COMMAND;
connection->transaction_id = avrcp_controller_get_next_transaction_label(connection);
connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
connection->command_type = AVRCP_CTYPE_STATUS;
@ -1336,14 +1342,24 @@ uint8_t avrcp_controller_get_now_playing_info(uint16_t avrcp_cid){
memset(connection->cmd_operands + pos, 0, 8); // identifier: PLAYING
pos += 8;
connection->cmd_operands[pos++] = 0; // attribute count, if 0 get all attributes
// every attribute is 4 bytes long
connection->cmd_operands[pos++] = num_attributes; // attribute count, if 0 get all attributes
int i;
for (i = 0; i < num_attributes; i++){
// every attribute is 4 bytes long
big_endian_store_32(connection->cmd_operands, pos, attributes[i]);
pos += 4;
}
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){
return avrcp_controller_get_element_attributes(avrcp_cid, 0, NULL);
}
uint8_t avrcp_controller_set_absolute_volume(uint16_t avrcp_cid, uint8_t volume){
avrcp_connection_t * connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid);
if (!connection){

View File

@ -238,7 +238,14 @@ uint8_t avrcp_controller_enable_notification(uint16_t avrcp_cid, avrcp_notificat
uint8_t avrcp_controller_disable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id);
/**
* @brief Get info on now playing media.
* @brief Get info on now playing media using subset of attribute IDs
* @param avrcp_cid
* @returns status
*/
uint8_t avrcp_controller_get_element_attributes(uint16_t avrcp_cid, uint8_t num_attributes, avrcp_media_attribute_id_t * attributes);
/**
* @brief Get info on now playing media using all IDs.
* @param avrcp_cid
* @returns status
*/

View File

@ -308,6 +308,10 @@ static uint8_t events[] = {
AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED
};
static avrcp_media_attribute_id_t now_playing_info_attributes [] = {
AVRCP_MEDIA_ATTR_TITLE
};
typedef struct {
uint8_t track_id[8];
uint32_t song_length_ms;
@ -865,6 +869,9 @@ static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channe
volume_percentage = avrcp_subevent_set_absolute_volume_response_get_absolute_volume(packet) * 100 / 127;
printf("absolute volume response %d %%\n", volume_percentage);
break;
case AVRCP_SUBEVENT_NOW_PLAYING_INFO_DONE:
printf("Playing info done with receiving\n");
break;
default:
printf("AVRCP controller: event not parsed 0x%02x\n", packet[2]);
break;
@ -1142,7 +1149,8 @@ static void show_usage(void){
printf("* - get subunit info\n");
printf("r - get play status\n");
printf("/ - get now playing info\n");
printf("$ - get TITLE of now playing song\n");
printf("01 - play\n");
printf("02 - pause\n");
printf("03 - stop\n");
@ -1328,6 +1336,11 @@ static void stdin_process(char * cmd, int size){
printf("AVRCP: get now playing info\n");
avrcp_controller_get_now_playing_info(avrcp_cid);
break;
case '$':
printf("AVRCP: get TITLE of now playing song\n");
avrcp_controller_get_element_attributes(avrcp_cid, sizeof(now_playing_info_attributes)/4, now_playing_info_attributes);
break;
case '0':
switch (cmd[1]){
case '1':

View File

@ -137,8 +137,8 @@ AVRCP/TG/PTT/BV-03-I : (Confirmation expected)
AVRCP/TG/PTT/BV-04-I : (Confirmation expected)
AVRCP/TG/PTT/BV-05-I : (Confirmation expected)
AVRCP/TG/RCR/BV-02-C : tl, (OK)
AVRCP/TG/RCR/BV-04-C : tl, (OK)
AVRCP/TG/RCR/BV-02-C : $
AVRCP/TG/RCR/BV-04-C : $
AVRCP/TG/VLH/BI-01-C : (wait)
AVRCP/TG/VLH/BI-02-C : (wait)