diff --git a/src/classic/avdtp.h b/src/classic/avdtp.h index b97f3c674..d6f0fdf5a 100644 --- a/src/classic/avdtp.h +++ b/src/classic/avdtp.h @@ -337,6 +337,7 @@ typedef struct { typedef enum { AVDTP_SIGNALING_CONNECTION_IDLE, + AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE, AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED, AVDTP_SIGNALING_CONNECTION_OPENED, AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED diff --git a/src/classic/avdtp_source.c b/src/classic/avdtp_source.c index 7d4592bb8..13ef1cc82 100644 --- a/src/classic/avdtp_source.c +++ b/src/classic/avdtp_source.c @@ -52,9 +52,13 @@ #include "avdtp_source.h" static avdtp_context_t * avdtp_source_context; - +static avdtp_connection_t * avtdp_connection_doing_sdp_query = NULL; +static int record_id = -1; static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); +static uint8_t attribute_value[1000]; +static const unsigned int attribute_value_buffer_size = sizeof(attribute_value); + void avdtp_source_register_media_transport_category(uint8_t seid){ avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, avdtp_source_context); avdtp_register_media_transport_category(stream_endpoint); @@ -107,14 +111,118 @@ void avdtp_source_register_packet_handler(btstack_packet_handler_t callback){ avdtp_source_context->avdtp_callback = callback; } -void avdtp_source_connect(bd_addr_t bd_addr){ - avdtp_connection_t * connection = avdtp_connection_for_bd_addr(bd_addr, avdtp_source_context); +static void avdtp_source_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); + + des_iterator_t des_list_it; + des_iterator_t prot_it; + uint32_t avdtp_remote_uuid = 0; + uint16_t avdtp_l2cap_psm = 0; + uint16_t avdtp_version = 0; + + if (!avtdp_connection_doing_sdp_query) return; + + switch (hci_event_packet_get_type(packet)){ + case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: + // Handle new SDP record + if (sdp_event_query_attribute_byte_get_record_id(packet) != record_id) { + record_id = sdp_event_query_attribute_byte_get_record_id(packet); + printf("SDP Record: Nr: %d\n", record_id); + } + + if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { + attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); + + if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { + + switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { + case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: + if (de_get_element_type(attribute_value) != DE_DES) break; + for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { + uint8_t * element = des_iterator_get_element(&des_list_it); + if (de_get_element_type(element) != DE_UUID) continue; + uint32_t uuid = de_get_uuid32(element); + switch (uuid){ + case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE: + printf("SDP Attribute 0x%04x: AVDTP SOURCE protocol UUID: 0x%04x\n", sdp_event_query_attribute_byte_get_attribute_id(packet), uuid); + avdtp_remote_uuid = uuid; + break; + case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK: + printf("SDP Attribute 0x%04x: AVDTP SINK protocol UUID: 0x%04x\n", sdp_event_query_attribute_byte_get_attribute_id(packet), uuid); + avdtp_remote_uuid = uuid; + break; + default: + break; + } + } + break; + + case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: { + printf("SDP Attribute: 0x%04x\n", 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; + uint8_t *element; + uint32_t uuid; + + if (des_iterator_get_type(&des_list_it) != DE_DES) continue; + + des_element = des_iterator_get_element(&des_list_it); + des_iterator_init(&prot_it, des_element); + element = des_iterator_get_element(&prot_it); + + if (de_get_element_type(element) != DE_UUID) continue; + + uuid = de_get_uuid32(element); + switch (uuid){ + case BLUETOOTH_PROTOCOL_L2CAP: + if (!des_iterator_has_more(&prot_it)) continue; + des_iterator_next(&prot_it); + de_element_get_uint16(des_iterator_get_element(&prot_it), &avdtp_l2cap_psm); + break; + case BLUETOOTH_PROTOCOL_AVDTP: + if (!des_iterator_has_more(&prot_it)) continue; + des_iterator_next(&prot_it); + de_element_get_uint16(des_iterator_get_element(&prot_it), &avdtp_version); + break; + default: + break; + } + } + printf("l2cap_psm 0x%04x, avdtp_version 0x%04x\n", avdtp_l2cap_psm, avdtp_version); + + /* Create AVDTP connection */ + avtdp_connection_doing_sdp_query->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; + l2cap_create_channel(packet_handler, avtdp_connection_doing_sdp_query->remote_addr, avdtp_l2cap_psm, l2cap_max_mtu(), NULL); + } + break; + default: + break; + } + } + } else { + fprintf(stderr, "SDP attribute value buffer size exceeded: available %d, required %d\n", attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet)); + } + break; + + case SDP_EVENT_QUERY_COMPLETE: + fprintf(stderr, "General query done with status %d.\n", sdp_event_query_complete_get_status(packet)); + break; + } +} + +void avdtp_source_connect(bd_addr_t remote){ + avtdp_connection_doing_sdp_query = NULL; + avdtp_connection_t * connection = avdtp_connection_for_bd_addr(remote, avdtp_source_context); if (!connection){ - connection = avdtp_create_connection(bd_addr, avdtp_source_context); + connection = avdtp_create_connection(remote, avdtp_source_context); } if (connection->state != AVDTP_SIGNALING_CONNECTION_IDLE) return; - connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; - l2cap_create_channel(packet_handler, connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, NULL); + avtdp_connection_doing_sdp_query = connection; + connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE; + sdp_client_query_uuid16(&avdtp_source_handle_sdp_client_query_result, remote, BLUETOOTH_PROTOCOL_AVDTP); } void avdtp_source_disconnect(uint16_t con_handle){ diff --git a/test/avdtp/Makefile b/test/avdtp/Makefile index 892e17fd2..a54580edb 100644 --- a/test/avdtp/Makefile +++ b/test/avdtp/Makefile @@ -26,7 +26,8 @@ COMMON += \ le_device_db_fs.c \ wav_util.c \ sdp_util.c \ - sdp_server.c \ + sdp_server.c \ + sdp_client.c \ CFLAGS += -g -Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wunused-variable -Wunused-parameter -Werror CFLAGS += -I.