avdtp: differentiate SDP queries towards sink and source

This commit is contained in:
Milanka Ringwald 2020-07-10 10:34:00 +02:00
parent bd6f65db86
commit 149deddbd9
6 changed files with 93 additions and 73 deletions

View File

@ -240,7 +240,6 @@ static void a2dp_signaling_emit_reconfigured(btstack_packet_handler_t callback,
static void a2dp_source_set_config_timer_handler(btstack_timer_source_t * ts){
UNUSED(ts);
log_info("a2dp_source_set_config_timer_handler, app state %u", app_state);
if (app_state != A2DP_CONNECTED) return;
app_state = A2DP_W2_DISCOVER_SEPS;
avdtp_source_discover_stream_endpoints(sc.avdtp_cid);
@ -278,12 +277,12 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
status = avdtp_subevent_signaling_connection_established_get_status(packet);
if (status != 0){
log_info("AVDTP_SUBEVENT_SIGNALING_CONNECTION failed status %d ---", status);
log_info("A2DP singnaling connection failed status %d", status);
app_state = A2DP_IDLE;
a2dp_signaling_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, status);
break;
}
log_info("A2DP_SUBEVENT_SIGNALING_CONNECTION established avdtp_cid 0x%02x ---", a2dp_source_context.avdtp_cid);
log_info("A2DP singnaling connection established avdtp_cid 0x%02x", a2dp_source_context.avdtp_cid);
sc.avdtp_cid = cid;
sc.active_remote_sep = NULL;
@ -292,11 +291,12 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
memset(remote_seps, 0, sizeof(avdtp_sep_t) * AVDTP_MAX_SEP_NUM);
// if we initiated the connection, start config right away, else wait a bit to give remote a chance to do it first
log_info("A2DP_SUBEVENT_SIGNALING_CONNECTION app_state %u", app_state);
if (app_state == A2DP_W4_CONNECTED){
log_info("A2DP singnaling connection: discover seps");
app_state = A2DP_W2_DISCOVER_SEPS;
avdtp_source_discover_stream_endpoints(sc.avdtp_cid);
} else {
log_info("A2DP singnaling connection: wait a bit, then discover seps");
app_state = A2DP_CONNECTED;
a2dp_source_set_config_timer_start();
}

View File

@ -245,6 +245,8 @@ static uint8_t avdtp_start_sdp_query(btstack_packet_handler_t packet_handler, av
sdp_query_context->avdtp_l2cap_psm = 0;
sdp_query_context->avdtp_version = 0;
sdp_query_context->avdtp_cid = cid;
sdp_query_context->sink_supported = false;
sdp_query_context->source_supported = false;
memcpy(sdp_query_context->remote_addr, remote_addr, 6);
return sdp_client_query_uuid16(packet_handler, (uint8_t *) remote_addr, BLUETOOTH_PROTOCOL_AVDTP);
@ -269,11 +271,18 @@ uint8_t avdtp_connect(bd_addr_t remote, avdtp_context_t * avdtp_context, uint16_
connection = avdtp_create_connection(remote, cid);
if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED;
connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE;
connection->avdtp_cid = cid;
avdtp_context->avdtp_cid = cid;
switch (avdtp_context->role){
case AVDTP_ROLE_SOURCE:
connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE;
break;
case AVDTP_ROLE_SINK:
connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE;
break;
default:
return ERROR_CODE_COMMAND_DISALLOWED;
}
return avdtp_start_sdp_query(&avdtp_handle_sdp_client_query_result, avdtp_context, remote, cid);
}
@ -456,6 +465,7 @@ static void avdtp_handle_sdp_client_query_attribute_value(uint8_t *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)) {
@ -464,20 +474,12 @@ static void avdtp_handle_sdp_client_query_attribute_value(uint8_t *packet){
uint32_t uuid = de_get_uuid32(element);
switch (uuid){
case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE:
if (sdp_query_context->query_role == AVDTP_SOURCE) {
sdp_query_context->role_supported = 1;
break;
}
// log_info("SDP Attribute 0x%04x: AVDTP SOURCE protocol UUID: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet), uuid);
// avdtp_remote_uuid = uuid;
sdp_query_context->source_supported = true;
log_info("source_supported");
break;
case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK:
if (sdp_query_context->query_role == AVDTP_SINK) {
sdp_query_context->role_supported = 1;
break;
}
// log_info("SDP Attribute 0x%04x: AVDTP SINK protocol UUID: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet), uuid);
// avdtp_remote_uuid = uuid;
sdp_query_context->sink_supported = true;
log_info("sink_supported");
break;
default:
break;
@ -485,7 +487,7 @@ static void avdtp_handle_sdp_client_query_attribute_value(uint8_t *packet){
}
break;
case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: {
case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
// 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;
@ -502,10 +504,11 @@ static void avdtp_handle_sdp_client_query_attribute_value(uint8_t *packet){
uuid = de_get_uuid32(element);
des_iterator_next(&prot_it);
// we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both
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->avdtp_l2cap_psm);
de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avdtp_l2cap_psm);
break;
case BLUETOOTH_PROTOCOL_AVDTP:
if (!des_iterator_has_more(&prot_it)) continue;
@ -515,8 +518,8 @@ static void avdtp_handle_sdp_client_query_attribute_value(uint8_t *packet){
break;
}
}
}
break;
default:
break;
}
@ -547,45 +550,64 @@ static void avdtp_handle_sdp_query_succeeded(avdtp_connection_t * connection){
}
static void avdtp_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);
avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(sdp_query_context->avdtp_cid);
if (!connection) {
log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context->avdtp_cid);
return;
}
if (connection->state != AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE) return;
UNUSED(packet_type);
UNUSED(channel);
UNUSED(size);
uint8_t status;
switch (hci_event_packet_get_type(packet)){
case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
avdtp_handle_sdp_client_query_attribute_value(packet);
bool query_succeded = false;
switch (connection->state){
case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE:
switch (hci_event_packet_get_type(packet)){
case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
avdtp_handle_sdp_client_query_attribute_value(packet);
return;
case SDP_EVENT_QUERY_COMPLETE:
status = sdp_event_query_complete_get_status(packet);
if (status != ERROR_CODE_SUCCESS) break;
if (!sdp_query_context->sink_supported) break;
if (sdp_query_context->avdtp_l2cap_psm == 0) break;
query_succeded = true;
break;
default:
btstack_assert(false);
break;
}
break;
case SDP_EVENT_QUERY_COMPLETE:
if (connection->state != AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE){
// bail out, we must have had an incoming connection in the meantime;
break;
case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE:
switch (hci_event_packet_get_type(packet)){
case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
avdtp_handle_sdp_client_query_attribute_value(packet);
return;
case SDP_EVENT_QUERY_COMPLETE:
status = sdp_event_query_complete_get_status(packet);
if (status != ERROR_CODE_SUCCESS) break;
if (!sdp_query_context->source_supported) break;
if (sdp_query_context->avdtp_l2cap_psm == 0) break;
query_succeded = true;
break;
default:
btstack_assert(false);
break;
}
status = sdp_event_query_complete_get_status(packet);
if (status != ERROR_CODE_SUCCESS){
avdtp_handle_sdp_query_failed(connection, status);
break;
}
if (!sdp_query_context->role_supported){
avdtp_handle_sdp_query_failed(connection, status);
break;
}
if (!sdp_query_context->avdtp_l2cap_psm) {
avdtp_handle_sdp_query_failed(connection, status);
break;
}
avdtp_handle_sdp_query_succeeded(connection);
break;
default:
// bail out, we must have had an incoming connection in the meantime;
return;
}
l2cap_create_channel(sdp_query_context->packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL);
break;
if (query_succeded){
avdtp_handle_sdp_query_succeeded(connection);
l2cap_create_channel(sdp_query_context->packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL);
} else {
avdtp_handle_sdp_query_failed(connection, status);
}
}

View File

@ -133,13 +133,13 @@ typedef enum {
AVDTP_RESPONSE_REJECT_MSG
} avdtp_message_type_t;
typedef enum{
typedef enum {
AVDTP_AUDIO = 0,
AVDTP_VIDEO,
AVDTP_MULTIMEDIA
} avdtp_media_type_t;
typedef enum{
typedef enum {
AVDTP_CODEC_SBC = 0x00,
AVDTP_CODEC_MPEG_1_2_AUDIO = 0x01,
AVDTP_CODEC_MPEG_2_4_AAC = 0x02,
@ -147,24 +147,21 @@ typedef enum{
AVDTP_CODEC_NON_A2DP = 0xFF
} avdtp_media_codec_type_t;
typedef enum{
typedef enum {
AVDTP_CONTENT_PROTECTION_DTCP = 0x0001,
AVDTP_CONTENT_PROTECTION_SCMS_T = 0x0002
} avdtp_content_protection_type_t;
typedef enum{
typedef enum {
AVDTP_SOURCE = 0,
AVDTP_SINK
} avdtp_sep_type_t;
typedef enum{
typedef enum {
AVDTP_ROLE_SOURCE = 0,
AVDTP_ROLE_SINK,
AVDTP_ROLE_SINK_AND_SOURCE,
AVDTP_ROLE_UNKNOWN
AVDTP_ROLE_SINK
} avdtp_role_t;
typedef enum {
AVDTP_SERVICE_CATEGORY_INVALID_0 = 0x00,
AVDTP_MEDIA_TRANSPORT = 0X01,
@ -351,7 +348,8 @@ typedef struct {
typedef enum {
AVDTP_SIGNALING_CONNECTION_IDLE,
AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE,
AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE,
AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE,
AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED,
AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY,
AVDTP_SIGNALING_CONNECTION_OPENED,
@ -551,7 +549,8 @@ typedef struct {
void (*handle_media_data)(uint8_t local_seid, uint8_t *packet, uint16_t size);
btstack_packet_handler_t packet_handler;
avdtp_sep_type_t query_role;
//avdtp_sep_type_t query_role;
avdtp_role_t role;
// SDP query
@ -559,7 +558,8 @@ typedef struct {
uint16_t avdtp_cid;
uint16_t avdtp_l2cap_psm;
uint16_t avdtp_version;
uint8_t role_supported;
bool sink_supported;
bool source_supported;
} avdtp_context_t;
extern avdtp_context_t * avdtp_source_context;

View File

@ -278,27 +278,27 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_
static bool avdtp_initiator_stream_config_subsm_run_signaling(avdtp_connection_t * connection){
switch (connection->initiator_connection_state){
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS:
log_info("INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS");
log_info("INT: W2_DISCOVER_SEPS");
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER;
avdtp_initiator_send_signaling_cmd(connection->l2cap_signaling_cid, AVDTP_SI_DISCOVER, connection->initiator_transaction_label);
return true;
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES:
log_info("INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES");
log_info("INT: W2_GET_CAPABILITIES");
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_GET_CAPABILITIES, connection->initiator_transaction_label, connection->initiator_remote_seid);
return true;
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES:
log_info("INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES");
log_info("INT: W2_GET_ALL_CAPABILITIES");
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_GET_ALL_CAPABILITIES, connection->initiator_transaction_label, connection->initiator_remote_seid);
return true;
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION:
log_info("INT: AVDTP_INITIATOR_W4_GET_CONFIGURATION");
log_info("INT: W4_GET_CONFIGURATION");
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_GET_CONFIGURATION, connection->initiator_transaction_label, connection->initiator_remote_seid);
return true;
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_DELAY_REPORT:
log_info("INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_DELAY_REPORT");
log_info("INT: W4_DELAY_REPORT");
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER;
avdtp_initiator_send_signaling_cmd_delay_report(connection->l2cap_signaling_cid, connection->initiator_transaction_label,
connection->initiator_remote_seid, connection->delay_ms);
@ -317,7 +317,7 @@ static void avdtp_initiator_stream_config_subsm_run_endpoint(avdtp_connection_t
log_info("initiator SM stop sending SET_CONFIGURATION cmd:");
break;
}
log_info("INT: AVDTP_INITIATOR_W2_(RE)CONFIGURATION bitmap, local seid %d, remote seid 0x%02x", connection->initiator_local_seid, connection->initiator_remote_seid);
log_info("INT: W2_(RE)CONFIGURATION bitmap, local seid %d, remote seid 0x%02x", connection->initiator_local_seid, connection->initiator_remote_seid);
// log_info_hexdump( connection->remote_capabilities.media_codec.media_codec_information, connection->remote_capabilities.media_codec.media_codec_information_len);
connection->initiator_signaling_packet.acp_seid = connection->initiator_remote_seid;
connection->initiator_signaling_packet.int_seid = connection->initiator_local_seid;

View File

@ -115,7 +115,6 @@ void avdtp_sink_init(avdtp_context_t * avdtp_context){
avdtp_sink_context = avdtp_context;
avdtp_sink_context->stream_endpoints = NULL;
avdtp_sink_context->stream_endpoints_id_counter = 0;
avdtp_sink_context->query_role = AVDTP_SOURCE;
avdtp_sink_context->packet_handler = packet_handler;
avdtp_sink_context->role = AVDTP_ROLE_SINK;

View File

@ -172,7 +172,6 @@ void avdtp_source_init(avdtp_context_t * avdtp_context){
avdtp_source_context = avdtp_context;
avdtp_source_context->stream_endpoints = NULL;
avdtp_source_context->stream_endpoints_id_counter = 0;
avdtp_source_context->query_role = AVDTP_SINK;
avdtp_source_context->packet_handler = packet_handler;
avdtp_source_context->role = AVDTP_ROLE_SOURCE;