From a0b8a58cf86bb5dcb706e025ce3ffb1106a93d23 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Fri, 25 Aug 2017 16:48:50 +0200 Subject: [PATCH] avdtp: on connect request, check if streaming is already established --- src/classic/avdtp.c | 108 ++++++++++++++++++++------------------- src/classic/avdtp_util.c | 18 +++++++ src/classic/avdtp_util.h | 1 + 3 files changed, 74 insertions(+), 53 deletions(-) diff --git a/src/classic/avdtp.c b/src/classic/avdtp.c index 0396a4daa..0555199f0 100644 --- a/src/classic/avdtp.c +++ b/src/classic/avdtp.c @@ -109,7 +109,6 @@ uint8_t avdtp_connect(bd_addr_t remote, avdtp_sep_type_t query_role, avdtp_conte if (!avdtp_cid) { return L2CAP_LOCAL_CID_DOES_NOT_EXIST; } - avdtp_context->avdtp_cid = connection->avdtp_cid; uint8_t err; @@ -127,9 +126,15 @@ uint8_t avdtp_connect(bd_addr_t remote, avdtp_sep_type_t query_role, avdtp_conte btstack_memory_avdtp_connection_free(connection); } return err; - case AVDTP_SIGNALING_CONNECTION_OPENED: + case AVDTP_SIGNALING_CONNECTION_OPENED:{ + avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid, avdtp_context); + if (stream_endpoint){ + avdtp_streaming_emit_connection_established(avdtp_context->avdtp_callback, connection->avdtp_cid, remote, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), 0); + break; + } avdtp_signaling_emit_connection_established(avdtp_context->avdtp_callback, avdtp_context->avdtp_cid, connection->remote_addr, ERROR_CODE_SUCCESS); break; + } default: log_error("avdtp_connect: sink in wrong state"); return AVDTP_CONNECTION_IN_WRONG_STATE; @@ -335,36 +340,32 @@ static void stream_endpoint_state_machine(avdtp_connection_t * connection, avdtp switch (event){ case L2CAP_EVENT_CHANNEL_OPENED: l2cap_event_channel_opened_get_address(packet, address); - if (stream_endpoint->l2cap_media_cid != 0){ - log_error("stream_endpoint_state_machine: channel already opened\n"); - avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), L2CAP_SERVICE_ALREADY_REGISTERED); + if (stream_endpoint->l2cap_media_cid == 0){ + status = l2cap_event_channel_opened_get_status(packet); + if (status){ + log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED failed with status %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", status, connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint)); + stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; + avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), status); + break; + } + if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED){ + log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED failed - stream endpoint in wrong state %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", stream_endpoint->state, connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint)); + avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE); + break; + } + stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED; + stream_endpoint->connection = connection; + stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet); + stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet); + log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint)); + avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), 0); return; } - - if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED){ - log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED failed - stream endpoint in wrong state %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", stream_endpoint->state, connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint)); - avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE); - break; - } - - status = l2cap_event_channel_opened_get_status(packet); - if (status){ - log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED failed with status %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", status, connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint)); - stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; - avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), status); - break; - } - - stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED; - stream_endpoint->connection = connection; - stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet); - stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet); - log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint)); - avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), 0); break; case L2CAP_EVENT_CHANNEL_CLOSED: local_cid = l2cap_event_channel_closed_get_local_cid(packet); + log_info("L2CAP_EVENT_CHANNEL_CLOSED stream endpoint sm: media cid 0x%02x, local cid 0x%02x\n", stream_endpoint->l2cap_media_cid , local_cid); if (stream_endpoint->l2cap_media_cid == local_cid){ avdtp_streaming_emit_connection_released(context->avdtp_callback, connection->avdtp_cid, avdtp_local_seid(stream_endpoint)); stream_endpoint->l2cap_media_cid = 0; @@ -606,42 +607,46 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet break; case L2CAP_EVENT_CHANNEL_OPENED: + psm = l2cap_event_channel_opened_get_psm(packet); + if (psm != BLUETOOTH_PROTOCOL_AVDTP){ + log_info("unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED"); + return; + } + status = l2cap_event_channel_opened_get_status(packet); // inform about new l2cap connection l2cap_event_channel_opened_get_address(packet, event_addr); local_cid = l2cap_event_channel_opened_get_local_cid(packet); - if (status){ - log_error("L2CAP connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); - if (connection){ + connection = avdtp_connection_for_bd_addr(event_addr, context); + + log_info("L2CAP_EVENT_CHANNEL_OPENED: status %d, cid 0x%02x , signaling connection %p \n", status, local_cid, connection); + connection = avdtp_connection_for_bd_addr(event_addr, context); + if (!connection){ + log_info("L2CAP_EVENT_CHANNEL_OPENED 2: status %d, signaling connection %p \n", status, connection); + break; + } + + if (connection->l2cap_signaling_cid == 0) { + if (status){ + log_info("L2CAP connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); connection->state = AVDTP_SIGNALING_CONNECTION_IDLE; + connection->l2cap_signaling_cid = 0; avdtp_signaling_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, event_addr, l2cap_event_channel_opened_get_status(packet)); break; - } - } - - psm = l2cap_event_channel_opened_get_psm(packet); - if (psm != BLUETOOTH_PROTOCOL_AVDTP){ - log_error("unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED"); - return; - } - // log_info("L2CAP_EVENT_CHANNEL_OPENED: Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x", - // bd_addr_to_str(event_addr), l2cap_event_channel_opened_get_handle(packet), psm, local_cid, l2cap_event_channel_opened_get_remote_cid(packet)); - - if (psm != BLUETOOTH_PROTOCOL_AVDTP) break; - - connection = avdtp_connection_for_bd_addr(event_addr, context); - if (!connection) break; - - if (connection->l2cap_signaling_cid == 0) { - if (connection->state != AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED) break; + } + if (connection->state != AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED) { + log_info("L2CAP connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); + avdtp_signaling_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, event_addr, AVDTP_CONNECTION_IN_WRONG_STATE); + break; + } connection->l2cap_signaling_cid = local_cid; connection->local_seid = 0; connection->state = AVDTP_SIGNALING_CONNECTION_OPENED; - log_info(" -> AVDTP_SIGNALING_CONNECTION_OPENED, connection %p, avdtp_cid 0x%02x", connection, connection->avdtp_cid); + log_info(" -> AVDTP_SIGNALING_CONNECTION_OPENED, connection %p, avdtp_cid 0x%02x", connection, local_cid); avdtp_signaling_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, event_addr, 0); break; } - + stream_endpoint = avdtp_stream_endpoint_for_seid(connection->local_seid, context); if (!stream_endpoint){ log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found"); @@ -657,10 +662,7 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet log_info("received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, %p, %p\n", local_cid, connection, stream_endpoint); if (stream_endpoint){ - if (!connection){ - connection = stream_endpoint->connection; - } - stream_endpoint_state_machine(connection, stream_endpoint, HCI_EVENT_PACKET, L2CAP_EVENT_CHANNEL_CLOSED, packet, size, context); + stream_endpoint_state_machine(stream_endpoint->connection, stream_endpoint, HCI_EVENT_PACKET, L2CAP_EVENT_CHANNEL_CLOSED, packet, size, context); break; } diff --git a/src/classic/avdtp_util.c b/src/classic/avdtp_util.c index 116dff5da..77e834eb7 100644 --- a/src/classic/avdtp_util.c +++ b/src/classic/avdtp_util.c @@ -144,6 +144,20 @@ avdtp_stream_endpoint_t * avdtp_stream_endpoint_for_l2cap_cid(uint16_t l2cap_cid return NULL; } +avdtp_stream_endpoint_t * avdtp_stream_endpoint_for_signaling_cid(uint16_t l2cap_cid, avdtp_context_t * context){ + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, &context->stream_endpoints); + while (btstack_linked_list_iterator_has_next(&it)){ + avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); + if (stream_endpoint->connection){ + if (stream_endpoint->connection->l2cap_signaling_cid == l2cap_cid){ + return stream_endpoint; + } + } + } + return NULL; +} + avdtp_stream_endpoint_t * avdtp_stream_endpoint_with_seid(uint8_t seid, avdtp_context_t * context){ btstack_linked_list_iterator_t it; btstack_linked_list_iterator_init(&it, &context->stream_endpoints); @@ -811,14 +825,17 @@ void avdtp_signaling_emit_media_codec_other_reconfiguration(btstack_packet_handl void avdtp_request_can_send_now_acceptor(avdtp_connection_t * connection, uint16_t l2cap_cid){ + if (!connection) return; connection->wait_to_send_acceptor = 1; l2cap_request_can_send_now_event(l2cap_cid); } void avdtp_request_can_send_now_initiator(avdtp_connection_t * connection, uint16_t l2cap_cid){ + if (!connection) return; connection->wait_to_send_initiator = 1; l2cap_request_can_send_now_event(l2cap_cid); } void avdtp_request_can_send_now_self(avdtp_connection_t * connection, uint16_t l2cap_cid){ + if (!connection) return; connection->wait_to_send_self = 1; l2cap_request_can_send_now_event(l2cap_cid); } @@ -863,6 +880,7 @@ uint8_t avdtp_remote_seid(avdtp_stream_endpoint_t * stream_endpoint){ void a2dp_streaming_emit_connection_established(btstack_packet_handler_t callback, uint16_t cid, bd_addr_t addr, uint8_t local_seid, uint8_t remote_seid, uint8_t status){ if (!callback) return; + printf("emit A2DP_SUBEVENT_STREAM_ESTABLISHED\n"); uint8_t event[14]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; diff --git a/src/classic/avdtp_util.h b/src/classic/avdtp_util.h index 01c180e5b..da435dde8 100644 --- a/src/classic/avdtp_util.h +++ b/src/classic/avdtp_util.h @@ -61,6 +61,7 @@ avdtp_stream_endpoint_t * avdtp_stream_endpoint_for_l2cap_cid(uint16_t l2cap_cid avdtp_stream_endpoint_t * avdtp_stream_endpoint_with_seid(uint8_t seid, avdtp_context_t * context); avdtp_stream_endpoint_t * avdtp_stream_endpoint_associated_with_acp_seid(uint16_t acp_seid, avdtp_context_t * context); avdtp_stream_endpoint_t * avdtp_stream_endpoint_for_seid(uint16_t seid, avdtp_context_t * context); +avdtp_stream_endpoint_t * avdtp_stream_endpoint_for_signaling_cid(uint16_t l2cap_cid, avdtp_context_t * context); static inline uint8_t avdtp_header(uint8_t tr_label, avdtp_packet_type_t packet_type, avdtp_message_type_t msg_type){ return (tr_label<<4) | ((uint8_t)packet_type<<2) | (uint8_t)msg_type;