avrcp, avrcp_browsing: schedule SDP query, avoids 'command disallowed' if SDP client is busy

This commit is contained in:
Milanka Ringwald 2020-09-04 17:15:29 +02:00
parent 40adb62dab
commit 64a27ec54b
4 changed files with 164 additions and 59 deletions

View File

@ -715,7 +715,9 @@ static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channe
case AVRCP_SUBEVENT_OPERATION_START: case AVRCP_SUBEVENT_OPERATION_START:
printf("AVRCP Controller: %s start\n", avrcp_operation2str(avrcp_subevent_operation_start_get_operation_id(packet))); printf("AVRCP Controller: %s start\n", avrcp_operation2str(avrcp_subevent_operation_start_get_operation_id(packet)));
break; break;
case AVRCP_SUBEVENT_NOTIFICATION_EVENT_TRACK_REACHED_END:
printf("AVRCP Controller: Track reached end\n");
break;
default: default:
printf("AVRCP Controller: Event 0x%02x is not parsed\n", packet[2]); printf("AVRCP Controller: Event 0x%02x is not parsed\n", packet[2]);
break; break;
@ -963,7 +965,7 @@ static void stdin_process(char cmd){
break; break;
case 'B': case 'B':
printf(" - AVDTP disconnect from addr %s.\n", bd_addr_to_str(device_addr)); printf(" - AVDTP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
status = avdtp_sink_disconnect(a2dp_cid); a2dp_sink_disconnect(a2dp_cid);
break; break;
case 'c': case 'c':
printf(" - Create AVRCP connection to addr %s.\n", bd_addr_to_str(device_addr)); printf(" - Create AVRCP connection to addr %s.\n", bd_addr_to_str(device_addr));
@ -1095,7 +1097,7 @@ static void stdin_process(char cmd){
return; return;
} }
if (status != ERROR_CODE_SUCCESS){ if (status != ERROR_CODE_SUCCESS){
printf("Could not perform command, status 0x%2x\n", status); printf("Could not perform command, status 0x%02x\n", status);
} }
} }
#endif #endif

View File

