avrcp controller: use max num fragments to limit num fragments that the controller can accept

This commit is contained in:
Milanka Ringwald 2018-02-07 15:27:45 +01:00
parent 864d08b05a
commit 8b2b40348d
4 changed files with 50 additions and 22 deletions

View File

@ -373,6 +373,7 @@ static avrcp_connection_t * avrcp_create_connection(bd_addr_t remote_addr, avrcp
memset(connection, 0, sizeof(avrcp_connection_t));
connection->state = AVCTP_CONNECTION_IDLE;
connection->transaction_label = 0xFF;
connection->max_num_fragments = 0xFF;
connection->avrcp_cid = avrcp_get_next_cid();
memcpy(connection->remote_addr, remote_addr, 6);
btstack_linked_list_add(&context->connections, (btstack_linked_item_t *) connection);

View File

@ -55,7 +55,7 @@ extern "C" {
#define BT_SIG_COMPANY_ID 0x001958
#define AVRCP_MEDIA_ATTR_COUNT 7
#define AVRCP_MAX_ATTRIBUTTE_SIZE 100
#define AVRCP_MAX_ATTRIBUTTE_SIZE 5000
#define AVRCP_ATTRIBUTE_HEADER_LEN 8
#define AVRCP_MAX_FOLDER_NAME_SIZE 20
@ -285,10 +285,9 @@ typedef struct {
} avrcp_track_t;
typedef enum {
AVRCP_PARSER_IDLE = 0,
AVRCP_PARSER_GET_ATTRIBUTE_HEADER, // 8 bytes
AVRCP_PARSER_GET_ATTRIBUTE_HEADER = 0, // 8 bytes
AVRCP_PARSER_GET_ATTRIBUTE_VALUE,
AVRCP_PARSER_IGNORE_ATTRIBUTE_VALUE
AVRCP_PARSER_CONTINUE_GET_ATTRIBUTE_VALUE
} avrcp_parser_state_t;
// BROWSING
@ -342,7 +341,7 @@ typedef struct {
uint8_t item_type;
uint16_t item_length;
uint16_t fragment_size;
uint8_t fragment[100];
uint8_t fragment[AVRCP_MAX_ATTRIBUTTE_SIZE];
} avrcp_browsing_connection_t;
// BROWSING END
@ -422,6 +421,10 @@ typedef struct {
uint8_t num_attributes;
uint8_t num_parsed_attributes;
// PTS requires definition of max num fragments
uint8_t max_num_fragments;
uint8_t num_received_fragments;
} avrcp_connection_t;
typedef enum {

View File

@ -215,7 +215,8 @@ static void avrcp_parser_reset(avrcp_connection_t * connection){
connection->num_attributes = 0;
connection->num_parsed_attributes = 0;
connection->parser_attribute_header_pos = 0;
connection->parser_state = AVRCP_PARSER_IDLE;
connection->num_received_fragments = 0;
connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER;
}
static void avrcp_controller_emit_now_playing_info_event_done(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t ctype, uint8_t status){
@ -301,23 +302,24 @@ static void avrcp_controller_emit_now_playing_info_event(btstack_packet_handler_
static void avrcp_parser_process_byte(uint8_t byte, avrcp_connection_t * connection, avrcp_command_type_t ctype){
switch(connection->parser_state){
case AVRCP_PARSER_GET_ATTRIBUTE_HEADER:
case AVRCP_PARSER_GET_ATTRIBUTE_HEADER:{
if (connection->parser_attribute_header_pos < AVRCP_ATTRIBUTE_HEADER_LEN) {
connection->parser_attribute_header[connection->parser_attribute_header_pos++] = byte;
connection->list_offset++;
break;
}
connection->attribute_value_len = btstack_min(big_endian_read_16(connection->parser_attribute_header, 6), AVRCP_MAX_ATTRIBUTTE_SIZE );
// printf(" attr id %d, len to read %d, total len %d \n", big_endian_read_32(connection->parser_attribute_header, 0), connection->attribute_value_len, big_endian_read_16(connection->parser_attribute_header, 6));
uint16_t attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 6);
connection->attribute_value_len = btstack_min(attribute_total_value_len, AVRCP_MAX_ATTRIBUTTE_SIZE);
connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_VALUE;
break;
}
case AVRCP_PARSER_GET_ATTRIBUTE_VALUE:{
if (connection->attribute_value_offset < connection->attribute_value_len){
connection->attribute_value[connection->attribute_value_offset++] = byte;
connection->list_offset++;
break;
}
// TODO emit event
uint32_t attribute_id = big_endian_read_32(connection->parser_attribute_header, 0);
if (attribute_id > AVRCP_MEDIA_ATTR_NONE && attribute_id <= AVRCP_MEDIA_ATTR_SONG_LENGTH_MS){
avrcp_controller_emit_now_playing_info_event(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, attribute_id, connection->attribute_value, connection->attribute_value_len);
@ -325,7 +327,7 @@ static void avrcp_parser_process_byte(uint8_t byte, avrcp_connection_t * connect
if (connection->attribute_value_offset < big_endian_read_16(connection->parser_attribute_header, 6)){
// printf("parse until end of valuE, and ignore it\n");
connection->parser_state = AVRCP_PARSER_IGNORE_ATTRIBUTE_VALUE;
connection->parser_state = AVRCP_PARSER_CONTINUE_GET_ATTRIBUTE_VALUE;
break;
}
@ -339,7 +341,7 @@ static void avrcp_parser_process_byte(uint8_t byte, avrcp_connection_t * connect
connection->parser_attribute_header_pos = 0;
break;
}
case AVRCP_PARSER_IGNORE_ATTRIBUTE_VALUE:
case AVRCP_PARSER_CONTINUE_GET_ATTRIBUTE_VALUE:
if (connection->attribute_value_offset < big_endian_read_16(connection->parser_attribute_header, 6)){
connection->list_offset++;
connection->attribute_value_offset++;
@ -708,24 +710,27 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
avrcp_parser_reset(connection);
connection->list_size = param_length;
connection->num_attributes = packet[pos++];
// printf("AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES num_attributes %d, total size %d, packet type 0x%02x \n", connection->num_attributes, connection->list_size, operands[4] & 0x03);
connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER;
avrcp_source_parse_and_emit_element_attrs(packet+pos, size-pos, connection, ctype);
if (packet_type == AVRCP_START_PACKET){
if (connection->num_attributes == 1 && connection->parser_state == AVRCP_PARSER_IGNORE_ATTRIBUTE_VALUE){
avrcp_controller_request_abort_continuation(connection);
} else {
avrcp_controller_request_continue_response(connection);
}
avrcp_controller_request_continue_response(connection);
}
break;
case AVRCP_CONTINUE_PACKET:
avrcp_source_parse_and_emit_element_attrs(packet+pos, size-pos, connection, ctype);
avrcp_controller_request_continue_response(connection);
break;
case AVRCP_END_PACKET:
avrcp_source_parse_and_emit_element_attrs(packet+pos, size-pos, connection, ctype);
connection->num_received_fragments++;
if (connection->num_received_fragments < connection->max_num_fragments){
avrcp_source_parse_and_emit_element_attrs(packet+pos, size-pos, connection, ctype);
if (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);
}
break;
}
}
@ -1253,3 +1258,13 @@ uint8_t avrcp_controller_play_item(uint16_t avrcp_cid, avrcp_browsing_scope_t sc
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
return ERROR_CODE_SUCCESS;
}
uint8_t avrcp_controller_set_max_num_fragments(uint16_t avrcp_cid, uint8_t max_num_fragments){
avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context);
if (!connection){
log_error("avrcp_controller_play_item: could not find a connection.");
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
connection->max_num_fragments = max_num_fragments;
return ERROR_CODE_SUCCESS;
}

View File

@ -92,6 +92,15 @@ uint8_t avrcp_controller_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid);
*/
uint8_t avrcp_controller_disconnect(uint16_t avrcp_cid);
/**
* @brief Set max num fragments in whuch message can be transmited.
* @param avrcp_cid
* @param max_num_fragments
* @returns status
*/
uint8_t avrcp_controller_set_max_num_fragments(uint16_t avrcp_cid, uint8_t max_num_fragments);
/**
* @brief Unit info.
* @param avrcp_cid