From ca1ffc842a89014003127a61bd1f8f5aaadfb5d6 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Mon, 16 Apr 2018 14:24:29 +0200 Subject: [PATCH 1/6] avdtp acceptor: fix sep configuration --- src/classic/avdtp_acceptor.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/classic/avdtp_acceptor.c b/src/classic/avdtp_acceptor.c index 2fff71c14..0392fc40c 100644 --- a/src/classic/avdtp_acceptor.c +++ b/src/classic/avdtp_acceptor.c @@ -230,11 +230,11 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t if (stream_endpoint->remote_sep_index != AVDTP_INVALID_SEP_INDEX){ if (stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].in_use){ - // if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_OPENED){ - // stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index] = sep; - // log_info("ACP: update seid %d, to %p", stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint); - // break; - // } + if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_OPENED){ + stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index] = sep; + log_info("ACP: update seid %d, to %p", stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint); + break; + } // reject if already configured connection->error_code = SEP_IN_USE; // find first registered category and fire the error From c15aaafb261d9e578d041384ee9481adb57116d3 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Tue, 17 Apr 2018 14:15:33 +0200 Subject: [PATCH 2/6] avdtp: add sep discovery done event --- src/btstack_defines.h | 7 +++++++ src/btstack_event.h | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/btstack_defines.h b/src/btstack_defines.h index 5243e9225..b289b2985 100644 --- a/src/btstack_defines.h +++ b/src/btstack_defines.h @@ -1547,6 +1547,13 @@ typedef uint8_t sm_key_t[16]; #define AVDTP_SUBEVENT_SIGNALING_CAPABILITY_DONE 0x15 +/** + * @format 12 + * @param subevent_code + * @param avdtp_cid + */ +#define AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE 0x16 + /** A2DP Subevent */ /* Stream goes through following states: diff --git a/src/btstack_event.h b/src/btstack_event.h index d4f3008f8..81abf94aa 100644 --- a/src/btstack_event.h +++ b/src/btstack_event.h @@ -5040,6 +5040,16 @@ static inline uint8_t avdtp_subevent_signaling_capability_done_get_remote_seid(c return event[6]; } +/** + * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE + * @param event packet + * @return avdtp_cid + * @note: btstack_type 2 + */ +static inline uint16_t avdtp_subevent_signaling_sep_dicovery_done_get_avdtp_cid(const uint8_t * event){ + return little_endian_read_16(event, 3); +} + /** * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW * @param event packet From 49307b6323d817317a24880846c7a7fc77c53d07 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Tue, 17 Apr 2018 15:27:08 +0200 Subject: [PATCH 3/6] avdtp: remove list of remote seps, emit instead seps to the app, with event done to mark the end --- src/classic/a2dp_source.c | 34 ++++++++----- src/classic/avdtp.c | 83 +++++++++++++++----------------- src/classic/avdtp.h | 14 +++--- src/classic/avdtp_acceptor.c | 35 +++++--------- src/classic/avdtp_initiator.c | 41 ++++++---------- src/classic/avdtp_source.c | 7 --- src/classic/avdtp_source.h | 2 - src/classic/avdtp_util.c | 78 +++++++++++++++--------------- src/classic/avdtp_util.h | 9 ++-- test/pts/avrcp_controller_test.c | 14 +++--- 10 files changed, 145 insertions(+), 172 deletions(-) diff --git a/src/classic/a2dp_source.c b/src/classic/a2dp_source.c index 3ebcba9f7..db7515db4 100644 --- a/src/classic/a2dp_source.c +++ b/src/classic/a2dp_source.c @@ -49,6 +49,7 @@ #include "classic/avdtp_source.h" #include "classic/a2dp_source.h" +#define AVDTP_MAX_SEP_NUM 10 #define AVDTP_MEDIA_PAYLOAD_HEADER_SIZE 12 static const char * default_a2dp_source_service_name = "BTstack A2DP Source Service"; @@ -57,6 +58,8 @@ static avdtp_context_t a2dp_source_context; static a2dp_state_t app_state = A2DP_IDLE; static avdtp_stream_endpoint_context_t sc; +static avdtp_sep_t remote_seps[AVDTP_MAX_SEP_NUM]; +static int remote_seps_index = 0; static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); @@ -227,12 +230,12 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe sc.active_remote_sep = NULL; sc.active_remote_sep_index = 0; app_state = A2DP_W2_DISCOVER_SEPS; + remote_seps_index = 0; + memset(remote_seps, 0, sizeof(avdtp_sep_t) * AVDTP_MAX_SEP_NUM); a2dp_signaling_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, status); avdtp_source_discover_stream_endpoints(cid); break; } - case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND: - break; case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY:{ log_info("A2DP received SBC capability."); @@ -327,6 +330,21 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, address, local_seid, remote_seid, 0); break; + case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND:{ + avdtp_sep_t sep; + sep.seid = avdtp_subevent_signaling_sep_found_get_remote_seid(packet);; + sep.in_use = avdtp_subevent_signaling_sep_found_get_in_use(packet); + sep.media_type = avdtp_subevent_signaling_sep_found_get_media_type(packet); + sep.type = avdtp_subevent_signaling_sep_found_get_sep_type(packet); + log_info("Found sep: seid %u, in_use %d, media type %d, sep type %d (1-SNK)", sep.seid, sep.in_use, sep.media_type, sep.type); + remote_seps[remote_seps_index++] = sep; + break; + } + case AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE: + app_state = A2DP_W2_GET_CAPABILITIES; + sc.active_remote_sep_index = 0; + break; + case AVDTP_SUBEVENT_SIGNALING_ACCEPT: // TODO check cid signal_identifier = avdtp_subevent_signaling_accept_get_signal_identifier(packet); @@ -334,17 +352,11 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe log_info("A2DP Accepted %d, state %d", signal_identifier, app_state); switch (app_state){ - case A2DP_W2_DISCOVER_SEPS: case A2DP_W2_GET_CAPABILITIES: - case A2DP_W2_GET_ALL_CAPABILITIES: - app_state = A2DP_W2_GET_ALL_CAPABILITIES; - sc.active_remote_sep = avdtp_source_remote_sep(cid, sc.active_remote_sep_index++); - if (!sc.active_remote_sep) { - app_state = A2DP_IDLE; - a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, AVDTP_SEID_DOES_NOT_EXIST); - break; + if (sc.active_remote_sep_index < remote_seps_index){ + sc.active_remote_sep = &remote_seps[sc.active_remote_sep_index++]; + avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid); } - avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid); break; case A2DP_W2_SET_CONFIGURATION:{ if (!sc.local_stream_endpoint) return; diff --git a/src/classic/avdtp.c b/src/classic/avdtp.c index 19932e86d..e1a528223 100644 --- a/src/classic/avdtp.c +++ b/src/classic/avdtp.c @@ -654,7 +654,7 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet local_cid = l2cap_event_channel_closed_get_local_cid(packet); connection = avdtp_connection_for_l2cap_signaling_cid(local_cid, context); stream_endpoint = avdtp_stream_endpoint_for_l2cap_cid(local_cid, context); - log_info("Neceived L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint); + log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint); if (stream_endpoint){ if (stream_endpoint->l2cap_media_cid == local_cid){ @@ -662,11 +662,7 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet if (connection) { avdtp_streaming_emit_connection_released(context->avdtp_callback, connection->avdtp_cid, avdtp_local_seid(stream_endpoint)); } - stream_endpoint->l2cap_media_cid = 0; - stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; - stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE; - stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE; - stream_endpoint->remote_sep_index = 0; + avdtp_reset_stream_endpoint(stream_endpoint); if (connection && connection->disconnect){ avdtp_request_can_send_now_self(connection, connection->l2cap_signaling_cid); } @@ -686,19 +682,17 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet } if (connection){ - btstack_run_loop_remove_timer(&connection->configuration_timer); - avdtp_signaling_emit_connection_released(context->avdtp_callback, connection->avdtp_cid); - - btstack_linked_list_remove(avdtp_connections, (btstack_linked_item_t*) connection); btstack_linked_list_iterator_t it; btstack_linked_list_iterator_init(&it, 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 == connection){ - avdtp_initialize_stream_endpoint(_stream_endpoint); + avdtp_reset_stream_endpoint(_stream_endpoint); } } + btstack_run_loop_remove_timer(&connection->configuration_timer); + avdtp_signaling_emit_connection_released(context->avdtp_callback, connection->avdtp_cid); + btstack_linked_list_remove(avdtp_connections, (btstack_linked_item_t*) connection); btstack_memory_avdtp_connection_free(connection); break; } @@ -749,10 +743,6 @@ uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote log_error("avdtp_media_connect: no connection for signaling cid 0x%02x found", avdtp_cid); return AVDTP_CONNECTION_DOES_NOT_EXIST; } - if (avdtp_find_remote_sep(connection, remote_seid) == 0xFF){ - log_error("avdtp_media_connect: no remote sep for seid %d found", remote_seid); - return AVDTP_SEID_DOES_NOT_EXIST; - } if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) { log_error("avdtp_media_connect: wrong connection state %d", connection->state); @@ -764,10 +754,14 @@ uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid); return AVDTP_SEID_DOES_NOT_EXIST; } + + if (stream_endpoint->remote_sep.seid != remote_seid){ + log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid); + return AVDTP_SEID_DOES_NOT_EXIST; + } if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE; - if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX) return AVDTP_SEID_DOES_NOT_EXIST; - + connection->initiator_transaction_label++; connection->remote_seid = remote_seid; connection->local_seid = local_seid; @@ -795,8 +789,9 @@ uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid, avdtp_context return AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST; } - if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX || stream_endpoint->start_stream){ - return AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE; + if (!is_avdtp_remote_seid_registered(stream_endpoint)){ + log_error("avdtp_media_connect: no remote sep registered with the stream endpoint"); + return AVDTP_SEID_DOES_NOT_EXIST; } stream_endpoint->start_stream = 1; @@ -822,8 +817,11 @@ uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid, avdtp_context_ log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid); return AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST; } - if (stream_endpoint->remote_sep_index == 0xFF || stream_endpoint->stop_stream) return ERROR_CODE_SUCCESS; + if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->stop_stream){ + return ERROR_CODE_SUCCESS; + } + stream_endpoint->stop_stream = 1; connection->local_seid = local_seid; avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); @@ -847,7 +845,10 @@ uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid, avdtp_context log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid); return AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST; } - if (stream_endpoint->remote_sep_index == 0xFF || stream_endpoint->abort_stream) return ERROR_CODE_SUCCESS; + + if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){ + return ERROR_CODE_SUCCESS; + } stream_endpoint->abort_stream = 1; connection->local_seid = local_seid; @@ -871,8 +872,11 @@ uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid, avdtp_conte log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid); return AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST; } - if (stream_endpoint->remote_sep_index == 0xFF || stream_endpoint->suspend_stream) return ERROR_CODE_SUCCESS; + if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->suspend_stream){ + return ERROR_CODE_SUCCESS; + } + stream_endpoint->suspend_stream = 1; connection->local_seid = local_seid; avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); @@ -956,6 +960,7 @@ uint8_t avdtp_set_configuration(uint16_t avdtp_cid, uint8_t local_seid, uint8_t } if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED || connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE) { + log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state); return AVDTP_CONNECTION_IN_WRONG_STATE; } @@ -965,7 +970,7 @@ uint8_t avdtp_set_configuration(uint16_t avdtp_cid, uint8_t local_seid, uint8_t return AVDTP_STREAM_ENDPOINT_DOES_NOT_EXIST; } if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){ - log_error("Ntream endpoint seid %d in wrong state", local_seid); + log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state); return AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE; } connection->active_stream_endpoint = (void*) stream_endpoint; @@ -1006,10 +1011,11 @@ uint8_t avdtp_reconfigure(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote return AVDTP_STREAM_ENDPOINT_DOES_NOT_EXIST; } - if (stream_endpoint->remote_sep_index == 0xFF){ + if (!is_avdtp_remote_seid_registered(stream_endpoint)){ log_error("avdtp_reconfigure: no associated remote sep"); return AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE; } + connection->initiator_transaction_label++; connection->remote_seid = remote_seid; connection->local_seid = local_seid; @@ -1019,26 +1025,6 @@ uint8_t avdtp_reconfigure(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); } -uint8_t avdtp_remote_seps_num(uint16_t avdtp_cid, avdtp_context_t * context){ - avdtp_connection_t * connection = avdtp_connection_for_avdtp_cid(avdtp_cid, context); - if (!connection){ - log_error("avdtp_suspend: no connection for AVDTP cid 0x%02x found", avdtp_cid); - return 0; - } - return connection->remote_seps_num; -} - -avdtp_sep_t * avdtp_remote_sep(uint16_t avdtp_cid, uint8_t index, avdtp_context_t * context){ - avdtp_connection_t * connection = avdtp_connection_for_avdtp_cid(avdtp_cid, context); - if (!connection){ - log_error("avdtp_suspend: no connection for AVDTP cid 0x%02x found", avdtp_cid); - return NULL; - } - if (index == AVDTP_INVALID_SEP_INDEX) return NULL; - if (index >= connection->remote_seps_num || index >= AVDTP_MAX_NUM_SEPS) return NULL; - return &connection->remote_seps[index]; -} - void avdtp_initialize_sbc_configuration_storage(avdtp_stream_endpoint_t * stream_endpoint, uint8_t * config_storage, uint16_t storage_size, uint8_t * packet, uint16_t packet_size){ UNUSED(packet_size); if (storage_size < 4) { @@ -1161,3 +1147,10 @@ uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endp uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; return btstack_max(media_codec[2], remote_min_bitpool_value); } + +uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){ + if (!stream_endpoint) return 0; + if (stream_endpoint->remote_sep.seid == 0) return 0; + if (stream_endpoint->remote_sep.seid > 0x3E) return 0; + return 1; +} \ No newline at end of file diff --git a/src/classic/avdtp.h b/src/classic/avdtp.h index b242a5779..e734f24c2 100644 --- a/src/classic/avdtp.h +++ b/src/classic/avdtp.h @@ -97,6 +97,9 @@ extern "C" { // ACP to INT, Procedure Error Codes #define BAD_STATE 0x31 + +#define AVDTP_INVALID_SEP_SEID 0xFF + // Signal Identifier fields typedef enum { AVDTP_SI_NONE = 0x00, @@ -412,8 +415,8 @@ typedef struct { uint8_t error_code; // store configurations with remote seps - avdtp_sep_t remote_seps[AVDTP_MAX_NUM_SEPS]; - uint8_t remote_seps_num; + // avdtp_sep_t remote_seps[AVDTP_MAX_NUM_SEPS]; + // uint8_t remote_seps_num; // store current role uint8_t is_initiator; @@ -445,6 +448,7 @@ typedef struct avdtp_stream_endpoint { // original capabilities avdtp_sep_t sep; + avdtp_sep_t remote_sep; hci_con_handle_t media_con_handle; uint16_t l2cap_media_cid; uint16_t l2cap_reporting_cid; @@ -457,7 +461,7 @@ typedef struct avdtp_stream_endpoint { // active connection avdtp_connection_t * connection; // currently active remote seid - uint8_t remote_sep_index; + // uint8_t remote_sep_index; avdtp_capabilities_t remote_capabilities; uint16_t remote_capabilities_bitmap; @@ -477,7 +481,6 @@ typedef struct avdtp_stream_endpoint { uint8_t send_stream; uint8_t abort_stream; uint8_t suspend_stream; - uint16_t sequence_number; } avdtp_stream_endpoint_t; @@ -553,8 +556,6 @@ uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid, avdt uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_context_t * context); uint8_t avdtp_set_configuration(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context); uint8_t avdtp_reconfigure(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context); -uint8_t avdtp_remote_seps_num(uint16_t avdtp_cid, avdtp_context_t * context); -avdtp_sep_t * avdtp_remote_sep(uint16_t avdtp_cid, uint8_t index, avdtp_context_t * context); void avdtp_initialize_sbc_configuration_storage(avdtp_stream_endpoint_t * stream_endpoint, uint8_t * config_storage, uint16_t storage_size, uint8_t * packet, uint16_t packet_size); uint8_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap); @@ -571,6 +572,7 @@ void avdtp_configuration_timeout_handler(btstack_timer_source_t * timer); void avdtp_configuration_timer_start(avdtp_connection_t * connection); void avdtp_configuration_timer_stop(avdtp_connection_t * connection); +uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint); #if defined __cplusplus } #endif diff --git a/src/classic/avdtp_acceptor.c b/src/classic/avdtp_acceptor.c index 0392fc40c..a6d16bfa7 100644 --- a/src/classic/avdtp_acceptor.c +++ b/src/classic/avdtp_acceptor.c @@ -207,7 +207,7 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t log_info("acceptor SM received SET_CONFIGURATION cmd: change role to acceptor, is_initiator %d", connection->is_initiator); } - log_info("ACP: AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION "); + log_info("ACP: AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION connection %p", connection); stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURATION_SUBSTATEMACHINE; stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION; connection->reject_service_category = 0; @@ -225,17 +225,11 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t } // find or add sep - stream_endpoint->remote_sep_index = avdtp_find_remote_sep(stream_endpoint->connection, sep.seid); - log_info("ACP .. seid %d, index %d", sep.seid, stream_endpoint->remote_sep_index); + log_info("ACP .. seid %d, remote sep seid %d", sep.seid, stream_endpoint->remote_sep.seid); - if (stream_endpoint->remote_sep_index != AVDTP_INVALID_SEP_INDEX){ - if (stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].in_use){ - if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_OPENED){ - stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index] = sep; - log_info("ACP: update seid %d, to %p", stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint); - break; - } - // reject if already configured + if (is_avdtp_remote_seid_registered(stream_endpoint)){ + if (stream_endpoint->remote_sep.in_use){ + log_info("reject as it is already in use"); connection->error_code = SEP_IN_USE; // find first registered category and fire the error connection->reject_service_category = 0; @@ -249,16 +243,14 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t connection->reject_signal_identifier = connection->signaling_packet.signal_identifier; stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE; } else { - stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index] = sep; - log_info("ACP: update seid %d, to %p", stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint); + stream_endpoint->remote_sep = sep; + log_info("ACP: update seid %d, to %p", stream_endpoint->remote_sep.seid, stream_endpoint); } } else { // add new log_info("ACP: seid %d not found in %p", sep.seid, stream_endpoint); - stream_endpoint->remote_sep_index = connection->remote_seps_num; - connection->remote_seps_num++; - connection->remote_seps[stream_endpoint->remote_sep_index] = sep; - log_info("ACP: add seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint); + stream_endpoint->remote_sep = sep; + log_info("ACP: add seid %d, to %p", stream_endpoint->remote_sep.seid, stream_endpoint); } avdtp_emit_configuration(context->avdtp_callback, connection->avdtp_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), &sep.configuration, sep.configured_service_categories); @@ -281,16 +273,15 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t } // find sep or raise error - stream_endpoint->remote_sep_index = avdtp_find_remote_sep(stream_endpoint->connection, sep.seid); - if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX){ + if (!is_avdtp_remote_seid_registered(stream_endpoint)){ log_info("ACP: REJECT AVDTP_SI_RECONFIGURE, BAD_ACP_SEID"); stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE; connection->error_code = BAD_ACP_SEID; connection->reject_signal_identifier = connection->signaling_packet.signal_identifier; break; } - stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index] = sep; - log_info("ACP: update seid %d, to %p", stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint); + stream_endpoint->remote_sep = sep; + log_info("ACP: update seid %d, to %p", stream_endpoint->remote_sep.seid, stream_endpoint); avdtp_emit_configuration(context->avdtp_callback, connection->avdtp_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), &sep.configuration, sep.configured_service_categories); avdtp_signaling_emit_accept(context->avdtp_callback, connection->avdtp_cid, avdtp_local_seid(stream_endpoint), connection->signaling_packet.signal_identifier); @@ -534,7 +525,7 @@ void avdtp_acceptor_stream_config_subsm_run(avdtp_connection_t * connection, avd break; case AVDTP_ACCEPTOR_W2_ANSWER_GET_CONFIGURATION:{ - avdtp_sep_t sep = stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index]; + avdtp_sep_t sep = stream_endpoint->remote_sep; avdtp_prepare_capabilities(&connection->signaling_packet, trid, sep.configured_service_categories, sep.configuration, AVDTP_SI_GET_CONFIGURATION); l2cap_reserve_packet_buffer(); out_buffer = l2cap_get_outgoing_buffer(); diff --git a/src/classic/avdtp_initiator.c b/src/classic/avdtp_initiator.c index 0a3271b5f..c38cc6d79 100644 --- a/src/classic/avdtp_initiator.c +++ b/src/classic/avdtp_initiator.c @@ -66,7 +66,6 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_ // int status = 0; avdtp_stream_endpoint_t * stream_endpoint = NULL; - uint8_t remote_sep_index; avdtp_sep_t sep; if (connection->initiator_connection_state == AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER) { connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE; @@ -97,7 +96,7 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_ break; } - int i; + int i; for (i = offset; i < size; i += 2){ sep.seid = packet[i] >> 2; offset++; @@ -109,12 +108,9 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_ sep.in_use = (packet[i] >> 1) & 0x01; sep.media_type = (avdtp_media_type_t)(packet[i+1] >> 4); sep.type = (avdtp_sep_type_t)((packet[i+1] >> 3) & 0x01); - - if (avdtp_find_remote_sep(connection, sep.seid) == 0xFF){ - connection->remote_seps[connection->remote_seps_num++] = sep; - } avdtp_signaling_emit_sep(context->avdtp_callback, connection->avdtp_cid, sep); } + avdtp_signaling_emit_sep_done(context->avdtp_callback, connection->avdtp_cid); break; } @@ -147,12 +143,10 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_ sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, &sep.configuration, connection->signaling_packet.command+4, connection->signaling_packet.size-4); // TODO check if configuration is supported - remote_sep_index = avdtp_find_remote_sep(connection, sep.seid); - if (remote_sep_index != 0xFF){ - stream_endpoint->remote_sep_index = remote_sep_index; - connection->remote_seps[stream_endpoint->remote_sep_index] = sep; + if (!is_avdtp_remote_seid_registered(stream_endpoint)){ + stream_endpoint->remote_sep = sep; stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURED; - log_info("INT: update seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint); + log_info("INT: update seid %d, to %p", stream_endpoint->remote_sep.seid, stream_endpoint); } break; @@ -165,20 +159,13 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_ sep.configured_service_categories = stream_endpoint->remote_configuration_bitmap; sep.configuration = stream_endpoint->remote_configuration; sep.in_use = 1; - // TODO check if configuration is supported - // find or add sep - remote_sep_index = avdtp_find_remote_sep(connection, sep.seid); - if (remote_sep_index != 0xFF){ - stream_endpoint->remote_sep_index = remote_sep_index; - } else { - stream_endpoint->remote_sep_index = connection->remote_seps_num; - connection->remote_seps_num++; - } - connection->remote_seps[stream_endpoint->remote_sep_index] = sep; - log_info("INT: configured remote seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint); stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURED; - + stream_endpoint->remote_sep = sep; + stream_endpoint->connection = connection; + + log_info("INT: configured remote seid %d, to %p", stream_endpoint->remote_sep.seid, stream_endpoint); + switch (stream_endpoint->media_codec_type){ case AVDTP_CODEC_SBC: avdtp_signaling_emit_media_codec_sbc_configuration(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->remote_seid, @@ -186,7 +173,7 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_ break; default: // TODO: we don\t have codec info to emit config - // avdtp_signaling_emit_media_codec_other_configuration(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->remote_seid, sep.configuration.media_codec); + avdtp_signaling_emit_media_codec_other_configuration(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->remote_seid, sep.configuration.media_codec); break; } @@ -317,7 +304,7 @@ void avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, av stream_endpoint->start_stream = 0; if (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_OPENED){ connection->local_seid = stream_endpoint->sep.seid; - connection->remote_seid = connection->remote_seps[stream_endpoint->remote_sep_index].seid; + connection->remote_seid = stream_endpoint->remote_sep.seid; avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_START, connection->initiator_transaction_label++, connection->remote_seid); return; } @@ -328,7 +315,7 @@ void avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, av stream_endpoint->stop_stream = 0; if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_OPENED){ connection->local_seid = stream_endpoint->sep.seid; - connection->remote_seid = connection->remote_seps[stream_endpoint->remote_sep_index].seid; + connection->remote_seid = stream_endpoint->remote_sep.seid; avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_CLOSE, connection->initiator_transaction_label++, connection->remote_seid); return; } @@ -342,7 +329,7 @@ void avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, av case AVDTP_STREAM_ENDPOINT_OPENED: case AVDTP_STREAM_ENDPOINT_STREAMING: connection->local_seid = stream_endpoint->sep.seid; - connection->remote_seid = connection->remote_seps[stream_endpoint->remote_sep_index].seid; + connection->remote_seid = stream_endpoint->remote_sep.seid; stream_endpoint->state = AVDTP_STREAM_ENDPOINT_ABORTING; avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_ABORT, connection->initiator_transaction_label++, connection->remote_seid); return; diff --git a/src/classic/avdtp_source.c b/src/classic/avdtp_source.c index e9511f551..3993b3874 100644 --- a/src/classic/avdtp_source.c +++ b/src/classic/avdtp_source.c @@ -175,10 +175,3 @@ void avdtp_source_init(avdtp_context_t * avdtp_context){ l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_0); } -uint8_t avdtp_source_remote_seps_num(uint16_t avdtp_cid){ - return avdtp_remote_seps_num(avdtp_cid, avdtp_source_context); -} - -avdtp_sep_t * avdtp_source_remote_sep(uint16_t avdtp_cid, uint8_t index){ - return avdtp_remote_sep(avdtp_cid, index, avdtp_source_context); -} diff --git a/src/classic/avdtp_source.h b/src/classic/avdtp_source.h index 6897a5541..b3010b1ff 100644 --- a/src/classic/avdtp_source.h +++ b/src/classic/avdtp_source.h @@ -152,8 +152,6 @@ uint8_t avdtp_source_suspend(uint16_t avdtp_cid, uint8_t local_seid); avdtp_stream_endpoint_t * avdtp_source_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type); -uint8_t avdtp_source_remote_seps_num(uint16_t avdtp_cid); -avdtp_sep_t * avdtp_source_remote_sep(uint16_t avdtp_cid, uint8_t index); /* API_END */ #if defined __cplusplus diff --git a/src/classic/avdtp_util.c b/src/classic/avdtp_util.c index d968f0291..bea340ec4 100644 --- a/src/classic/avdtp_util.c +++ b/src/classic/avdtp_util.c @@ -70,15 +70,33 @@ const char * avdtp_si2str(uint16_t index){ return avdtp_si_name[index]; } -void avdtp_initialize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){ +void avdtp_reset_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){ + stream_endpoint->media_con_handle = 0; + stream_endpoint->l2cap_media_cid = 0; + stream_endpoint->l2cap_reporting_cid = 0; + stream_endpoint->l2cap_recovery_cid = 0; + stream_endpoint->connection = NULL; stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE; stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE; - stream_endpoint->remote_sep_index = AVDTP_INVALID_SEP_INDEX; - stream_endpoint->media_disconnect = 0; + stream_endpoint->sep.in_use = 0; - stream_endpoint->remote_sep_index = 0; + memset(&stream_endpoint->remote_sep, 0, sizeof(avdtp_sep_t)); + memset(&stream_endpoint->remote_capabilities, 0, sizeof(avdtp_capabilities_t)); + memset(&stream_endpoint->remote_configuration, 0, sizeof(avdtp_capabilities_t)); + + stream_endpoint->remote_capabilities_bitmap = 0; + stream_endpoint->remote_configuration_bitmap = 0; + + stream_endpoint->media_disconnect = 0; + stream_endpoint->media_connect = 0; + stream_endpoint->start_stream = 0; + stream_endpoint->stop_stream = 0; + stream_endpoint->send_stream = 0; + stream_endpoint->abort_stream = 0; + stream_endpoint->suspend_stream = 0; + stream_endpoint->sequence_number = 0; } avdtp_stream_endpoint_t * avdtp_stream_endpoint_for_seid(uint16_t seid, avdtp_context_t * context){ @@ -175,12 +193,8 @@ avdtp_stream_endpoint_t * avdtp_stream_endpoint_associated_with_acp_seid(uint16_ 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->remote_sep_index != AVDTP_INVALID_SEP_INDEX){ - if (!stream_endpoint->connection) continue; - if (stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid == acp_seid){ - return stream_endpoint; - } + if (stream_endpoint->remote_sep.seid == acp_seid){ + return stream_endpoint; } } return NULL; @@ -619,6 +633,19 @@ void avdtp_signaling_emit_sep(btstack_packet_handler_t callback, uint16_t avdtp_ (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } +void avdtp_signaling_emit_sep_done(btstack_packet_handler_t callback, uint16_t avdtp_cid){ + if (!callback) return; + uint8_t event[5]; + int pos = 0; + event[pos++] = HCI_EVENT_AVDTP_META; + event[pos++] = sizeof(event) - 2; + event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE; + little_endian_store_16(event, pos, avdtp_cid); + pos += 2; + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); +} + + void avdtp_signaling_emit_accept(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier){ if (!callback) return; uint8_t event[7]; @@ -1024,32 +1051,6 @@ uint8_t avdtp_request_can_send_now_self(avdtp_connection_t * connection, uint16_ return ERROR_CODE_SUCCESS; } -uint8_t avdtp_get_index_of_remote_stream_endpoint_with_seid(avdtp_stream_endpoint_t * stream_endpoint, uint16_t seid){ - if (!stream_endpoint->connection) return AVDTP_INVALID_SEP_INDEX; - if (stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid == seid){ - return stream_endpoint->remote_sep_index; - } - int i; - for (i=0; i < stream_endpoint->connection->remote_seps_num; i++){ - if (stream_endpoint->connection->remote_seps[i].seid == seid){ - return i; - } - } - return AVDTP_INVALID_SEP_INDEX; -} - -uint8_t avdtp_find_remote_sep(avdtp_connection_t * connection, uint8_t remote_seid){ - if (!connection) return AVDTP_INVALID_SEP_INDEX; - int i; - for (i = 0; i < connection->remote_seps_num; i++){ - if (connection->remote_seps[i].seid == remote_seid){ - return i; - } - } - return AVDTP_INVALID_SEP_INDEX; -} - - uint8_t avdtp_local_seid(avdtp_stream_endpoint_t * stream_endpoint){ if (!stream_endpoint) return 0; return stream_endpoint->sep.seid; @@ -1057,9 +1058,8 @@ uint8_t avdtp_local_seid(avdtp_stream_endpoint_t * stream_endpoint){ } uint8_t avdtp_remote_seid(avdtp_stream_endpoint_t * stream_endpoint){ - if (!stream_endpoint) return 0; - if (!stream_endpoint->connection) return 0; - return stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid; + if (!stream_endpoint) return AVDTP_INVALID_SEP_SEID; + return stream_endpoint->remote_sep.seid; } 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){ diff --git a/src/classic/avdtp_util.h b/src/classic/avdtp_util.h index 7e88262ff..5c462c869 100644 --- a/src/classic/avdtp_util.h +++ b/src/classic/avdtp_util.h @@ -52,8 +52,6 @@ extern "C" { #endif -#define AVDTP_INVALID_SEP_INDEX 0xff - avdtp_connection_t * avdtp_connection_for_bd_addr(bd_addr_t addr, avdtp_context_t * context); avdtp_connection_t * avdtp_connection_for_avdtp_cid(uint16_t l2cap_cid, avdtp_context_t * context); avdtp_connection_t * avdtp_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid, avdtp_context_t * context); @@ -85,6 +83,8 @@ void avdtp_signaling_emit_connection_released(btstack_packet_handler_t callback, void avdtp_streaming_emit_connection_released(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t local_seid); void avdtp_signaling_emit_sep(btstack_packet_handler_t callback, uint16_t avdtp_cid, avdtp_sep_t sep); +void avdtp_signaling_emit_sep_done(btstack_packet_handler_t callback, uint16_t avdtp_cid); + void avdtp_signaling_emit_accept(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t seid, avdtp_signal_identifier_t identifier); void avdtp_signaling_emit_general_reject(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, avdtp_signal_identifier_t identifier); void avdtp_signaling_emit_reject(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, avdtp_signal_identifier_t identifier); @@ -102,10 +102,7 @@ uint8_t avdtp_request_can_send_now_acceptor(avdtp_connection_t * connection, uin uint8_t avdtp_request_can_send_now_initiator(avdtp_connection_t * connection, uint16_t l2cap_cid); uint8_t avdtp_request_can_send_now_self(avdtp_connection_t * connection, uint16_t l2cap_cid); -uint8_t avdtp_get_index_of_remote_stream_endpoint_with_seid(avdtp_stream_endpoint_t * stream_endpoint, uint16_t acp_seid); - -void avdtp_initialize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint); -uint8_t avdtp_find_remote_sep(avdtp_connection_t * connection, uint8_t remote_seid); +void avdtp_reset_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint); // uint16_t avdtp_cid(avdtp_stream_endpoint_t * stream_endpoint); uint8_t avdtp_local_seid(avdtp_stream_endpoint_t * stream_endpoint); diff --git a/test/pts/avrcp_controller_test.c b/test/pts/avrcp_controller_test.c index 61261c795..9539a01c9 100644 --- a/test/pts/avrcp_controller_test.c +++ b/test/pts/avrcp_controller_test.c @@ -43,6 +43,7 @@ #include #include "btstack.h" +#include "btstack_stdin_pts.h" #define AVRCP_BROWSING_ENABLED 1 #define AVRCP_BROWSING_MAX_PLAYERS 10 @@ -106,6 +107,7 @@ typedef struct { uint8_t num_attributes; } avrcp_browsable_media_element_item_t; +void btstack_stdin_pts_setup(void (*stdin_handler)(char * c, int size)); static uint8_t parent_folder_set = 0; static uint8_t parent_folder_uid[8]; @@ -248,9 +250,9 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe memcpy(media_element_items[index].uid, packet+pos, 8); printf("Received media element item UID (index %d): ", index); - uint32_t media_uid_high = big_endian_read_32(packet, pos); + // uint32_t media_uid_high = big_endian_read_32(packet, pos); pos += 4; - uint32_t media_uid_low = big_endian_read_32(packet, pos+4); + // uint32_t media_uid_low = big_endian_read_32(packet, pos+4); pos += 4; avrcp_browsing_media_type_t media_type = packet[pos++]; @@ -292,9 +294,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context); uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context); uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context); - uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context); - attr_value[attr_value_length] = 0; - + const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context); printf(" - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, attr_value_length, attr_value); } } @@ -321,7 +321,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe printf("AVDTP connection released: avdtp_cid 0x%02x.\n", avdtp_cid); break; default: - printf("AVDTP event not parsed.\n"); + // printf("AVDTP event not parsed.\n"); break; } break; @@ -985,7 +985,7 @@ static void stdin_process(char * cmd, int size){ status = avrcp_controller_play_item_for_scope(avrcp_cid, media_element_items[0].uid, media_element_item_index, AVRCP_BROWSING_NOW_PLAYING); break; - case '53': + case '5': printf("Add to now playing: first media item from virtual file system\n"); if (media_element_item_index < 0){ printf("AVRCP Browsing: no media items found\n"); From fbc78aa395a3dbd173f4d0305e8ccc5a346d9354 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Tue, 17 Apr 2018 15:28:51 +0200 Subject: [PATCH 4/6] a2dp: remove l2cap register service from init --- src/classic/a2dp_sink.c | 1 - src/classic/a2dp_source.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/classic/a2dp_sink.c b/src/classic/a2dp_sink.c index 9c0b06170..c02b111c2 100644 --- a/src/classic/a2dp_sink.c +++ b/src/classic/a2dp_sink.c @@ -157,7 +157,6 @@ void a2dp_sink_register_media_handler(void (*callback)(uint8_t local_seid, uint8 void a2dp_sink_init(void){ avdtp_sink_init(&a2dp_sink_context); - l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_0); } uint8_t a2dp_sink_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, diff --git a/src/classic/a2dp_source.c b/src/classic/a2dp_source.c index db7515db4..b15ed35b6 100644 --- a/src/classic/a2dp_source.c +++ b/src/classic/a2dp_source.c @@ -442,7 +442,6 @@ void a2dp_source_register_packet_handler(btstack_packet_handler_t callback){ void a2dp_source_init(void){ avdtp_source_init(&a2dp_source_context); - l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_0); } avdtp_stream_endpoint_t * a2dp_source_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, From 7fffb19261ad2498226fa44aec75808f49efbc36 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Tue, 17 Apr 2018 15:32:55 +0200 Subject: [PATCH 5/6] avdtp: fix typo in log info msgs --- src/classic/avdtp.c | 46 ++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/classic/avdtp.c b/src/classic/avdtp.c index e1a528223..377aaf041 100644 --- a/src/classic/avdtp.c +++ b/src/classic/avdtp.c @@ -356,7 +356,7 @@ static void handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ avdtp_connection_t * connection = avdtp_connection_for_avdtp_cid(sdp_query_context->avdtp_cid, sdp_query_context); if (!connection) { - log_error("Ndp query, connection with 0x%02x cid not found", sdp_query_context->avdtp_cid); + 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; @@ -460,21 +460,21 @@ static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c avdtp_signaling_emit_connection_established(sdp_query_context->avdtp_callback, sdp_query_context->avdtp_cid, connection->remote_addr, status); btstack_linked_list_remove(&sdp_query_context->connections, (btstack_linked_item_t*) connection); btstack_memory_avdtp_connection_free(connection); - log_info("NDP query failed with status 0x%02x.", status); + log_info("SDP query failed with status 0x%02x.", status); break; } if (!sdp_query_context->role_supported){ btstack_linked_list_remove(&sdp_query_context->connections, (btstack_linked_item_t*) connection); btstack_memory_avdtp_connection_free(connection); avdtp_signaling_emit_connection_established(sdp_query_context->avdtp_callback, sdp_query_context->avdtp_cid, connection->remote_addr, SDP_SERVICE_NOT_FOUND); - log_info("NDP query, remote device does not support required role."); + log_info("SDP query, remote device does not support required role."); break; } if (!sdp_query_context->avdtp_l2cap_psm) { btstack_linked_list_remove(&sdp_query_context->connections, (btstack_linked_item_t*)connection); btstack_memory_avdtp_connection_free(connection); avdtp_signaling_emit_connection_established(sdp_query_context->avdtp_callback, sdp_query_context->avdtp_cid, connection->remote_addr, L2CAP_SERVICE_DOES_NOT_EXIST); - log_info("NDP query, no l2cap psm found."); + log_info("SDP query, no l2cap psm found."); break; } connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; @@ -546,27 +546,27 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet l2cap_event_incoming_connection_get_address(packet, event_addr); local_cid = l2cap_event_incoming_connection_get_local_cid(packet); connection = avdtp_connection_for_bd_addr(event_addr, context); - log_info("N2CAP_EVENT_INCOMING_CONNECTION, local cid 0x%02x ", local_cid); + log_info("L2CAP_EVENT_INCOMING_CONNECTION, local cid 0x%02x ", local_cid); if (connection){ - log_info("Nonnection state %d", connection->state); + log_info("Connection state %d", connection->state); } if (!connection || connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED){ connection = avdtp_create_connection(event_addr, context); connection->is_initiator = 0; - log_info("N2CAP_EVENT_INCOMING_CONNECTION: role is_initiator %d", connection->is_initiator); + log_info("L2CAP_EVENT_INCOMING_CONNECTION: role is_initiator %d", connection->is_initiator); connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; - log_info("N2CAP_EVENT_INCOMING_CONNECTION, connection %p, state connection %d, avdtp cid 0x%02x", connection, connection->state, connection->avdtp_cid); + log_info("L2CAP_EVENT_INCOMING_CONNECTION, connection %p, state connection %d, avdtp cid 0x%02x", connection, connection->state, connection->avdtp_cid); l2cap_accept_connection(local_cid); break; } stream_endpoint = avdtp_stream_endpoint_for_seid(connection->local_seid, context); if (!stream_endpoint) { - log_info("N2CAP_EVENT_INCOMING_CONNECTION no streamendpoint found for seid %d", connection->local_seid); + log_info("L2CAP_EVENT_INCOMING_CONNECTION no streamendpoint found for seid %d", connection->local_seid); break; } - log_info("Nhecking l2cap_media_cid %d, for local seid %d, state of stream endpoint %d, role is_initiator %d", stream_endpoint->l2cap_media_cid, connection->local_seid, stream_endpoint->state, connection->is_initiator); + log_info("Checking l2cap_media_cid %d, for local seid %d, state of stream endpoint %d, role is_initiator %d", stream_endpoint->l2cap_media_cid, connection->local_seid, stream_endpoint->state, connection->is_initiator); if (stream_endpoint->l2cap_media_cid == 0){ if (connection->is_initiator){ l2cap_decline_connection(local_cid); @@ -581,7 +581,7 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet case L2CAP_EVENT_CHANNEL_OPENED: psm = l2cap_event_channel_opened_get_psm(packet); if (psm != BLUETOOTH_PROTOCOL_AVDTP){ - log_info("Nnexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED "); + log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED "); return; } @@ -591,50 +591,50 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet local_cid = l2cap_event_channel_opened_get_local_cid(packet); connection = avdtp_connection_for_bd_addr(event_addr, context); - log_info("N2CAP_EVENT_CHANNEL_OPENED: status %d, cid 0x%02x , signaling connection %p ", status, local_cid, connection); + log_info("L2CAP_EVENT_CHANNEL_OPENED: status %d, cid 0x%02x , signaling connection %p ", status, local_cid, connection); connection = avdtp_connection_for_bd_addr(event_addr, context); if (!connection){ - log_info("N2CAP_EVENT_CHANNEL_OPENED 2: status %d, signaling connection %p ", status, connection); + log_info("L2CAP_EVENT_CHANNEL_OPENED 2: status %d, signaling connection %p ", status, connection); break; } if (connection->l2cap_signaling_cid == 0) { if (status){ - log_info("N2CAP connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), 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; } if (connection->state != AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED) { - log_info("N2CAP connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); + 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("NVDTP_SIGNALING_CONNECTION_OPENED, connection %p, l2cap_signaling_cid 0x%02x, avdtp_cid 0x%02x", connection, local_cid, connection->avdtp_cid); + log_info("AVDTP_SIGNALING_CONNECTION_OPENED, connection %p, l2cap_signaling_cid 0x%02x, avdtp_cid 0x%02x", connection, local_cid, connection->avdtp_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("N2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found"); + log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found"); return; } if (stream_endpoint->l2cap_media_cid == 0){ status = l2cap_event_channel_opened_get_status(packet); if (status){ - log_info("NVDTP_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)); + 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, event_addr, 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("NVDTP_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)); + 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, event_addr, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE); break; } @@ -644,7 +644,7 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet 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("NVDTP_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)); + 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, event_addr, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), 0); return; } @@ -669,13 +669,13 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet break; } if (stream_endpoint->l2cap_recovery_cid == local_cid){ - log_info("N2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid); + log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid); stream_endpoint->l2cap_recovery_cid = 0; break; } if (stream_endpoint->l2cap_reporting_cid == local_cid){ - log_info("N2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid); + log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid); stream_endpoint->l2cap_reporting_cid = 0; break; } @@ -712,7 +712,7 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet avdtp_handle_can_send_now(connection, channel, context); break; default: - log_info("Nnknown HCI event type %02x", hci_event_packet_get_type(packet)); + log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet)); break; } break; From df4913f899770bec5b742ee4f6203e8f973d2526 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Mon, 16 Apr 2018 17:09:58 +0200 Subject: [PATCH 6/6] avrcp_controller: fix parsing of attributes with length == 0 --- src/classic/avrcp_controller.c | 79 ++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/src/classic/avrcp_controller.c b/src/classic/avrcp_controller.c index 94a8dc76a..3baa4be7f 100644 --- a/src/classic/avrcp_controller.c +++ b/src/classic/avrcp_controller.c @@ -301,64 +301,67 @@ static void avrcp_controller_emit_now_playing_info_event(btstack_packet_handler_ } static void avrcp_parser_process_byte(uint8_t byte, avrcp_connection_t * connection, avrcp_command_type_t ctype){ + uint16_t attribute_total_value_len; + uint32_t attribute_id; switch(connection->parser_state){ - case AVRCP_PARSER_GET_ATTRIBUTE_HEADER:{ + case AVRCP_PARSER_GET_ATTRIBUTE_HEADER: if (connection->parser_attribute_header_pos < AVRCP_ATTRIBUTE_HEADER_LEN) { connection->parser_attribute_header[connection->parser_attribute_header_pos++] = byte; connection->list_offset++; + return; + } + attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 6); + connection->attribute_value_len = btstack_min(attribute_total_value_len, AVRCP_MAX_ATTRIBUTTE_SIZE); + if (connection->attribute_value_len == 0){ + // emit attribute although len == 0 + attribute_id = big_endian_read_32(connection->parser_attribute_header, 0); + avrcp_controller_emit_now_playing_info_event(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, attribute_id, connection->attribute_value, connection->attribute_value_len); break; } - uint16_t attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 6); - connection->attribute_value_len = btstack_min(attribute_total_value_len, AVRCP_MAX_ATTRIBUTTE_SIZE); connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_VALUE; - break; - } - case AVRCP_PARSER_GET_ATTRIBUTE_VALUE:{ + return; + + case AVRCP_PARSER_GET_ATTRIBUTE_VALUE: if (connection->attribute_value_offset < connection->attribute_value_len){ connection->attribute_value[connection->attribute_value_offset++] = byte; connection->list_offset++; - break; + return; } - uint32_t attribute_id = big_endian_read_32(connection->parser_attribute_header, 0); - if (attribute_id > AVRCP_MEDIA_ATTR_NONE && attribute_id <= AVRCP_MEDIA_ATTR_SONG_LENGTH_MS){ - avrcp_controller_emit_now_playing_info_event(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, attribute_id, connection->attribute_value, connection->attribute_value_len); - } - - if (connection->attribute_value_offset < big_endian_read_16(connection->parser_attribute_header, 6)){ - // printf("parse until end of valuE, and ignore it\n"); + // emit (potentially partial) attribute + attribute_id = big_endian_read_32(connection->parser_attribute_header, 0); + avrcp_controller_emit_now_playing_info_event(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, attribute_id, connection->attribute_value, connection->attribute_value_len); + + // ignore rest of attribute + attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 6); + if (connection->attribute_value_offset < attribute_total_value_len){ connection->parser_state = AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE; - break; + return; } - - if (connection->list_offset == connection->list_size){ - avrcp_parser_reset(connection); - avrcp_controller_emit_now_playing_info_event_done(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, 0); - break; - } - - connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER; - connection->parser_attribute_header_pos = 0; break; - } + case AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE: - if (connection->attribute_value_offset < big_endian_read_16(connection->parser_attribute_header, 6)){ + attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 6); + if (connection->attribute_value_offset < attribute_total_value_len){ connection->list_offset++; connection->attribute_value_offset++; - break; + return; } - // printf("read %d, total %d\n", connection->attribute_value_offset, big_endian_read_16(connection->parser_attribute_header, 6)); - - if (connection->list_offset == connection->list_size){ - avrcp_parser_reset(connection); - avrcp_controller_emit_now_playing_info_event_done(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, 0); - break; - } - connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER; - connection->parser_attribute_header_pos = 0; break; + default: - break; + return; + } + + // attribute fully read, check if more to come + if (connection->list_offset < connection->list_size){ + // more to come + connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER; + connection->parser_attribute_header_pos = 0; + } else { + // fully done + avrcp_parser_reset(connection); + avrcp_controller_emit_now_playing_info_event_done(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, 0); } } @@ -1324,4 +1327,4 @@ uint8_t avrcp_controller_set_max_num_fragments(uint16_t avrcp_cid, uint8_t max_n } connection->max_num_fragments = max_num_fragments; return ERROR_CODE_SUCCESS; -} \ No newline at end of file +}