@ -49,6 +49,19 @@
#include "classic/sdp_util.h" #include "classic/sdp_util.h"
#include "classic/avrcp.h" #include "classic/avrcp.h"
typedef struct {
uint8_t parse_sdp_record;
uint32_t record_id;
uint16_t avrcp_cid;
uint16_t avrcp_l2cap_psm;
uint16_t avrcp_version;
uint16_t browsing_l2cap_psm;
uint16_t browsing_version;
} avrcp_sdp_query_context_t;
static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static const char * default_avrcp_controller_service_name = "BTstack AVRCP Controller Service"; static const char * default_avrcp_controller_service_name = "BTstack AVRCP Controller Service";
@ -58,8 +71,9 @@ static const char * default_avrcp_target_service_provider_name = "BTstack AVRCP
static uint16_t avrcp_cid_counter = 0; static uint16_t avrcp_cid_counter = 0;
static avrcp_context_t * sdp_query_context; static btstack_context_callback_registration_t avrcp_handle_sdp_client_query_request;
static avrcp_context_t avrcp_context;
static avrcp_sdp_query_context_t sdp_query_context;
static btstack_packet_handler_t avrcp_callback; static btstack_packet_handler_t avrcp_callback;
@ -172,6 +186,10 @@ const char * avrcp_repeat2str(uint8_t index){
return "NONE"; return "NONE";
} }
btstack_linked_list_t avrcp_get_connections(void){
return connections;
}
uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){ uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){
uint8_t cmd_opcode_index = 5; uint8_t cmd_opcode_index = 5;
if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED; if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED;
@ -439,7 +457,7 @@ static void avrcp_emit_connection_closed(uint16_t avrcp_cid){
} }
uint16_t avrcp_sdp_sdp_query_browsing_l2cap_psm(void){ uint16_t avrcp_sdp_sdp_query_browsing_l2cap_psm(void){
return sdp_query_context->browsing_l2cap_psm; return sdp_query_context.browsing_l2cap_psm;
} }
void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){
@ -447,9 +465,9 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){
des_iterator_t prot_it; des_iterator_t prot_it;
// Handle new SDP record // Handle new SDP record
if (sdp_event_query_attribute_byte_get_record_id(packet) != sdp_query_context->record_id) { if (sdp_event_query_attribute_byte_get_record_id(packet) != sdp_query_context.record_id) {
sdp_query_context->record_id = sdp_event_query_attribute_byte_get_record_id(packet); sdp_query_context.record_id = sdp_event_query_attribute_byte_get_record_id(packet);
sdp_query_context->parse_sdp_record = 0; sdp_query_context.parse_sdp_record = 0;
// log_info("SDP Record: Nr: %d", record_id); // log_info("SDP Record: Nr: %d", record_id);
} }
@ -468,7 +486,7 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){
case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET: case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET:
case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL: case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL:
case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER: case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER:
sdp_query_context->parse_sdp_record = 1; sdp_query_context.parse_sdp_record = 1;
break; break;
default: default:
break; break;
@ -477,7 +495,7 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){
break; break;
case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: { case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: {
if (!sdp_query_context->parse_sdp_record) break; if (!sdp_query_context.parse_sdp_record) break;
// log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
uint8_t *des_element; uint8_t *des_element;
@ -497,11 +515,11 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){
switch (uuid){ switch (uuid){
case BLUETOOTH_PROTOCOL_L2CAP: case BLUETOOTH_PROTOCOL_L2CAP:
if (!des_iterator_has_more(&prot_it)) continue; if (!des_iterator_has_more(&prot_it)) continue;
de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_l2cap_psm); de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_l2cap_psm);
break; break;
case BLUETOOTH_PROTOCOL_AVCTP: case BLUETOOTH_PROTOCOL_AVCTP:
if (!des_iterator_has_more(&prot_it)) continue; if (!des_iterator_has_more(&prot_it)) continue;
de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_version); de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_version);
break; break;
default: default:
break; break;
@ -511,7 +529,7 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){
break; break;
case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: { case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: {
// log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
if (!sdp_query_context->parse_sdp_record) break; if (!sdp_query_context.parse_sdp_record) break;
if (de_get_element_type(attribute_value) != DE_DES) break; if (de_get_element_type(attribute_value) != DE_DES) break;
des_iterator_t des_list_0_it; des_iterator_t des_list_0_it;
@ -538,11 +556,11 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){
switch (uuid){ switch (uuid){
case BLUETOOTH_PROTOCOL_L2CAP: case BLUETOOTH_PROTOCOL_L2CAP:
if (!des_iterator_has_more(&prot_it)) continue; if (!des_iterator_has_more(&prot_it)) continue;
de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->browsing_l2cap_psm); de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.browsing_l2cap_psm);
break; break;
case BLUETOOTH_PROTOCOL_AVCTP: case BLUETOOTH_PROTOCOL_AVCTP:
if (!des_iterator_has_more(&prot_it)) continue; if (!des_iterator_has_more(&prot_it)) continue;
de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->browsing_version); de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.browsing_version);
break; break;
default: default:
break; break;
@ -569,9 +587,9 @@ static void avrcp_handle_sdp_query_failed(avrcp_connection_t * connection, uint8
static void avrcp_handle_sdp_query_succeeded(avrcp_connection_t * connection){ static void avrcp_handle_sdp_query_succeeded(avrcp_connection_t * connection){
if (connection == NULL) return; if (connection == NULL) return;
connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
connection->avrcp_l2cap_psm = sdp_query_context->avrcp_l2cap_psm; connection->avrcp_l2cap_psm = sdp_query_context.avrcp_l2cap_psm;
connection->browsing_version = sdp_query_context->browsing_version; connection->browsing_version = sdp_query_context.browsing_version;
connection->browsing_l2cap_psm = sdp_query_context->browsing_l2cap_psm; connection->browsing_l2cap_psm = sdp_query_context.browsing_l2cap_psm;
} }
static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
@ -579,8 +597,19 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c
UNUSED(channel); UNUSED(channel);
UNUSED(size); UNUSED(size);
avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, sdp_query_context->remote_addr); avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, sdp_query_context.avrcp_cid);
avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, sdp_query_context->remote_addr); if (!avrcp_target_connection) {
log_error("SDP query, target connection with 0x%02x cid not found", sdp_query_context.avrcp_cid);
return;
}
if (avrcp_target_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) return;
avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, sdp_query_context.avrcp_cid);
if (!avrcp_controller_connection) {
log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context.avrcp_cid);
return;
}
if (avrcp_controller_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) return;
uint8_t status; uint8_t status;
@ -598,7 +627,7 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c
break; break;
} }
if (!sdp_query_context->avrcp_l2cap_psm){ if (!sdp_query_context.avrcp_l2cap_psm){
avrcp_handle_sdp_query_failed(avrcp_controller_connection, SDP_SERVICE_NOT_FOUND); avrcp_handle_sdp_query_failed(avrcp_controller_connection, SDP_SERVICE_NOT_FOUND);
avrcp_handle_sdp_query_failed(avrcp_target_connection, SDP_SERVICE_NOT_FOUND); avrcp_handle_sdp_query_failed(avrcp_target_connection, SDP_SERVICE_NOT_FOUND);
break; break;
@ -607,13 +636,16 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c
avrcp_handle_sdp_query_succeeded(avrcp_controller_connection); avrcp_handle_sdp_query_succeeded(avrcp_controller_connection);
avrcp_handle_sdp_query_succeeded(avrcp_target_connection); avrcp_handle_sdp_query_succeeded(avrcp_target_connection);
l2cap_create_channel(&avrcp_packet_handler, sdp_query_context->remote_addr, sdp_query_context->avrcp_l2cap_psm, l2cap_max_mtu(), NULL); l2cap_create_channel(&avrcp_packet_handler, avrcp_target_connection->remote_addr, sdp_query_context.avrcp_l2cap_psm, l2cap_max_mtu(), NULL);
break; break;
default: default:
break; break;
} }
// register the SDP Query request to check if there is another connection waiting for the query
// ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
(void) sdp_client_register_query_callback(&avrcp_handle_sdp_client_query_request);
} }
@ -639,7 +671,7 @@ static void avrcp_handle_open_connection(avrcp_connection_t * connection, uint16
connection->playback_status = AVRCP_PLAYBACK_STATUS_ERROR; connection->playback_status = AVRCP_PLAYBACK_STATUS_ERROR;
connection->state = AVCTP_CONNECTION_OPENED; connection->state = AVCTP_CONNECTION_OPENED;
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, state %d", connection->avrcp_cid, connection->l2cap_signaling_cid, connection->role, connection->state);
} }
static void avrcp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ static void avrcp_retry_timer_timeout_handler(btstack_timer_source_t * timer){
@ -736,7 +768,7 @@ static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
if (decline_connection){ if (decline_connection){
l2cap_decline_connection(local_cid); l2cap_decline_connection(local_cid);
} else { } else {
log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION local cid 0x%02x", local_cid); log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION local cid 0x%02x, state %d", local_cid, connection_controller->state);
l2cap_accept_connection(local_cid); l2cap_accept_connection(local_cid);
} }
break; break;
@ -852,25 +884,44 @@ uint8_t avrcp_disconnect(uint16_t avrcp_cid){
return ERROR_CODE_SUCCESS; return ERROR_CODE_SUCCESS;
} }
uint8_t avrcp_start_sdp_query(btstack_packet_handler_t packet_handler, const uint8_t *remote_addr, uint16_t cid) { static void avrcp_handle_start_sdp_client_query(void * context){
sdp_query_context = &avrcp_context; UNUSED(context);
sdp_query_context->avrcp_l2cap_psm = 0;
sdp_query_context->avrcp_version = 0;
sdp_query_context->avrcp_cid = cid;
memcpy(sdp_query_context->remote_addr, remote_addr, 6);
return sdp_client_query_uuid16(packet_handler, (uint8_t *) remote_addr, BLUETOOTH_PROTOCOL_AVCTP); btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &connections);
while (btstack_linked_list_iterator_has_next(&it)){
avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
if (connection->state != AVCTP_CONNECTION_W2_SEND_SDP_QUERY) continue;
connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
// prevent triggering SDP query twice (for each role once)
avrcp_connection_t * connection_with_opposite_role;
switch (connection->role){
case AVRCP_CONTROLLER:
connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, connection->avrcp_cid);
break;
case AVRCP_TARGET:
connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, connection->avrcp_cid);
break;
default:
btstack_assert(false);
return;
}
connection_with_opposite_role->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
sdp_query_context.avrcp_l2cap_psm = 0;
sdp_query_context.avrcp_version = 0;
sdp_query_context.avrcp_cid = connection->avrcp_cid;
sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP);
return;
}
} }
uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){ uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){
btstack_assert(avrcp_controller_packet_handler != NULL); btstack_assert(avrcp_controller_packet_handler != NULL);
btstack_assert(avrcp_target_packet_handler != NULL); btstack_assert(avrcp_target_packet_handler != NULL);
// TODO: implement delayed SDP query
if (sdp_client_ready() == 0){
return ERROR_CODE_COMMAND_DISALLOWED;
}
avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr); avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr);
if (connection_controller){ if (connection_controller){
return ERROR_CODE_COMMAND_DISALLOWED; return ERROR_CODE_COMMAND_DISALLOWED;
@ -895,13 +946,16 @@ uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){
*avrcp_cid = cid; *avrcp_cid = cid;
} }
connection_controller->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; connection_controller->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY;
connection_controller->avrcp_cid = cid; connection_controller->avrcp_cid = cid;
connection_target->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; connection_target->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY;
connection_target->avrcp_cid = cid; connection_target->avrcp_cid = cid;
return avrcp_start_sdp_query(&avrcp_handle_sdp_client_query_result, remote_addr, cid); avrcp_handle_sdp_client_query_request.callback = &avrcp_handle_start_sdp_client_query;
// ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
(void) sdp_client_register_query_callback(&avrcp_handle_sdp_client_query_request);
return ERROR_CODE_SUCCESS;
} }
void avrcp_init(void){ void avrcp_init(void){

View File

@ -294,6 +294,7 @@ typedef enum {
typedef enum { typedef enum {
AVCTP_CONNECTION_IDLE, AVCTP_CONNECTION_IDLE,
AVCTP_CONNECTION_W2_SEND_SDP_QUERY,
AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE, AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE,
AVCTP_CONNECTION_W4_ERTM_CONFIGURATION, AVCTP_CONNECTION_W4_ERTM_CONFIGURATION,
AVCTP_CONNECTION_W4_L2CAP_CONNECTED, AVCTP_CONNECTION_W4_L2CAP_CONNECTED,
@ -555,17 +556,6 @@ typedef struct {
btstack_packet_handler_t browsing_avrcp_callback; btstack_packet_handler_t browsing_avrcp_callback;
btstack_packet_handler_t browsing_packet_handler; btstack_packet_handler_t browsing_packet_handler;
// SDP query
bd_addr_t remote_addr;
uint8_t parse_sdp_record;
uint32_t record_id;
uint16_t avrcp_cid;
uint16_t avrcp_l2cap_psm;
uint16_t avrcp_version;
uint16_t browsing_l2cap_psm;
uint16_t browsing_version;
} avrcp_context_t; } avrcp_context_t;
@ -594,8 +584,8 @@ avrcp_browsing_connection_t * avrcp_get_browsing_connection_for_l2cap_cid_for_ro
void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid); void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid);
uint16_t avrcp_get_next_cid(avrcp_role_t role); uint16_t avrcp_get_next_cid(avrcp_role_t role);
btstack_linked_list_t avrcp_get_connections(void);
uint8_t avrcp_start_sdp_query(btstack_packet_handler_t packet_handler, const uint8_t *remote_addr, uint16_t cid);
uint16_t avrcp_sdp_sdp_query_browsing_l2cap_psm(void); uint16_t avrcp_sdp_sdp_query_browsing_l2cap_psm(void);
void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet); void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet);
avrcp_connection_t * get_avrcp_connection_for_browsing_cid_for_role(avrcp_role_t role, uint16_t browsing_cid); avrcp_connection_t * get_avrcp_connection_for_browsing_cid_for_role(avrcp_role_t role, uint16_t browsing_cid);

