diff --git a/example/a2dp_sink_demo.c b/example/a2dp_sink_demo.c index ebd0d2904..808aacc05 100644 --- a/example/a2dp_sink_demo.c +++ b/example/a2dp_sink_demo.c @@ -715,7 +715,9 @@ static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channe case AVRCP_SUBEVENT_OPERATION_START: printf("AVRCP Controller: %s start\n", avrcp_operation2str(avrcp_subevent_operation_start_get_operation_id(packet))); break; - + case AVRCP_SUBEVENT_NOTIFICATION_EVENT_TRACK_REACHED_END: + printf("AVRCP Controller: Track reached end\n"); + break; default: printf("AVRCP Controller: Event 0x%02x is not parsed\n", packet[2]); break; @@ -963,7 +965,7 @@ static void stdin_process(char cmd){ break; case 'B': 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; case 'c': 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; } 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 diff --git a/src/classic/avrcp.c b/src/classic/avrcp.c index b47fe6f08..6e444805c 100644 --- a/src/classic/avrcp.c +++ b/src/classic/avrcp.c @@ -49,6 +49,19 @@ #include "classic/sdp_util.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 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 avrcp_context_t * sdp_query_context; -static avrcp_context_t avrcp_context; +static btstack_context_callback_registration_t avrcp_handle_sdp_client_query_request; + +static avrcp_sdp_query_context_t sdp_query_context; static btstack_packet_handler_t avrcp_callback; @@ -172,6 +186,10 @@ const char * avrcp_repeat2str(uint8_t index){ 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 cmd_opcode_index = 5; 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){ - 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){ @@ -447,9 +465,9 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ des_iterator_t prot_it; // Handle new SDP record - 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->parse_sdp_record = 0; + 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.parse_sdp_record = 0; // 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: case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER: - sdp_query_context->parse_sdp_record = 1; + sdp_query_context.parse_sdp_record = 1; break; default: break; @@ -477,7 +495,7 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ break; 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)); 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; @@ -497,11 +515,11 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ switch (uuid){ case BLUETOOTH_PROTOCOL_L2CAP: 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; case BLUETOOTH_PROTOCOL_AVCTP: 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; default: break; @@ -511,7 +529,7 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ break; case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: { // 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; des_iterator_t des_list_0_it; @@ -538,11 +556,11 @@ void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ switch (uuid){ case BLUETOOTH_PROTOCOL_L2CAP: 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; case BLUETOOTH_PROTOCOL_AVCTP: 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; default: 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){ if (connection == NULL) return; connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; - connection->avrcp_l2cap_psm = sdp_query_context->avrcp_l2cap_psm; - connection->browsing_version = sdp_query_context->browsing_version; - connection->browsing_l2cap_psm = sdp_query_context->browsing_l2cap_psm; + connection->avrcp_l2cap_psm = sdp_query_context.avrcp_l2cap_psm; + connection->browsing_version = sdp_query_context.browsing_version; + 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){ @@ -579,8 +597,19 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c UNUSED(channel); 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_controller_connection = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, 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); + 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; @@ -598,7 +627,7 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c 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_target_connection, SDP_SERVICE_NOT_FOUND); 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_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; default: 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->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){ @@ -736,7 +768,7 @@ static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t if (decline_connection){ l2cap_decline_connection(local_cid); } 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); } break; @@ -852,25 +884,44 @@ uint8_t avrcp_disconnect(uint16_t avrcp_cid){ return ERROR_CODE_SUCCESS; } -uint8_t avrcp_start_sdp_query(btstack_packet_handler_t packet_handler, const uint8_t *remote_addr, uint16_t cid) { - sdp_query_context = &avrcp_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); +static void avrcp_handle_start_sdp_client_query(void * context){ + UNUSED(context); - 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){ btstack_assert(avrcp_controller_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); if (connection_controller){ 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; } - connection_controller->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; + connection_controller->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 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; - 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){ diff --git a/src/classic/avrcp.h b/src/classic/avrcp.h index 6b6611f67..9a2e79d1d 100644 --- a/src/classic/avrcp.h +++ b/src/classic/avrcp.h @@ -294,6 +294,7 @@ typedef enum { typedef enum { AVCTP_CONNECTION_IDLE, + AVCTP_CONNECTION_W2_SEND_SDP_QUERY, AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE, AVCTP_CONNECTION_W4_ERTM_CONFIGURATION, AVCTP_CONNECTION_W4_L2CAP_CONNECTED, @@ -555,17 +556,6 @@ typedef struct { btstack_packet_handler_t browsing_avrcp_callback; 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; @@ -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); 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); 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); diff --git a/src/classic/avrcp_browsing.c b/src/classic/avrcp_browsing.c index 727d39f9e..ed937341a 100644 --- a/src/classic/avrcp_browsing.c +++ b/src/classic/avrcp_browsing.c @@ -49,14 +49,21 @@ #include "classic/sdp_util.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 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 btstack_packet_handler_t avrcp_browsing_controller_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; @@ -387,8 +394,15 @@ static void avrcp_browsing_handle_sdp_client_query_result(uint8_t packet_type, u UNUSED(channel); 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_controller_connection = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, 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_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; uint16_t browsing_l2cap_psm; @@ -416,7 +430,6 @@ static void avrcp_browsing_handle_sdp_client_query_result(uint8_t packet_type, u 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, &avrcp_controller_connection->browsing_connection->ertm_config, 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: 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){ btstack_assert(avrcp_browsing_controller_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){ memcpy(avrcp_browsing_sdp_addr, remote_addr, 6); - connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; - connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; - return avrcp_start_sdp_query(&avrcp_browsing_handle_sdp_client_query_result, remote_addr, cid); + connection_controller->browsing_connection->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; + connection_target->browsing_connection->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; + 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 { connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;