avrcp browsing controller: fragmentation for get folder items

This commit is contained in:
Milanka Ringwald 2018-02-02 15:06:32 +01:00
parent eb3e114b6f
commit be65baf476
7 changed files with 213 additions and 89 deletions

View File

@ -1937,13 +1937,14 @@ typedef uint8_t sm_key_t[16];
/** /**
* @format 1211 * @format 12211
* @param subevent_code * @param subevent_code
* @param browsing_cid * @param browsing_cid
* @param uid_counter
* @param browsing_status * @param browsing_status
* @param bluetooth_status * @param bluetooth_status
*/ */
#define AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE 0x1E #define AVRCP_SUBEVENT_BROWSING_DONE 0x1E
/** /**

View File

@ -6216,31 +6216,40 @@ static inline uint16_t avrcp_subevent_browsing_connection_released_get_browsing_
} }
/** /**
* @brief Get field browsing_cid from event AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE * @brief Get field browsing_cid from event AVRCP_SUBEVENT_BROWSING_DONE
* @param event packet * @param event packet
* @return browsing_cid * @return browsing_cid
* @note: btstack_type 2 * @note: btstack_type 2
*/ */
static inline uint16_t avrcp_subevent_browsing_media_item_done_get_browsing_cid(const uint8_t * event){ static inline uint16_t avrcp_subevent_browsing_done_get_browsing_cid(const uint8_t * event){
return little_endian_read_16(event, 3); return little_endian_read_16(event, 3);
} }
/** /**
* @brief Get field browsing_status from event AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE * @brief Get field uid_counter from event AVRCP_SUBEVENT_BROWSING_DONE
* @param event packet
* @return uid_counter
* @note: btstack_type 2
*/
static inline uint16_t avrcp_subevent_browsing_done_get_uid_counter(const uint8_t * event){
return little_endian_read_16(event, 5);
}
/**
* @brief Get field browsing_status from event AVRCP_SUBEVENT_BROWSING_DONE
* @param event packet * @param event packet
* @return browsing_status * @return browsing_status
* @note: btstack_type 1 * @note: btstack_type 1
*/ */
static inline uint8_t avrcp_subevent_browsing_media_item_done_get_browsing_status(const uint8_t * event){ static inline uint8_t avrcp_subevent_browsing_done_get_browsing_status(const uint8_t * event){
return event[5]; return event[7];
} }
/** /**
* @brief Get field bluetooth_status from event AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE * @brief Get field bluetooth_status from event AVRCP_SUBEVENT_BROWSING_DONE
* @param event packet * @param event packet
* @return bluetooth_status * @return bluetooth_status
* @note: btstack_type 1 * @note: btstack_type 1
*/ */
static inline uint8_t avrcp_subevent_browsing_media_item_done_get_bluetooth_status(const uint8_t * event){ static inline uint8_t avrcp_subevent_browsing_done_get_bluetooth_status(const uint8_t * event){
return event[6]; return event[8];
} }
/** /**

View File

@ -57,6 +57,7 @@ extern "C" {
#define AVRCP_MEDIA_ATTR_COUNT 7 #define AVRCP_MEDIA_ATTR_COUNT 7
#define AVRCP_MAX_ATTRIBUTTE_SIZE 100 #define AVRCP_MAX_ATTRIBUTTE_SIZE 100
#define AVRCP_ATTRIBUTE_HEADER_LEN 8 #define AVRCP_ATTRIBUTE_HEADER_LEN 8
#define AVRCP_MAX_FOLDER_NAME_SIZE 20
typedef enum { typedef enum {
AVRCP_STATUS_INVALID_COMMAND = 0, // sent if TG received a PDU that it did not understand. AVRCP_STATUS_INVALID_COMMAND = 0, // sent if TG received a PDU that it did not understand.
@ -129,6 +130,7 @@ 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_PLAY_ITEM = 0x74,
AVRCP_PDU_ID_UNDEFINED = 0xFF AVRCP_PDU_ID_UNDEFINED = 0xFF
} avrcp_pdu_id_t; } avrcp_pdu_id_t;
@ -256,6 +258,13 @@ typedef enum {
AVCTP_W2_RECEIVE_RESPONSE AVCTP_W2_RECEIVE_RESPONSE
} avctp_connection_state_t; } avctp_connection_state_t;
typedef enum {
AVRCP_BROWSING_MEDIA_PLAYER_LIST = 0x00,
AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM,
AVRCP_BROWSING_SEARCH,
AVRCP_BROWSING_NOW_PLAYING
} avrcp_browsing_scope_t;
typedef struct { typedef struct {
uint16_t len; uint16_t len;
uint8_t * value; uint8_t * value;
@ -304,7 +313,7 @@ typedef struct {
// get folder item // get folder item
uint8_t get_folder_item; uint8_t get_folder_item;
uint8_t scope; avrcp_browsing_scope_t scope;
uint32_t start_item; uint32_t start_item;
uint32_t end_item; uint32_t end_item;
uint32_t attr_bitmap; uint32_t attr_bitmap;
@ -314,6 +323,17 @@ typedef struct {
uint8_t direction; uint8_t direction;
uint16_t uid_counter; uint16_t uid_counter;
uint8_t folder_uid[8]; uint8_t folder_uid[8];
// fragmentation
uint8_t fragmented;
avrcp_pdu_id_t fragmented_pdu_id;
uint8_t fragmented_browsing_status;
uint16_t fragmented_uid_counter;
uint16_t num_items;
uint8_t item_type;
uint16_t item_length;
uint16_t fragment_size;
uint8_t fragment[100];
} avrcp_browsing_connection_t; } avrcp_browsing_connection_t;
// BROWSING END // BROWSING END

View File

@ -383,26 +383,33 @@ static void avrcp_browsing_controller_handle_can_send_now(avrcp_browsing_connect
avrcp_browsing_controller_send_change_path_cmd(connection->l2cap_browsing_cid, connection); avrcp_browsing_controller_send_change_path_cmd(connection->l2cap_browsing_cid, connection);
break; break;
} }
break;
default: default:
return; return;
} }
} }
static void avrcp_browsing_controller_emit_done(btstack_packet_handler_t callback, uint16_t browsing_cid, uint8_t browsing_status, uint8_t bluetooth_status){
static void avrcp_browsing_controller_emit_done_with_uid_counter(btstack_packet_handler_t callback, uint16_t browsing_cid, uint16_t uid_counter, uint8_t browsing_status, uint8_t bluetooth_status){
if (!callback) return; if (!callback) return;
uint8_t event[7]; uint8_t event[9];
int pos = 0; int pos = 0;
event[pos++] = HCI_EVENT_AVRCP_META; event[pos++] = HCI_EVENT_AVRCP_META;
event[pos++] = sizeof(event) - 2; event[pos++] = sizeof(event) - 2;
event[pos++] = AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE; event[pos++] = AVRCP_SUBEVENT_BROWSING_DONE;
little_endian_store_16(event, pos, browsing_cid); little_endian_store_16(event, pos, browsing_cid);
pos += 2; pos += 2;
little_endian_store_16(event, pos, uid_counter);
pos += 2;
event[pos++] = browsing_status; event[pos++] = browsing_status;
event[pos++] = bluetooth_status; event[pos++] = bluetooth_status;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
} }
static void avrcp_browsing_controller_emit_done(btstack_packet_handler_t callback, uint16_t browsing_cid, uint8_t browsing_status, uint8_t bluetooth_status){
avrcp_browsing_controller_emit_done_with_uid_counter(callback, browsing_cid, 0, browsing_status, bluetooth_status);
}
static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
avrcp_browsing_connection_t * browsing_connection; avrcp_browsing_connection_t * browsing_connection;
@ -410,52 +417,45 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
case L2CAP_DATA_PACKET:{ case L2CAP_DATA_PACKET:{
browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid(channel, &avrcp_controller_context); browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid(channel, &avrcp_controller_context);
if (!browsing_connection) break; if (!browsing_connection) break;
browsing_connection->state = AVCTP_CONNECTION_OPENED;
// printf_hexdump(packet, size);
int pos = 0; int pos = 0;
uint8_t transport_header = packet[pos++]; uint8_t transport_header = packet[pos++];
// Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
// uint8_t transaction_label = transport_header >> 4; // uint8_t transaction_label = transport_header >> 4;
avrcp_packet_type_t avctp_packet_type = (transport_header & 0x0F) >> 2; avrcp_packet_type_t avctp_packet_type = (transport_header & 0x0F) >> 2;
avrcp_pdu_id_t pdu_id;
uint8_t browsing_status;
uint16_t uid_counter;
if (!browsing_connection->fragmented){
browsing_connection->state = AVCTP_CONNECTION_OPENED;
// printf_hexdump(packet, size);
// uint8_t frame_type = (transport_header & 0x03) >> 1; // uint8_t frame_type = (transport_header & 0x03) >> 1;
// uint8_t ipid = transport_header & 0x01; // uint8_t ipid = transport_header & 0x01;
pos += 2; pos += 2;
browsing_connection->num_packets = 1; browsing_connection->num_packets = 1;
switch (avctp_packet_type){ if (avctp_packet_type == AVRCP_START_PACKET){
case AVRCP_SINGLE_PACKET:
break;
case AVRCP_START_PACKET:
browsing_connection->num_packets = packet[pos++]; browsing_connection->num_packets = packet[pos++];
break;
case AVRCP_CONTINUE_PACKET:
case AVRCP_END_PACKET:
// browsing_connection->num_packets = packet[pos++];
break;
} }
if (pos + 4 > size){ if (pos + 4 > size){
avrcp_browsing_controller_emit_done(avrcp_controller_context.browsing_avrcp_callback, channel, AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND, ERROR_CODE_SUCCESS); avrcp_browsing_controller_emit_done(avrcp_controller_context.browsing_avrcp_callback, channel, AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND, ERROR_CODE_SUCCESS);
return; return;
} }
pdu_id = packet[pos++];
avrcp_pdu_id_t pdu_id = packet[pos++]; // uint16_t length = big_endian_read_16(packet, pos);
uint16_t length = big_endian_read_16(packet, pos);
pos += 2; pos += 2;
UNUSED(length); browsing_status = packet[pos++];
// if (browsing_connection->num_packets > 1)
// if (browsing_connection->num_packets == 1 && (pos + length > size)){
// printf("pos + length > size, %d, %d, %d \n", pos, length, size);
// avrcp_browsing_controller_emit_done(avrcp_controller_context.browsing_avrcp_callback, channel, AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND, ERROR_CODE_SUCCESS);
// return;
// }
uint8_t browsing_status = packet[pos++];
if (browsing_status != AVRCP_BROWSING_ERROR_CODE_SUCCESS){ if (browsing_status != AVRCP_BROWSING_ERROR_CODE_SUCCESS){
printf("browsing_status %d\n", browsing_status);
avrcp_browsing_controller_emit_done(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_status, ERROR_CODE_SUCCESS); avrcp_browsing_controller_emit_done(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_status, ERROR_CODE_SUCCESS);
return; return;
} }
uid_counter = big_endian_read_16(packet, pos);
pos += 2;
} else {
pdu_id = browsing_connection->fragmented_pdu_id;
browsing_status = browsing_connection->fragmented_browsing_status;
uid_counter = browsing_connection->fragmented_uid_counter;
}
uint32_t i; uint32_t i;
switch(pdu_id){ switch(pdu_id){
@ -463,46 +463,90 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
printf("AVRCP_PDU_ID_CHANGE_PATH \n"); printf("AVRCP_PDU_ID_CHANGE_PATH \n");
break; break;
case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER: case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER:
printf("AVRCP_PDU_ID_CHANGE_PATH \n"); printf("AVRCP_PDU_ID_SET_ADDRESSED_PLAYER \n");
break; break;
case AVRCP_PDU_ID_SET_BROWSED_PLAYER:{ case AVRCP_PDU_ID_SET_BROWSED_PLAYER:{
browsing_connection->browsed_player_uid_counter = big_endian_read_16(packet, pos); browsing_connection->browsed_player_uid_counter = uid_counter;
pos += 2; // uint32_t num_items = big_endian_read_32(packet, pos);
uint32_t num_items = big_endian_read_32(packet, pos);
pos += 4; pos += 4;
printf("AVRCP_PDU_ID_SET_BROWSED_PLAYER uuid counter 0x0%2x, num items %d\n", browsing_connection->browsed_player_uid_counter, num_items); // uint16_t charset = big_endian_read_16(packet, pos);
pos += 2;
uint8_t folder_depth = packet[pos++];
for (i = 0; i < num_items; i++){ for (i = 0; i < folder_depth; i++){
uint16_t browsable_item_length = 5 + big_endian_read_16(packet, pos+3); uint16_t folder_name_length = big_endian_read_16(packet, pos);
printf(" pos %d, len %d\n", pos, browsable_item_length); pos += 2;
// reuse byte to put the new type AVRCP_BROWSING_MEDIA_ROOT_FOLDER // reuse packet and add data type as a header
packet[pos-1] = AVRCP_BROWSING_MEDIA_ROOT_FOLDER; packet[pos-1] = AVRCP_BROWSING_MEDIA_ROOT_FOLDER;
(*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos, browsable_item_length+1); (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos-1, folder_name_length+1);
pos += browsable_item_length; pos += folder_name_length;
}
if (avctp_packet_type == AVRCP_SINGLE_PACKET || avctp_packet_type == AVRCP_END_PACKET){
avrcp_browsing_controller_emit_done_with_uid_counter(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_connection->browsed_player_uid_counter, browsing_status, ERROR_CODE_SUCCESS);
} }
break; break;
} }
case AVRCP_PDU_ID_GET_FOLDER_ITEMS:{ case AVRCP_PDU_ID_GET_FOLDER_ITEMS:{
// uint16_t uid_counter = big_endian_read_16(packet, pos); printf("AVRCP_PDU_ID_GET_FOLDER_ITEMS \n");
// send UID counter with done
if (!browsing_connection->fragmented){
browsing_connection->num_items = big_endian_read_16(packet, pos);
pos += 2; pos += 2;
uint16_t num_items = big_endian_read_16(packet, pos); }
while (pos < size){
uint8_t header_size = 1;
if (browsing_connection->fragment_size == 0){
browsing_connection->item_type = packet[pos++];
browsing_connection->item_length = big_endian_read_16(packet, pos);
pos += 2; pos += 2;
for (i = 0; i < num_items; i++){ // reuse packet and add data type as a header
uint16_t browsable_item_length = 3 + big_endian_read_16(packet, pos+1); packet[pos-1] = browsing_connection->item_type;
(*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos, browsable_item_length);
pos += browsable_item_length; if (browsing_connection->item_length + pos > size) {
browsing_connection->fragment_size = size - pos;
browsing_connection->fragment[0] = browsing_connection->item_type;
memcpy(&browsing_connection->fragment[header_size], &packet[pos], browsing_connection->fragment_size);
break;
}
(*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, &packet[pos-header_size], browsing_connection->item_length+header_size);
browsing_connection->num_items--;
pos += browsing_connection->item_length;
} else {
uint16_t remaining_bytes_to_copy = browsing_connection->item_length - browsing_connection->fragment_size;
if (remaining_bytes_to_copy + pos > size) {
memcpy(&browsing_connection->fragment[browsing_connection->fragment_size+1], &packet[pos], size - pos);
browsing_connection->fragment_size += size - pos;
break;
}
memcpy(&browsing_connection->fragment[browsing_connection->fragment_size+1], &packet[pos], remaining_bytes_to_copy);
(*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, browsing_connection->fragment, browsing_connection->item_length+1);
browsing_connection->num_items--;
browsing_connection->fragment_size = 0;
pos += remaining_bytes_to_copy;
}
} }
break; break;
} }
default: default:
break; break;
} }
switch (avctp_packet_type){ switch (avctp_packet_type){
case AVRCP_SINGLE_PACKET: case AVRCP_SINGLE_PACKET:
case AVRCP_END_PACKET: case AVRCP_END_PACKET:
avrcp_browsing_controller_emit_done(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_status, ERROR_CODE_SUCCESS); browsing_connection->state = AVCTP_CONNECTION_OPENED;
browsing_connection->fragmented = 0;
browsing_connection->num_items = 0;
browsing_connection->fragment_size = 0;
avrcp_browsing_controller_emit_done_with_uid_counter(avrcp_controller_context.browsing_avrcp_callback, channel, uid_counter, browsing_status, ERROR_CODE_SUCCESS);
break; break;
default: case AVRCP_START_PACKET:
browsing_connection->fragmented = 1;
browsing_connection->fragmented_pdu_id = pdu_id;
browsing_connection->fragmented_browsing_status = browsing_status;
break;
case AVRCP_CONTINUE_PACKET:
browsing_connection->fragmented = 1;
break; break;
} }
break; break;
@ -600,7 +644,7 @@ uint8_t avrcp_avrcp_browsing_decline_incoming_connection(uint16_t avrcp_browsing
* @param attribute_count * @param attribute_count
* @param attribute_list * @param attribute_list
**/ **/
static uint8_t avrcp_browsing_controller_get_folder_items(uint16_t avrcp_browsing_cid, uint8_t scope, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ static uint8_t avrcp_browsing_controller_get_folder_items(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid(avrcp_browsing_cid, &avrcp_controller_context); avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid(avrcp_browsing_cid, &avrcp_controller_context);
if (!avrcp_connection){ if (!avrcp_connection){
log_error("avrcp_browsing_controller_disconnect: could not find a connection."); log_error("avrcp_browsing_controller_disconnect: could not find a connection.");
@ -620,21 +664,21 @@ static uint8_t avrcp_browsing_controller_get_folder_items(uint16_t avrcp_browsin
} }
uint8_t avrcp_browsing_controller_get_media_players(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ uint8_t avrcp_browsing_controller_get_media_players(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 0, start_item, end_item, attr_bitmap); return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_LIST, start_item, end_item, attr_bitmap);
} }
uint8_t avrcp_browsing_controller_browse_file_system(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ uint8_t avrcp_browsing_controller_browse_file_system(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
// return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 1, 0, 0xFFFFFFFF, attr_bitmap); // return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 1, 0, 0xFFFFFFFF, attr_bitmap);
return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 1, start_item, end_item, attr_bitmap); return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM, start_item, end_item, attr_bitmap);
} }
uint8_t avrcp_browsing_controller_browse_media(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ uint8_t avrcp_browsing_controller_browse_media(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
// return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 2, 0, 0xFFFFFFFF, 0, NULL); // return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 2, 0, 0xFFFFFFFF, 0, NULL);
return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 2, start_item, end_item, attr_bitmap); return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_SEARCH, start_item, end_item, attr_bitmap);
} }
uint8_t avrcp_browsing_controller_browse_now_playing_list(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ uint8_t avrcp_browsing_controller_browse_now_playing_list(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 3, start_item, end_item, attr_bitmap); return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_NOW_PLAYING, start_item, end_item, attr_bitmap);
} }
@ -690,7 +734,7 @@ uint8_t avrcp_browsing_controller_change_path(uint16_t avrcp_browsing_cid, uint8
avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection;
if (!connection || connection->state != AVCTP_CONNECTION_OPENED || !folder_uid){ if (!connection || connection->state != AVCTP_CONNECTION_OPENED){
log_error("avrcp_browsing_controller_change_path: connection in wrong state."); log_error("avrcp_browsing_controller_change_path: connection in wrong state.");
return ERROR_CODE_COMMAND_DISALLOWED; return ERROR_CODE_COMMAND_DISALLOWED;
} }
@ -699,17 +743,20 @@ uint8_t avrcp_browsing_controller_change_path(uint16_t avrcp_browsing_cid, uint8
log_error("avrcp_browsing_controller_change_path: no browsed player set."); log_error("avrcp_browsing_controller_change_path: no browsed player set.");
return ERROR_CODE_COMMAND_DISALLOWED; return ERROR_CODE_COMMAND_DISALLOWED;
} }
printf(" send change path\n");
connection->change_path = 1; connection->change_path = 1;
connection->direction = direction; connection->direction = direction;
memset(connection->folder_uid, 0, 8);
if (folder_uid){
memcpy(connection->folder_uid, folder_uid, 8); memcpy(connection->folder_uid, folder_uid, 8);
}
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_go_up_one_level(uint16_t avrcp_browsing_cid){ uint8_t avrcp_browsing_controller_go_up_one_level(uint16_t avrcp_browsing_cid){
return avrcp_browsing_controller_change_path(avrcp_browsing_cid, 0, 0); return avrcp_browsing_controller_change_path(avrcp_browsing_cid, 0, NULL);
} }
uint8_t avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid, uint8_t * folder_uid){ uint8_t avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid, uint8_t * folder_uid){

View File

@ -202,7 +202,6 @@ uint8_t avrcp_browsing_controller_set_addressed_player(uint16_t avrcp_browsing_c
uint8_t avrcp_browsing_controller_change_path(uint16_t avrcp_browsing_cid, uint8_t direction, uint8_t * folder_uid); uint8_t avrcp_browsing_controller_change_path(uint16_t avrcp_browsing_cid, uint8_t direction, uint8_t * folder_uid);
uint8_t avrcp_browsing_controller_go_up_one_level(uint16_t avrcp_browsing_cid); uint8_t avrcp_browsing_controller_go_up_one_level(uint16_t avrcp_browsing_cid);
uint8_t avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid, uint8_t * folder_uid); uint8_t avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid, uint8_t * folder_uid);
/* API_END */ /* API_END */
#if defined __cplusplus #if defined __cplusplus

