mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-29 22:20:37 +00:00
avrcp: track transaction labels for registered events
This commit is contained in:
parent
30bbf872b1
commit
0ec79bd007
@ -383,7 +383,7 @@ uint16_t avrcp_get_next_cid(void){
|
||||
static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t remote_addr){
|
||||
avrcp_connection_t * connection = btstack_memory_avrcp_connection_get();
|
||||
if (!connection){
|
||||
log_error("avrcp: not enough memory to create connection");
|
||||
log_error("Not enough memory to create connection for role %d", role);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -392,7 +392,7 @@ static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t
|
||||
connection->transaction_label = 0xFF;
|
||||
connection->max_num_fragments = 0xFF;
|
||||
connection->avrcp_cid = avrcp_get_next_cid();
|
||||
printf("created connection, role %d, avrcp cid 0x%02x\n", role, connection->avrcp_cid);
|
||||
log_info("avrcp_create_connection, role %d, avrcp cid 0x%02x", role, connection->avrcp_cid);
|
||||
memcpy(connection->remote_addr, remote_addr, 6);
|
||||
btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection);
|
||||
return connection;
|
||||
@ -584,7 +584,6 @@ void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel,
|
||||
break;
|
||||
}
|
||||
connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
|
||||
printf("l2cap_create_channel\n");
|
||||
l2cap_create_channel(&avrcp_packet_handler, connection->remote_addr, sdp_query_context->avrcp_l2cap_psm, l2cap_max_mtu(), NULL);
|
||||
break;
|
||||
}
|
||||
@ -602,14 +601,17 @@ static btstack_packet_handler_t avrcp_packet_handler_for_role(avrcp_role_t role)
|
||||
}
|
||||
|
||||
static int avrcp_handle_incoming_connection_for_role(avrcp_role_t role, bd_addr_t event_addr, uint16_t local_cid){
|
||||
// printf("AVRCP: avrcp_handle_incoming_connection_for_role %d\n", role);
|
||||
if (!avrcp_packet_handler_for_role(role)) return 0;
|
||||
if (!avrcp_packet_handler_for_role(role)) {
|
||||
// printf("AVRCP: avrcp_handle_incoming_connection_for_role %d, PH not defined\n", role);
|
||||
return 0;
|
||||
}
|
||||
|
||||
avrcp_connection_t * connection = avrcp_create_connection(role, event_addr);
|
||||
if (!connection) {
|
||||
log_error("Failed to alloc target connection structure");
|
||||
return 0;
|
||||
}
|
||||
// printf("AVRCP: avrcp_handle_incoming_connection_for_role %d, no connection created\n", role);
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
// printf("AVRCP: AVCTP_CONNECTION_W4_L2CAP_CONNECTED, role %d\n", role);
|
||||
connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
|
||||
connection->l2cap_signaling_cid = local_cid;
|
||||
@ -618,11 +620,19 @@ static int avrcp_handle_incoming_connection_for_role(avrcp_role_t role, bd_addr_
|
||||
|
||||
static void avrcp_handle_open_connection_for_role(avrcp_role_t role, bd_addr_t event_addr, uint16_t local_cid, uint16_t l2cap_mtu, uint8_t status){
|
||||
// printf("AVRCP: avrcp_handle_open_connection_for_role %d\n", role);
|
||||
|
||||
btstack_packet_handler_t packet_handler = avrcp_packet_handler_for_role(role);
|
||||
if (!packet_handler) return;
|
||||
|
||||
if (!packet_handler) {
|
||||
// printf("AVRCP: avrcp_handle_open_connection_for_role %d, PH not defined\n", role);
|
||||
return;
|
||||
}
|
||||
avrcp_connection_t * connection = get_avrcp_connection_for_bd_addr(role, event_addr);
|
||||
if (!connection) return;
|
||||
if (!connection) {
|
||||
// printf("AVRCP: avrcp_handle_open_connection_for_role %d, no connection found\n", role);
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection->state == AVCTP_CONNECTION_OPENED) return;
|
||||
|
||||
if (status != ERROR_CODE_SUCCESS){
|
||||
log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status);
|
||||
@ -637,7 +647,7 @@ static void avrcp_handle_open_connection_for_role(avrcp_role_t role, bd_addr_t e
|
||||
connection->song_position_ms = 0xFFFFFFFF;
|
||||
connection->playback_status = AVRCP_PLAYBACK_STATUS_ERROR;
|
||||
|
||||
log_info("L2CAP_EVENT_CHANNEL_OPENED avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d ", connection->avrcp_cid, connection->l2cap_signaling_cid, connection->role);
|
||||
log_info("L2CAP_EVENT_CHANNEL_OPENED avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d", connection->avrcp_cid, connection->l2cap_signaling_cid, connection->role);
|
||||
connection->state = AVCTP_CONNECTION_OPENED;
|
||||
// emit twice for each role
|
||||
avrcp_emit_connection_established(packet_handler, connection->avrcp_cid, event_addr, ERROR_CODE_SUCCESS);
|
||||
@ -651,12 +661,22 @@ static void avrcp_handle_close_connection_for_role(avrcp_role_t role,uint16_t lo
|
||||
avrcp_connection_t * connection = get_avrcp_connection_for_l2cap_signaling_cid(role, local_cid);
|
||||
if (!connection) return;
|
||||
|
||||
printf("avrcp_handle_close_connection_for_role avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d\n", connection->avrcp_cid, connection->l2cap_signaling_cid, role);
|
||||
// printf("avrcp_handle_close_connection_for_role avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d\n", connection->avrcp_cid, connection->l2cap_signaling_cid, role);
|
||||
|
||||
avrcp_emit_connection_closed(packet_handler, connection->avrcp_cid);
|
||||
avrcp_finalize_connection(connection);
|
||||
}
|
||||
|
||||
static avrcp_role_t avrcp_role_from_transport_header(uint8_t transport_header){
|
||||
avrcp_frame_type_t frame_type = (avrcp_frame_type_t)((transport_header & 0x02) >> 1);
|
||||
switch (frame_type){
|
||||
case AVRCP_COMMAND_FRAME:
|
||||
return AVRCP_TARGET;
|
||||
case AVRCP_RESPONSE_FRAME:
|
||||
return AVRCP_CONTROLLER;
|
||||
}
|
||||
}
|
||||
|
||||
static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
UNUSED(channel);
|
||||
UNUSED(size);
|
||||
@ -665,39 +685,35 @@ static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
||||
uint16_t l2cap_mtu;
|
||||
uint8_t status;
|
||||
avrcp_connection_t * connection = NULL;
|
||||
|
||||
avrcp_connection_t * controller_connection = NULL;
|
||||
avrcp_connection_t * target_connection = NULL;
|
||||
avrcp_role_t role;
|
||||
btstack_packet_handler_t packet_handler;
|
||||
uint8_t status_target;
|
||||
uint8_t status_controller;
|
||||
|
||||
switch (packet_type) {
|
||||
case L2CAP_DATA_PACKET:
|
||||
// figure out role! for now send to both
|
||||
controller_connection = get_avrcp_connection_for_l2cap_signaling_cid(AVRCP_CONTROLLER, channel);
|
||||
target_connection = get_avrcp_connection_for_l2cap_signaling_cid(AVRCP_TARGET, channel);
|
||||
|
||||
// call correct controller/target packet hander
|
||||
if (controller_connection && avrcp_controller_packet_handler){
|
||||
(*avrcp_controller_packet_handler)(packet_type, channel, packet, size);
|
||||
}
|
||||
|
||||
if (target_connection && avrcp_target_packet_handler) {
|
||||
(*avrcp_target_packet_handler)(packet_type, channel, packet, size);
|
||||
}
|
||||
role = avrcp_role_from_transport_header(packet[0]);
|
||||
packet_handler = avrcp_packet_handler_for_role(role);
|
||||
if (!packet_handler) return;
|
||||
|
||||
(*packet_handler)(packet_type, channel, packet, size);
|
||||
break;
|
||||
|
||||
case HCI_EVENT_PACKET:
|
||||
switch (hci_event_packet_get_type(packet)) {
|
||||
|
||||
case L2CAP_EVENT_INCOMING_CONNECTION:
|
||||
// printf("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION \n");
|
||||
l2cap_event_incoming_connection_get_address(packet, event_addr);
|
||||
local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
|
||||
// create two connection objects (both)
|
||||
if (!avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, event_addr, local_cid) &&
|
||||
!avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, event_addr, local_cid)){
|
||||
status_target = avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, event_addr, local_cid);
|
||||
status_controller = avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, event_addr, local_cid);
|
||||
|
||||
if (!status_target && !status_controller){
|
||||
l2cap_decline_connection(local_cid);
|
||||
break;
|
||||
}
|
||||
|
||||
log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION avrcp_cid 0x%02x", local_cid);
|
||||
l2cap_accept_connection(local_cid);
|
||||
break;
|
||||
@ -721,7 +737,6 @@ static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CAN_SEND_NOW:
|
||||
// printf("AVRCP: L2CAP_EVENT_CAN_SEND_NOW\n");
|
||||
local_cid = l2cap_event_can_send_now_get_local_cid(packet);
|
||||
|
||||
connection = get_avrcp_connection_for_l2cap_signaling_cid(AVRCP_TARGET, local_cid);
|
||||
@ -758,10 +773,7 @@ uint8_t avrcp_connect(avrcp_role_t role, bd_addr_t bd_addr, avrcp_context_t * co
|
||||
if (!packet_handler) return 0;
|
||||
|
||||
connection = avrcp_create_connection(role, bd_addr);
|
||||
if (!connection){
|
||||
log_error("avrcp: could not allocate connection struct.");
|
||||
return BTSTACK_MEMORY_ALLOC_FAILED;
|
||||
}
|
||||
if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED;
|
||||
|
||||
if (avrcp_cid){
|
||||
*avrcp_cid = connection->avrcp_cid;
|
||||
|
@ -161,9 +161,11 @@ typedef enum {
|
||||
AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED = 0x0a, // The available players have changed, see 6.9.4.
|
||||
AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED = 0x0b, // The Addressed Player has been changed, see 6.9.2.
|
||||
AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED = 0x0c, // The UIDs have changed, see 6.10.3.3.
|
||||
AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED = 0x0d // The volume has been changed locally on the TG, see 6.13.3.
|
||||
AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED = 0x0d, // The volume has been changed locally on the TG, see 6.13.3.
|
||||
AVRCP_NOTIFICATION_EVENT_COUNT = 0x0d
|
||||
} avrcp_notification_event_id_t;
|
||||
|
||||
|
||||
// control command response: accepted, rejected, interim
|
||||
// status command response: not implemented, rejected, in transition, stable
|
||||
// notify command response: not implemented, rejected, changed
|
||||
@ -434,6 +436,7 @@ typedef struct {
|
||||
uint16_t notifications_enabled;
|
||||
uint16_t notifications_to_register;
|
||||
uint16_t notifications_to_deregister;
|
||||
uint8_t notifications_transaction_label[AVRCP_NOTIFICATION_EVENT_COUNT];
|
||||
|
||||
avrcp_subunit_type_t unit_type;
|
||||
uint32_t company_id;
|
||||
@ -458,7 +461,8 @@ typedef struct {
|
||||
avrcp_battery_status_t battery_status;
|
||||
uint8_t battery_status_changed;
|
||||
uint8_t volume_percentage;
|
||||
uint8_t volume_percentage_changed;
|
||||
uint8_t notify_volume_percentage_changed;
|
||||
|
||||
uint8_t now_playing_info_response;
|
||||
uint8_t now_playing_info_attr_bitmap;
|
||||
uint8_t abort_continue_response;
|
||||
@ -487,6 +491,8 @@ typedef struct {
|
||||
// PTS requires definition of max num fragments
|
||||
uint8_t max_num_fragments;
|
||||
uint8_t num_received_fragments;
|
||||
|
||||
uint8_t accept_response;
|
||||
} avrcp_connection_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -76,6 +76,20 @@ static void avrcp_target_emit_operation(btstack_packet_handler_t callback, uint1
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void avrcp_target_emit_volume_changed(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t absolute_volume){
|
||||
if (!callback) return;
|
||||
uint8_t event[7];
|
||||
int offset = 0;
|
||||
event[offset++] = HCI_EVENT_AVRCP_META;
|
||||
event[offset++] = sizeof(event) - 2;
|
||||
event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED;
|
||||
little_endian_store_16(event, offset, avrcp_cid);
|
||||
offset += 2;
|
||||
event[offset++] = AVRCP_CTYPE_NOTIFY;
|
||||
event[offset++] = absolute_volume;
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void avrcp_target_emit_respond_vendor_dependent_query(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t subevent_id){
|
||||
if (!callback) return;
|
||||
uint8_t event[5];
|
||||
@ -305,16 +319,23 @@ static int avrcp_target_send_response(uint16_t cid, avrcp_connection_t * connect
|
||||
packet[pos++] = (connection->subunit_type << 3) | connection->subunit_id;
|
||||
// opcode
|
||||
packet[pos++] = (uint8_t)connection->command_opcode;
|
||||
|
||||
// if (connection->command_opcode == AVRCP_CMD_OPCODE_VENDOR_DEPENDENT){
|
||||
// // company id is 3 bytes long
|
||||
// big_endian_store_24(packet, pos, BT_SIG_COMPANY_ID);
|
||||
// pos += 3;
|
||||
// }
|
||||
// operands
|
||||
memcpy(packet+pos, connection->cmd_operands, connection->cmd_operands_length);
|
||||
// printf_hexdump(packet+pos, connection->cmd_operands_length);
|
||||
|
||||
pos += connection->cmd_operands_length;
|
||||
// printf(" pos to send %d\n", pos);
|
||||
// printf_hexdump(packet, pos);
|
||||
|
||||
connection->wait_to_send = 0;
|
||||
return l2cap_send_prepared(cid, pos);
|
||||
}
|
||||
|
||||
static uint8_t avrcp_target_response_accept(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, avrcp_status_code_t status){
|
||||
static uint8_t avrcp_target_response_accept(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, uint8_t status){
|
||||
// AVRCP_CTYPE_RESPONSE_REJECTED
|
||||
connection->command_type = AVRCP_CTYPE_RESPONSE_ACCEPTED;
|
||||
connection->subunit_type = subunit_type;
|
||||
@ -329,7 +350,7 @@ static uint8_t avrcp_target_response_accept(avrcp_connection_t * connection, avr
|
||||
pos += 2;
|
||||
connection->cmd_operands[pos++] = status;
|
||||
connection->cmd_operands_length = pos;
|
||||
connection->state = AVCTP_W2_SEND_RESPONSE;
|
||||
connection->accept_response = 1;
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
@ -395,7 +416,6 @@ static uint8_t avrcp_target_response_vendor_dependent_interim(avrcp_connection_t
|
||||
pos += value_len;
|
||||
}
|
||||
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;
|
||||
@ -739,15 +759,24 @@ uint8_t avrcp_target_volume_changed(uint16_t avrcp_cid, uint8_t volume_percentag
|
||||
log_error("avrcp_unit_info: could not find a connection.");
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (connection->volume_percentage == volume_percentage) return ERROR_CODE_SUCCESS;
|
||||
// if (connection->volume_percentage == volume_percentage) return ERROR_CODE_SUCCESS;
|
||||
if (connection->notifications_enabled & (1 << AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED )) {
|
||||
connection->volume_percentage = volume_percentage;
|
||||
connection->volume_percentage_changed = 1;
|
||||
connection->notify_volume_percentage_changed = 1;
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
}
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static void avrcp_target_set_transaction_label_for_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t notification, uint8_t transaction_label){
|
||||
if (notification > AVRCP_NOTIFICATION_EVENT_COUNT) return;
|
||||
connection->notifications_transaction_label[notification] = transaction_label;
|
||||
}
|
||||
|
||||
static uint8_t avrcp_target_get_transaction_label_for_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t notification){
|
||||
if (notification > AVRCP_NOTIFICATION_EVENT_COUNT) return 0;
|
||||
return connection->notifications_transaction_label[notification];
|
||||
}
|
||||
|
||||
static uint8_t * avrcp_get_company_id(uint8_t *packet, uint16_t size){
|
||||
UNUSED(size);
|
||||
@ -952,7 +981,8 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
// 2-3 param length
|
||||
avrcp_notification_event_id_t event_id = (avrcp_notification_event_id_t) pdu[4];
|
||||
uint16_t event_mask = (1 << event_id);
|
||||
|
||||
avrcp_target_set_transaction_label_for_notification(connection, event_id, connection->transaction_label);
|
||||
|
||||
switch (event_id){
|
||||
case AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED:
|
||||
connection->notifications_enabled |= event_mask;
|
||||
@ -971,6 +1001,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
avrcp_target_response_vendor_dependent_interim(connection, subunit_type, subunit_id, opcode, pdu_id, event_id, NULL, 0);
|
||||
break;
|
||||
case AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED:
|
||||
connection->notify_volume_percentage_changed = 0;
|
||||
connection->notifications_enabled |= event_mask;
|
||||
avrcp_target_response_vendor_dependent_interim(connection, subunit_type, subunit_id, opcode, pdu_id, event_id, (const uint8_t *)&connection->volume_percentage, 1);
|
||||
break;
|
||||
@ -1003,7 +1034,9 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
if (absolute_volume < 0x80){
|
||||
connection->volume_percentage = absolute_volume;
|
||||
}
|
||||
avrcp_target_response_accept(connection, subunit_type, subunit_id, opcode, pdu_id, (avrcp_status_code_t) connection->volume_percentage);
|
||||
avrcp_target_response_accept(connection, subunit_type, subunit_id, opcode, pdu_id, connection->volume_percentage);
|
||||
avrcp_target_emit_volume_changed(avrcp_target_context.avrcp_callback, connection->avrcp_cid, connection->volume_percentage);
|
||||
// avrcp_target_volume_changed(connection->avrcp_cid, connection->volume_percentage);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -1065,7 +1098,7 @@ static int avrcp_target_send_addressed_player_changed_notification(uint16_t cid,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int avrcp_target_send_notification(uint16_t cid, avrcp_connection_t * connection, uint8_t notification_id, uint8_t * value, uint16_t value_len){
|
||||
static int avrcp_target_send_notification(uint16_t cid, avrcp_connection_t * connection, avrcp_notification_event_id_t notification_id, uint8_t * value, uint16_t value_len){
|
||||
if (!connection){
|
||||
log_error("avrcp tartget: could not find a connection.");
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
@ -1075,7 +1108,8 @@ static int avrcp_target_send_notification(uint16_t cid, avrcp_connection_t * con
|
||||
connection->command_type = AVRCP_CTYPE_RESPONSE_CHANGED_STABLE;
|
||||
connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
|
||||
connection->subunit_id = AVRCP_SUBUNIT_ID;
|
||||
|
||||
connection->transaction_label = avrcp_target_get_transaction_label_for_notification(connection, notification_id);
|
||||
|
||||
uint16_t pos = 0;
|
||||
l2cap_reserve_packet_buffer();
|
||||
uint8_t * packet = l2cap_get_outgoing_buffer();
|
||||
@ -1100,26 +1134,26 @@ static int avrcp_target_send_notification(uint16_t cid, avrcp_connection_t * con
|
||||
|
||||
packet[pos++] = AVRCP_PDU_ID_REGISTER_NOTIFICATION;
|
||||
packet[pos++] = 0;
|
||||
uint16_t remainig_outgoing_buffer_size = size > (value_len + 2 + 1) ? size - (value_len + 2 + 1): 0;
|
||||
uint16_t caped_value_len = value_len > remainig_outgoing_buffer_size ? remainig_outgoing_buffer_size : value_len;
|
||||
uint16_t remainig_outgoing_buffer_size = size - pos - 2;
|
||||
|
||||
uint16_t caped_value_len = btstack_min(value_len + 1, remainig_outgoing_buffer_size);
|
||||
big_endian_store_16(packet, pos, caped_value_len);
|
||||
pos += 2;
|
||||
packet[pos++] = notification_id;
|
||||
|
||||
memcpy(packet+pos, value, caped_value_len);
|
||||
pos += caped_value_len;
|
||||
memcpy(packet+pos, value, caped_value_len-1);
|
||||
pos += caped_value_len - 1;
|
||||
connection->wait_to_send = 0;
|
||||
return l2cap_send_prepared(cid, pos);
|
||||
}
|
||||
|
||||
static void avrcp_target_reset_notification(avrcp_connection_t * connection, uint8_t notification_id){
|
||||
static void avrcp_target_reset_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t notification_id){
|
||||
if (!connection){
|
||||
log_error("avrcp tartget: could not find a connection.");
|
||||
return;
|
||||
}
|
||||
connection->notifications_enabled &= ~(1 << notification_id);
|
||||
connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
|
||||
|
||||
avrcp_target_set_transaction_label_for_notification(connection, notification_id, 0);
|
||||
}
|
||||
|
||||
static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
@ -1143,6 +1177,12 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
|
||||
break;
|
||||
}
|
||||
|
||||
if (connection->accept_response){
|
||||
connection->accept_response = 0;
|
||||
avrcp_target_send_response(connection->l2cap_signaling_cid, connection);
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
break;
|
||||
}
|
||||
if (connection->abort_continue_response){
|
||||
connection->abort_continue_response = 0;
|
||||
connection->now_playing_info_response = 0;
|
||||
@ -1196,8 +1236,9 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
|
||||
break;
|
||||
}
|
||||
|
||||
if (connection->volume_percentage_changed){
|
||||
connection->volume_percentage_changed = 0;
|
||||
if (connection->notify_volume_percentage_changed){
|
||||
// printf("emit new volume %d\n", connection->volume_percentage);
|
||||
connection->notify_volume_percentage_changed = 0;
|
||||
avrcp_target_send_notification(connection->l2cap_signaling_cid, connection, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED, &connection->volume_percentage, 1);
|
||||
avrcp_target_reset_notification(connection, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED);
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
@ -1205,7 +1246,6 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
|
||||
}
|
||||
|
||||
if (connection->reject_transport_header){
|
||||
printf(" reject_transport_header\n");
|
||||
connection->state = AVCTP_CONNECTION_OPENED;
|
||||
connection->reject_transport_header = 0;
|
||||
l2cap_reserve_packet_buffer();
|
||||
@ -1216,7 +1256,6 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (connection->state){
|
||||
case AVCTP_W2_SEND_RESPONSE:
|
||||
@ -1227,10 +1266,12 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
|
||||
// break;
|
||||
// }
|
||||
avrcp_target_send_response(connection->l2cap_signaling_cid, connection);
|
||||
break;
|
||||
default:
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -1245,7 +1286,7 @@ void avrcp_target_init(void){
|
||||
avrcp_init();
|
||||
avrcp_target_context.role = AVRCP_TARGET;
|
||||
avrcp_target_context.packet_handler = avrcp_target_packet_handler;
|
||||
avrcp_register_controller_packet_handler(&avrcp_target_packet_handler);
|
||||
avrcp_register_target_packet_handler(&avrcp_target_packet_handler);
|
||||
}
|
||||
|
||||
void avrcp_target_register_packet_handler(btstack_packet_handler_t callback){
|
||||
@ -1263,7 +1304,7 @@ uint8_t avrcp_target_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid){
|
||||
uint8_t avrcp_target_disconnect(uint16_t avrcp_cid){
|
||||
avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(AVRCP_TARGET, avrcp_cid);
|
||||
if (!connection){
|
||||
log_error("avrcp_get_capabilities: could not find a connection.");
|
||||
log_error("avrcp_target_disconnect: could not find a connection.");
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
|
Loading…
x
Reference in New Issue
Block a user