mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-14 10:21:49 +00:00
avrctp browsing target: start addr player changed, get folder items
This commit is contained in:
parent
7f803253e9
commit
6568eb54ed
@ -51,6 +51,63 @@
|
||||
static void avrcp_browser_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avrcp_context_t * context);
|
||||
static void avrcp_browsing_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
|
||||
static void avrcp_browsing_target_request_can_send_now(avrcp_browsing_connection_t * connection, uint16_t l2cap_cid){
|
||||
connection->wait_to_send = 1;
|
||||
l2cap_request_can_send_now_event(l2cap_cid);
|
||||
}
|
||||
|
||||
static int avrcp_browsing_target_handle_can_send_now(avrcp_browsing_connection_t * connection){
|
||||
|
||||
int pos = 0;
|
||||
l2cap_reserve_packet_buffer();
|
||||
uint8_t * packet = l2cap_get_outgoing_buffer();
|
||||
|
||||
// transport header
|
||||
// Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
|
||||
|
||||
// TODO: check for fragmentation
|
||||
connection->packet_type = AVRCP_SINGLE_PACKET;
|
||||
printf("ttransaction %d \n", connection->transaction_label);
|
||||
packet[pos++] = (connection->transaction_label << 4) | (connection->packet_type << 2) | (AVRCP_RESPONSE_FRAME << 1) | 0;
|
||||
// Profile IDentifier (PID)
|
||||
packet[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8;
|
||||
packet[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF;
|
||||
// command_type
|
||||
// packet[pos++] = connection->command_type;
|
||||
// // subunit_type | subunit ID
|
||||
// packet[pos++] = (connection->subunit_type << 3) | connection->subunit_id;
|
||||
// // opcode
|
||||
// packet[pos++] = (uint8_t)connection->command_opcode;
|
||||
// operands
|
||||
// company id is 3 bytes long
|
||||
// big_endian_store_24(packet, pos, BT_SIG_COMPANY_ID);
|
||||
// pos += 3;
|
||||
memcpy(packet+pos, connection->cmd_operands, connection->cmd_operands_length);
|
||||
// printf_hexdump(packet+pos, connection->cmd_operands_length);
|
||||
|
||||
pos += connection->cmd_operands_length;
|
||||
connection->wait_to_send = 0;
|
||||
printf(" send reject \n");
|
||||
printf_hexdump(packet, pos);
|
||||
return l2cap_send_prepared(connection->l2cap_browsing_cid, pos);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t avrcp_browsing_target_response_reject(avrcp_browsing_connection_t * connection, avrcp_status_code_t status){
|
||||
// AVRCP_CTYPE_RESPONSE_REJECTED
|
||||
int pos = 0;
|
||||
connection->cmd_operands[pos++] = AVRCP_PDU_ID_GENERAL_REJECT;
|
||||
// connection->cmd_operands[pos++] = 0;
|
||||
// param length
|
||||
big_endian_store_16(connection->cmd_operands, pos, 1);
|
||||
pos += 2;
|
||||
connection->cmd_operands[pos++] = status;
|
||||
connection->cmd_operands_length = 4;
|
||||
connection->state = AVCTP_W2_SEND_RESPONSE;
|
||||
avrcp_browsing_target_request_can_send_now(connection, connection->l2cap_browsing_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static avrcp_connection_t * get_avrcp_connection_for_browsing_cid(uint16_t browsing_cid, avrcp_context_t * context){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &context->connections);
|
||||
@ -84,6 +141,21 @@ static avrcp_browsing_connection_t * get_avrcp_browsing_connection_for_l2cap_cid
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void avrcp_browsing_target_emit_get_folder_items(btstack_packet_handler_t callback, uint16_t browsing_cid, avrcp_browsing_connection_t * connection){
|
||||
if (!callback) return;
|
||||
uint8_t event[10];
|
||||
int pos = 0;
|
||||
event[pos++] = HCI_EVENT_AVRCP_META;
|
||||
event[pos++] = sizeof(event) - 2;
|
||||
event[pos++] = AVRCP_SUBEVENT_BROWSING_GET_FOLDER_ITEMS;
|
||||
little_endian_store_16(event, pos, browsing_cid);
|
||||
pos += 2;
|
||||
event[pos++] = connection->scope;
|
||||
big_endian_store_32(event, pos, connection->attr_bitmap);
|
||||
pos += 4;
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void avrcp_emit_browsing_connection_established(btstack_packet_handler_t callback, uint16_t browsing_cid, bd_addr_t addr, uint8_t status){
|
||||
if (!callback) return;
|
||||
uint8_t event[12];
|
||||
@ -249,7 +321,6 @@ static void avrcp_browser_packet_handler(uint8_t packet_type, uint16_t channel,
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void avrcp_browsing_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
avrcp_browsing_connection_t * browsing_connection;
|
||||
|
||||
@ -257,14 +328,84 @@ static void avrcp_browsing_target_packet_handler(uint8_t packet_type, uint16_t c
|
||||
case L2CAP_DATA_PACKET:{
|
||||
browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid(channel, &avrcp_target_context);
|
||||
if (!browsing_connection) break;
|
||||
printf_hexdump(packet,size);
|
||||
|
||||
int pos = 0;
|
||||
uint8_t transport_header = packet[pos++];
|
||||
// Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
|
||||
browsing_connection->transaction_label = transport_header >> 4;
|
||||
avrcp_packet_type_t avctp_packet_type = (transport_header & 0x0F) >> 2;
|
||||
printf("L2CAP_DATA_PACKET, transaction_label %d\n", browsing_connection->transaction_label);
|
||||
switch (avctp_packet_type){
|
||||
case AVRCP_SINGLE_PACKET:
|
||||
case AVRCP_START_PACKET:
|
||||
// uint8_t frame_type = (transport_header & 0x03) >> 1;
|
||||
// uint8_t ipid = transport_header & 0x01;
|
||||
browsing_connection->subunit_type = packet[pos++] >> 2;
|
||||
browsing_connection->subunit_id = 0;
|
||||
browsing_connection->command_opcode = packet[pos++];
|
||||
// printf("subunit_id")
|
||||
// pos += 2;
|
||||
browsing_connection->num_packets = 1;
|
||||
if (avctp_packet_type == AVRCP_START_PACKET){
|
||||
browsing_connection->num_packets = packet[pos++];
|
||||
}
|
||||
browsing_connection->pdu_id = packet[pos++];
|
||||
// uint16_t length = big_endian_read_16(packet, pos);
|
||||
// pos += 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("pdu id 0x%2x\n", browsing_connection->pdu_id);
|
||||
// uint32_t i;
|
||||
switch(browsing_connection->pdu_id){
|
||||
case AVRCP_PDU_ID_GET_FOLDER_ITEMS:
|
||||
printf("\n");
|
||||
browsing_connection->scope = packet[pos++];
|
||||
browsing_connection->start_item = big_endian_read_32(packet, pos);
|
||||
pos += 4;
|
||||
browsing_connection->end_item = big_endian_read_32(packet, pos);
|
||||
pos += 4;
|
||||
uint8_t attr_count = packet[pos++];
|
||||
|
||||
while (attr_count){
|
||||
uint32_t attr_id = big_endian_read_32(packet, pos);
|
||||
pos += 4;
|
||||
browsing_connection->attr_bitmap |= (1 << attr_id);
|
||||
attr_count--;
|
||||
}
|
||||
avrcp_browsing_target_emit_get_folder_items(avrcp_target_context.browsing_avrcp_callback, channel, browsing_connection);
|
||||
|
||||
break;
|
||||
default:
|
||||
printf(" not parsed pdu ID 0x%02x\n", browsing_connection->pdu_id);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (avctp_packet_type){
|
||||
case AVRCP_SINGLE_PACKET:
|
||||
case AVRCP_END_PACKET:
|
||||
printf("send avrcp_browsing_target_response_reject\n");
|
||||
browsing_connection->state = AVCTP_CONNECTION_OPENED;
|
||||
avrcp_browsing_target_response_reject(browsing_connection, AVRCP_STATUS_INVALID_COMMAND);
|
||||
// avrcp_browsing_target_emit_done_with_uid_counter(avrcp_target_context.browsing_avrcp_callback, channel, browsing_connection->uid_counter, browsing_connection->browsing_status, ERROR_CODE_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// printf(" paket done\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case HCI_EVENT_PACKET:
|
||||
switch (hci_event_packet_get_type(packet)){
|
||||
case L2CAP_EVENT_CAN_SEND_NOW:
|
||||
browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid(channel, &avrcp_target_context);
|
||||
if (!browsing_connection) break;
|
||||
// avrcp_browsing_target_handle_can_send_now(browsing_connection);
|
||||
if (browsing_connection->state != AVCTP_W2_SEND_RESPONSE) return;
|
||||
browsing_connection->state = AVCTP_CONNECTION_OPENED;
|
||||
avrcp_browsing_target_handle_can_send_now(browsing_connection);
|
||||
break;
|
||||
default:
|
||||
avrcp_browser_packet_handler(packet_type, channel, packet, size, &avrcp_target_context);
|
||||
|
@ -395,6 +395,32 @@ static uint8_t avrcp_target_response_vendor_dependent_interim(avrcp_connection_t
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t avrcp_target_response_addressed_player_changed_interim(avrcp_connection_t * connection, avrcp_subunit_type_t subunit_type, avrcp_subunit_id_t subunit_id, avrcp_command_opcode_t opcode, avrcp_pdu_id_t pdu_id){
|
||||
connection->command_type = AVRCP_CTYPE_RESPONSE_INTERIM;
|
||||
connection->subunit_type = subunit_type;
|
||||
connection->subunit_id = subunit_id;
|
||||
connection->command_opcode = opcode;
|
||||
printf("avrcp_target_response_addressed_player_changed_interim \n");
|
||||
// company id is 3 bytes long
|
||||
int pos = connection->cmd_operands_length;
|
||||
connection->cmd_operands[pos++] = pdu_id;
|
||||
connection->cmd_operands[pos++] = 0;
|
||||
// param length
|
||||
big_endian_store_16(connection->cmd_operands, pos, 5);
|
||||
pos += 2;
|
||||
connection->cmd_operands[pos++] = AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED;
|
||||
big_endian_read_16( &connection->cmd_operands[pos], connection->addressed_player_id);
|
||||
pos += 2;
|
||||
big_endian_read_16( &connection->cmd_operands[pos], connection->uid_counter);
|
||||
pos += 2;
|
||||
|
||||
connection->cmd_operands_length = pos;
|
||||
connection->state = AVCTP_W2_SEND_RESPONSE;
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// static uint8_t avrcp_target_response_vendor_dependent_changed(avrcp_connection_t * connection, avrcp_pdu_id_t pdu_id, uint8_t event_id){
|
||||
// connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
|
||||
// connection->command_type = AVRCP_CTYPE_RESPONSE_CHANGED_STABLE;
|
||||
@ -659,7 +685,7 @@ uint8_t avrcp_target_track_changed(uint16_t avrcp_cid, uint8_t * track_id){
|
||||
uint8_t avrcp_target_playing_content_changed(uint16_t avrcp_cid){
|
||||
avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context);
|
||||
if (!connection){
|
||||
log_error("avrcp_unit_info: could not find a connection.");
|
||||
log_error("avrcp_target_playing_content_changed: could not find a connection.");
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (connection->notifications_enabled & (1 << AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED)) {
|
||||
@ -669,6 +695,22 @@ uint8_t avrcp_target_playing_content_changed(uint16_t avrcp_cid){
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t avrcp_target_addressed_player_changed(uint16_t avrcp_cid, uint16_t player_id, uint16_t uid_counter){
|
||||
avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context);
|
||||
if (!connection){
|
||||
log_error("avrcp_unit_info: could not find a connection.");
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (connection->notifications_enabled & (1 << AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED)) {
|
||||
printf("send AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED\n");
|
||||
// connection->addressed_player_changed = 1;
|
||||
// connection->uid_counter = uid_counter;
|
||||
// connection->addressed_player_id = player_id;
|
||||
// avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
}
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t avrcp_target_battery_status_changed(uint16_t avrcp_cid, avrcp_battery_status_t battery_status){
|
||||
avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context);
|
||||
if (!connection){
|
||||
@ -803,10 +845,22 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT:
|
||||
pdu_id = pdu[0];
|
||||
// 1 - reserved
|
||||
// 2-3 param length,
|
||||
// 2-3 param length,
|
||||
printf_hexdump(packet, size);
|
||||
|
||||
uint16_t length = big_endian_read_16(pdu, 1);
|
||||
memcpy(connection->cmd_operands, company_id, 3);
|
||||
connection->cmd_operands_length = 3;
|
||||
switch (pdu_id){
|
||||
case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER:{
|
||||
if (length == 0){
|
||||
printf(" reject id\n");
|
||||
avrcp_target_response_reject(connection, subunit_type, subunit_id, opcode, pdu_id, AVRCP_STATUS_INVALID_PLAYER_ID);
|
||||
break;
|
||||
}
|
||||
avrcp_target_response_accept(connection, subunit_type, subunit_id, opcode, pdu_id, AVRCP_STATUS_SUCCESS);
|
||||
break;
|
||||
}
|
||||
case AVRCP_PDU_ID_GET_CAPABILITIES:{
|
||||
avrcp_capability_id_t capability_id = (avrcp_capability_id_t) pdu[pos];
|
||||
switch (capability_id){
|
||||
@ -898,10 +952,14 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
break;
|
||||
case AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED:
|
||||
case AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:
|
||||
case AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED:
|
||||
case AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED:
|
||||
avrcp_target_response_not_implemented(connection, subunit_type, subunit_id, opcode, pdu_id, event_id);
|
||||
return;
|
||||
case AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED:
|
||||
connection->notifications_enabled |= event_mask;
|
||||
printf("respond with interim AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED\n");
|
||||
avrcp_target_response_addressed_player_changed_interim(connection, subunit_type, subunit_id, opcode, pdu_id);
|
||||
return;
|
||||
default:
|
||||
avrcp_target_response_reject(connection, subunit_type, subunit_id, opcode, pdu_id, AVRCP_STATUS_INVALID_PARAMETER);
|
||||
return;
|
||||
@ -938,6 +996,53 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
}
|
||||
}
|
||||
|
||||
static int avrcp_target_send_addressed_player_changed_notification(uint16_t cid, avrcp_connection_t * connection, uint16_t uid, uint16_t uid_counter){
|
||||
if (!connection){
|
||||
log_error("avrcp tartget: could not find a connection.");
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
printf("avrcp_target_send_addressed_player_changed_notification \n");
|
||||
connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
|
||||
connection->command_type = AVRCP_CTYPE_RESPONSE_CHANGED_STABLE;
|
||||
connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
|
||||
connection->subunit_id = AVRCP_SUBUNIT_ID;
|
||||
|
||||
uint16_t pos = 0;
|
||||
l2cap_reserve_packet_buffer();
|
||||
uint8_t * packet = l2cap_get_outgoing_buffer();
|
||||
|
||||
connection->packet_type = AVRCP_SINGLE_PACKET;
|
||||
packet[pos++] = (connection->transaction_label << 4) | (connection->packet_type << 2) | (AVRCP_RESPONSE_FRAME << 1) | 0;
|
||||
// Profile IDentifier (PID)
|
||||
packet[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8;
|
||||
packet[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF;
|
||||
|
||||
// command_type
|
||||
packet[pos++] = connection->command_type;
|
||||
// subunit_type | subunit ID
|
||||
packet[pos++] = (connection->subunit_type << 3) | connection->subunit_id;
|
||||
// opcode
|
||||
packet[pos++] = (uint8_t)connection->command_opcode;
|
||||
|
||||
// company id is 3 bytes long
|
||||
big_endian_store_24(packet, pos, BT_SIG_COMPANY_ID);
|
||||
pos += 3;
|
||||
|
||||
packet[pos++] = AVRCP_PDU_ID_REGISTER_NOTIFICATION;
|
||||
packet[pos++] = 0;
|
||||
big_endian_store_16(packet, pos, 5);
|
||||
pos += 2;
|
||||
packet[pos++] = AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED;
|
||||
big_endian_store_16(packet, pos, uid);
|
||||
pos += 2;
|
||||
big_endian_store_16(packet, pos, uid_counter);
|
||||
pos += 2;
|
||||
|
||||
connection->wait_to_send = 0;
|
||||
return l2cap_send_prepared(cid, pos);
|
||||
}
|
||||
|
||||
|
||||
static int avrcp_target_send_notification(uint16_t cid, avrcp_connection_t * connection, uint8_t notification_id, uint8_t * value, uint16_t value_len){
|
||||
if (!connection){
|
||||
log_error("avrcp tartget: could not find a connection.");
|
||||
@ -990,6 +1095,7 @@ static void avrcp_target_reset_notification(avrcp_connection_t * connection, uin
|
||||
log_error("avrcp tartget: could not find a connection.");
|
||||
return;
|
||||
}
|
||||
printf("reset notification\n");
|
||||
connection->notifications_enabled &= ~(1 << notification_id);
|
||||
connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
|
||||
|
||||
@ -1041,6 +1147,14 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
|
||||
break;
|
||||
}
|
||||
|
||||
// if (connection->addressed_player_changed){
|
||||
// connection->playback_status_changed = 0;
|
||||
// avrcp_target_send_addressed_player_changed_notification(connection->l2cap_signaling_cid, connection, connection->addressed_player_id, connection->uid_counter);
|
||||
// avrcp_target_reset_notification(connection, AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED);
|
||||
// avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
// break;
|
||||
// }
|
||||
|
||||
if (connection->playing_content_changed){
|
||||
connection->playing_content_changed = 0;
|
||||
avrcp_target_send_notification(connection->l2cap_signaling_cid, connection, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED, NULL, 0);
|
||||
|
@ -85,6 +85,8 @@ void avrcp_target_set_unit_info(uint16_t avrcp_cid, avrcp_subunit_type_t unit_ty
|
||||
void avrcp_target_set_subunit_info(uint16_t avrcp_cid, avrcp_subunit_type_t subunit_type, const uint8_t * subunit_info_data, uint16_t subunit_info_data_size);
|
||||
|
||||
uint8_t avrcp_target_playing_content_changed(uint16_t avrcp_cid);
|
||||
uint8_t avrcp_target_addressed_player_changed(uint16_t avrcp_cid, uint16_t player_id, uint16_t uid_counter);
|
||||
|
||||
uint8_t avrcp_target_battery_status_changed(uint16_t avrcp_cid, avrcp_battery_status_t battery_status);
|
||||
uint8_t avrcp_target_volume_changed(uint16_t avrcp_cid, uint8_t volume_percentage);
|
||||
uint8_t avrcp_target_track_changed(uint16_t avrcp_cid, uint8_t * trackID);
|
||||
|
@ -547,6 +547,10 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
|
||||
printf("AVRCP Browsing Client connected\n");
|
||||
return;
|
||||
}
|
||||
case AVRCP_SUBEVENT_BROWSING_GET_FOLDER_ITEMS:
|
||||
printf(" AVRCP_SUBEVENT_BROWSING_GET_FOLDER_ITEMS \n");
|
||||
break;
|
||||
|
||||
case AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED:
|
||||
printf("AVRCP Browsing Controller released\n");
|
||||
browsing_cid = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user