View File

@ -1185,3 +1185,40 @@ uint8_t avrcp_controller_disconnect(uint16_t avrcp_cid){
l2cap_disconnect(connection->l2cap_signaling_cid, 0); l2cap_disconnect(connection->l2cap_signaling_cid, 0);
return ERROR_CODE_SUCCESS; return ERROR_CODE_SUCCESS;
} }
uint8_t avrcp_controller_play_item(uint16_t avrcp_cid, avrcp_browsing_scope_t scope, uint8_t * uid, uint16_t uid_counter){
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;
}
if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED;
connection->state = AVCTP_W2_SEND_COMMAND;
connection->transaction_label++;
connection->command_type = AVRCP_CTYPE_CONTROL;
connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
connection->subunit_id = AVRCP_SUBUNIT_ID;
connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
int pos = 0;
big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID);
pos += 3;
connection->cmd_operands[pos++] = AVRCP_PDU_ID_PLAY_ITEM; // PDU ID
// reserved
connection->cmd_operands[pos++] = 0;
// Parameter Length
big_endian_store_16(connection->cmd_operands, pos, 11);
pos += 2;
connection->cmd_operands[pos++] = scope;
memset(&connection->cmd_operands[pos], 0, 8);
if (uid){
memcpy(&connection->cmd_operands[pos], uid, 8);
}
pos += 8;
big_endian_store_16(connection->cmd_operands, pos, uid_counter);
pos += 2;
connection->cmd_operands_length = pos;
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
return ERROR_CODE_SUCCESS;
}

View File

@ -284,6 +284,17 @@ uint8_t avrcp_controller_set_shuffle_mode(uint16_t avrcp_cid, avrcp_shuffle_mode
* @returns status * @returns status
*/ */
uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t mode); uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t mode);
/**
* @brief The PlayItem command starts playing an item indicated by the UID. It is routed to the Addressed Player.
* @param avrcp_cid
* @param scope
* @param uid
* @param uid_counter
* @return status
**/
uint8_t avrcp_controller_play_item(uint16_t avrcp_cid, avrcp_browsing_scope_t scope, uint8_t * uid, uint16_t uid_counter);
/* API_END */ /* API_END */
// Used by AVRCP controller and AVRCP browsing controller // Used by AVRCP controller and AVRCP browsing controller