From 2f0acaf70c0e9fb38956385d868c32270b46a6e3 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Fri, 21 Apr 2023 12:28:59 +0200 Subject: [PATCH] avrcp_browsing: reuse avrcp sdp query --- src/classic/avrcp_browsing.c | 166 +++++++++++++---------------------- 1 file changed, 61 insertions(+), 105 deletions(-) diff --git a/src/classic/avrcp_browsing.c b/src/classic/avrcp_browsing.c index 63ca4ac0a..e6ece1d7a 100644 --- a/src/classic/avrcp_browsing.c +++ b/src/classic/avrcp_browsing.c @@ -384,12 +384,65 @@ static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, } -void avrcp_browsing_init(void){ - if (avrcp_browsing_l2cap_service_registered) return; - int status = l2cap_register_service(&avrcp_browsing_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_2); +static void avrcp_browsing_handle_sdp_query_complete(avrcp_connection_t * connection, uint8_t status){ - if (status != ERROR_CODE_SUCCESS) return; - avrcp_browsing_l2cap_service_registered = true; + if (connection->browsing_connection == NULL) { + return; + } + if (connection->browsing_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE){ + return; + } + + // l2cap available? + if (status == ERROR_CODE_SUCCESS){ + if (connection->browsing_l2cap_psm == 0){ + status = SDP_SERVICE_NOT_FOUND; + } + } + + if (status == ERROR_CODE_SUCCESS) { + // ready to connect + connection->browsing_connection->state = AVCTP_CONNECTION_W2_L2CAP_CONNECT; + + // check if both events have been handled + 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_with_opposite_role->browsing_connection->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) { + + connection->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; + connection_with_opposite_role->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; + + l2cap_ertm_create_channel(avrcp_browsing_packet_handler, + connection->remote_addr, + connection->browsing_l2cap_psm, + &connection->browsing_connection->ertm_config, + connection->browsing_connection->ertm_buffer, + connection->browsing_connection->ertm_buffer_size, + NULL); + } + } else { + avrcp_browsing_finalize_connection(connection); + avrcp_browsing_emit_connection_established(connection->avrcp_browsing_cid, connection->remote_addr, status); + } +} + +void avrcp_browsing_init(void){ + avrcp_register_browsing_sdp_query_complete_handler(&avrcp_browsing_handle_sdp_query_complete); + if (avrcp_browsing_l2cap_service_registered) return; + uint8_t status = l2cap_register_service(&avrcp_browsing_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_2); + avrcp_browsing_l2cap_service_registered = status == ERROR_CODE_SUCCESS; } void avrcp_browsing_deinit(void){ @@ -404,101 +457,6 @@ void avrcp_browsing_deinit(void){ avrcp_browsing_l2cap_service_registered = false; } -static void avrcp_browsing_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ - UNUSED(packet_type); - UNUSED(channel); - UNUSED(size); - - avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_sdp_query_context.browsing_cid); - avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_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; - - switch (hci_event_packet_get_type(packet)){ - case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: - avrcp_handle_sdp_client_query_attribute_value(packet); - break; - - case SDP_EVENT_QUERY_COMPLETE: - status = sdp_event_query_complete_get_status(packet); - - if (status != ERROR_CODE_SUCCESS){ - avrcp_browsing_emit_connection_established(avrcp_target_connection->avrcp_browsing_cid, avrcp_browsing_sdp_addr, status); - avrcp_browsing_finalize_connection(avrcp_target_connection); - avrcp_browsing_finalize_connection(avrcp_controller_connection); - break; - } - - browsing_l2cap_psm = avrcp_sdp_query_browsing_l2cap_psm(); - if (!browsing_l2cap_psm){ - avrcp_browsing_emit_connection_established(avrcp_target_connection->avrcp_browsing_cid, avrcp_browsing_sdp_addr, SDP_SERVICE_NOT_FOUND); - avrcp_browsing_finalize_connection(avrcp_target_connection); - avrcp_browsing_finalize_connection(avrcp_controller_connection); - break; - } - - l2cap_ertm_create_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, - avrcp_controller_connection->browsing_connection->ertm_buffer_size, 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_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; - } - - avrcp_browsing_sdp_query_context.browsing_l2cap_psm = 0; - avrcp_browsing_sdp_query_context.browsing_version = 0; - avrcp_browsing_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); @@ -538,12 +496,10 @@ 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_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; + connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; + connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; - // 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); + avrcp_trigger_sdp_query(connection_controller, connection_target); return ERROR_CODE_SUCCESS; } else { connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;