View File

@ -49,14 +49,21 @@
#include "classic/sdp_util.h" #include "classic/sdp_util.h"
#include "classic/avrcp_browsing.h" #include "classic/avrcp_browsing.h"
typedef struct {
uint16_t browsing_cid;
uint16_t browsing_l2cap_psm;
uint16_t browsing_version;
} avrcp_browsing_sdp_query_context_t;
static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static btstack_packet_handler_t avrcp_browsing_callback; static btstack_packet_handler_t avrcp_browsing_callback;
static avrcp_browsing_sdp_query_context_t sdp_query_context;
static bool l2cap_browsing_service_registered = false; static bool l2cap_browsing_service_registered = false;
static btstack_packet_handler_t avrcp_browsing_controller_packet_handler; static btstack_packet_handler_t avrcp_browsing_controller_packet_handler;
static btstack_packet_handler_t avrcp_browsing_target_packet_handler; static btstack_packet_handler_t avrcp_browsing_target_packet_handler;
static btstack_context_callback_registration_t avrcp_browsing_handle_sdp_client_query_request;
static bd_addr_t avrcp_browsing_sdp_addr; static bd_addr_t avrcp_browsing_sdp_addr;
@ -387,8 +394,15 @@ static void avrcp_browsing_handle_sdp_client_query_result(uint8_t packet_type, u
UNUSED(channel); UNUSED(channel);
UNUSED(size); UNUSED(size);
avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, avrcp_browsing_sdp_addr); avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_TARGET, sdp_query_context.browsing_cid);
avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, avrcp_browsing_sdp_addr); avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, sdp_query_context.browsing_cid);
if ((avrcp_target_connection == NULL) || (avrcp_target_connection->browsing_connection == NULL)) return;
if (avrcp_target_connection->browsing_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) return;
if ((avrcp_controller_connection == NULL) || (avrcp_controller_connection->browsing_connection == NULL)) return;
if (avrcp_controller_connection->browsing_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) return;
uint8_t status; uint8_t status;
uint16_t browsing_l2cap_psm; uint16_t browsing_l2cap_psm;
@ -416,7 +430,6 @@ static void avrcp_browsing_handle_sdp_client_query_result(uint8_t packet_type, u
break; break;
} }
// l2cap_create_channel(&avrcp_packet_handler, sdp_query_context->remote_addr, sdp_query_context->avrcp_l2cap_psm, l2cap_max_mtu(), NULL);
l2cap_create_ertm_channel(avrcp_browsing_packet_handler, avrcp_browsing_sdp_addr, browsing_l2cap_psm, l2cap_create_ertm_channel(avrcp_browsing_packet_handler, avrcp_browsing_sdp_addr, browsing_l2cap_psm,
&avrcp_controller_connection->browsing_connection->ertm_config, &avrcp_controller_connection->browsing_connection->ertm_config,
avrcp_controller_connection->browsing_connection->ertm_buffer, avrcp_controller_connection->browsing_connection->ertm_buffer,
@ -425,10 +438,52 @@ static void avrcp_browsing_handle_sdp_client_query_result(uint8_t packet_type, u
default: default:
break; break;
}
// register the SDP Query request to check if there is another connection waiting for the query
// ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
(void) sdp_client_register_query_callback(&avrcp_browsing_handle_sdp_client_query_request);
}
static void avrcp_browsing_handle_start_sdp_client_query(void * context){
UNUSED(context);
// TODO
btstack_linked_list_t connections = avrcp_get_connections();
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &connections);
while (btstack_linked_list_iterator_has_next(&it)){
avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
if (connection->browsing_connection == NULL) continue;
if (connection->browsing_connection->state != AVCTP_CONNECTION_W2_SEND_SDP_QUERY) continue;
connection->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
// prevent triggering SDP query twice (for each role once)
avrcp_connection_t * connection_with_opposite_role;
switch (connection->role){
case AVRCP_CONTROLLER:
connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, connection->avrcp_cid);
break;
case AVRCP_TARGET:
connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, connection->avrcp_cid);
break;
default:
btstack_assert(false);
return;
}
if (connection->browsing_connection != NULL){
connection_with_opposite_role->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
}
sdp_query_context.browsing_l2cap_psm = 0;
sdp_query_context.browsing_version = 0;
sdp_query_context.browsing_cid = connection->avrcp_browsing_cid;
sdp_client_query_uuid16(&avrcp_browsing_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP);
return;
} }
} }
uint8_t avrcp_browsing_connect(bd_addr_t remote_addr, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config, uint16_t * avrcp_browsing_cid){ uint8_t avrcp_browsing_connect(bd_addr_t remote_addr, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config, uint16_t * avrcp_browsing_cid){
btstack_assert(avrcp_browsing_controller_packet_handler != NULL); btstack_assert(avrcp_browsing_controller_packet_handler != NULL);
btstack_assert(avrcp_browsing_target_packet_handler != NULL); btstack_assert(avrcp_browsing_target_packet_handler != NULL);
@ -468,9 +523,13 @@ uint8_t avrcp_browsing_connect(bd_addr_t remote_addr, uint8_t * ertm_buffer, uin
if (connection_controller->browsing_l2cap_psm == 0){ if (connection_controller->browsing_l2cap_psm == 0){
memcpy(avrcp_browsing_sdp_addr, remote_addr, 6); memcpy(avrcp_browsing_sdp_addr, remote_addr, 6);
connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; connection_controller->browsing_connection->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY;
connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; connection_target->browsing_connection->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY;
return avrcp_start_sdp_query(&avrcp_browsing_handle_sdp_client_query_result, remote_addr, cid); avrcp_browsing_handle_sdp_client_query_request.callback = &avrcp_browsing_handle_start_sdp_client_query;
// ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
(void) sdp_client_register_query_callback(&avrcp_browsing_handle_sdp_client_query_request);
return ERROR_CODE_SUCCESS;
} else { } else {
connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;