diff --git a/example/a2dp_sink_demo.c b/example/a2dp_sink_demo.c index a3a37e137..bbc26864d 100644 --- a/example/a2dp_sink_demo.c +++ b/example/a2dp_sink_demo.c @@ -176,21 +176,14 @@ static const char * device_addr_string = "54:E4:3A:26:A2:39"; // bt dongle: -u 02-02 static bd_addr_t remote = {0x00, 0x02, 0x72, 0xDC, 0x31, 0xC1}; -static uint16_t avdtp_cid = 0; +static uint16_t a2dp_cid = 0; static uint8_t sdp_avdtp_sink_service_buffer[150]; static avdtp_sep_t sep; -static adtvp_media_codec_information_sbc_t sbc_capability; static avdtp_media_codec_configuration_sbc_t sbc_configuration; -static avdtp_stream_endpoint_t * local_stream_endpoint; static uint8_t local_seid = 0; -#ifdef HAVE_BTSTACK_STDIN -static uint16_t remote_configuration_bitmap; -static avdtp_capabilities_t remote_configuration; -#endif - typedef enum { AVDTP_APPLICATION_IDLE, AVDTP_APPLICATION_CONNECTED, @@ -559,18 +552,8 @@ static void handle_l2cap_media_data_packet(avdtp_stream_endpoint_t * stream_endp #endif } -static void dump_sbc_capability(adtvp_media_codec_information_sbc_t media_codec_sbc){ - printf("Received media codec capability:\n"); - printf(" - sampling_frequency: 0x%02x\n", media_codec_sbc.sampling_frequency_bitmap); - printf(" - channel_mode: 0x%02x\n", media_codec_sbc.channel_mode_bitmap); - printf(" - block_length: 0x%02x\n", media_codec_sbc.block_length_bitmap); - printf(" - subbands: 0x%02x\n", media_codec_sbc.subbands_bitmap); - printf(" - allocation_method: 0x%02x\n", media_codec_sbc.allocation_method_bitmap); - printf(" - bitpool_value [%d, %d] \n", media_codec_sbc.min_bitpool_value, media_codec_sbc.max_bitpool_value); -} - static void dump_sbc_configuration(avdtp_media_codec_configuration_sbc_t configuration){ - printf("Received media codec configuration:\n"); + printf(" -- a2dp sink demo: Received media codec configuration:\n"); printf(" - num_channels: %d\n", configuration.num_channels); printf(" - sampling_frequency: %d\n", configuration.sampling_frequency); printf(" - channel_mode: %d\n", configuration.channel_mode); @@ -578,6 +561,7 @@ static void dump_sbc_configuration(avdtp_media_codec_configuration_sbc_t configu printf(" - subbands: %d\n", configuration.subbands); printf(" - allocation_method: %d\n", configuration.allocation_method); printf(" - bitpool_value [%d, %d] \n", configuration.min_bitpool_value, configuration.max_bitpool_value); + printf("\n"); } static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ @@ -709,69 +693,31 @@ static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t } - static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); UNUSED(size); + uint8_t status; - bd_addr_t event_addr; switch (packet_type) { - case HCI_EVENT_PACKET: switch (hci_event_packet_get_type(packet)) { - case HCI_EVENT_PIN_CODE_REQUEST: - // inform about pin code request - printf("Pin code request - using '0000'\n"); - hci_event_pin_code_request_get_bd_addr(packet, event_addr); - hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000"); - break; - case HCI_EVENT_DISCONNECTION_COMPLETE: - // connection closed -> quit test app - app_state = AVDTP_APPLICATION_IDLE; - printf("\n --- avdtp_test: HCI_EVENT_DISCONNECTION_COMPLETE ---\n"); - media_processing_close(); - break; - case HCI_EVENT_AVDTP_META: + case HCI_EVENT_A2DP_META: switch (packet[2]){ - case AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED: - app_state = AVDTP_APPLICATION_CONNECTED; - avdtp_cid = avdtp_subevent_signaling_connection_established_get_avdtp_cid(packet); - printf("\n --- avdtp_test: AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED, cid 0x%02x ---\n", avdtp_cid); + case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION: + printf(" received non SBC codec. not implemented\n"); break; - case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND: - if (app_state < AVDTP_APPLICATION_CONNECTED) return; - sep.seid = avdtp_subevent_signaling_sep_found_get_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); - printf("Found sep: seid %u, in_use %d, media type %d, sep type %d (1-SNK)\n", sep.seid, sep.in_use, sep.media_type, sep.type); - break; - case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY: - if (app_state < AVDTP_APPLICATION_CONNECTED) return; - sbc_capability.sampling_frequency_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet); - sbc_capability.channel_mode_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet); - sbc_capability.block_length_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet); - sbc_capability.subbands_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(packet); - sbc_capability.allocation_method_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(packet); - sbc_capability.min_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet); - sbc_capability.max_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet); - dump_sbc_capability(sbc_capability); - break; - case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{ - if (app_state < AVDTP_APPLICATION_CONNECTED) return; - sbc_configuration.reconfigure = avdtp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet); - sbc_configuration.num_channels = avdtp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet); - sbc_configuration.sampling_frequency = avdtp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet); - sbc_configuration.channel_mode = avdtp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet); - sbc_configuration.block_length = avdtp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet); - sbc_configuration.subbands = avdtp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet); - sbc_configuration.allocation_method = avdtp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet); - sbc_configuration.min_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet); - sbc_configuration.max_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet); + case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{ + sbc_configuration.reconfigure = a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet); + sbc_configuration.num_channels = a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet); + sbc_configuration.sampling_frequency = a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet); + sbc_configuration.channel_mode = a2dp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet); + sbc_configuration.block_length = a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet); + sbc_configuration.subbands = a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet); + sbc_configuration.allocation_method = a2dp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet); + sbc_configuration.min_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet); + sbc_configuration.max_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet); sbc_configuration.frames_per_buffer = sbc_configuration.subbands * sbc_configuration.block_length; dump_sbc_configuration(sbc_configuration); - // // TODO: use actual config - // btstack_sbc_encoder_init(&local_stream_endpoint->sbc_encoder_state, SBC_MODE_STANDARD, 16, 8, 2, 44100, 53); if (sbc_configuration.reconfigure){ media_processing_close(); @@ -781,14 +727,55 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe } break; } - case AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED: + case A2DP_SUBEVENT_STREAM_ESTABLISHED: + status = a2dp_subevent_stream_established_get_status(packet); + if (status != 0){ + printf(" -- a2dp sink demo: streaming connection cannot be established, status 0x%02X\n", status); + app_state = AVDTP_APPLICATION_IDLE; + break; + } + // TODO: check it it the correct a2dp cid + a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet); + printf(" -- a2dp sink demo: streaming connection is established, a2dp cid 0x%02X\n", status); app_state = AVDTP_APPLICATION_STREAMING; break; - case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY: - printf(" received non SBC codec. not implemented\n"); + + case A2DP_SUBEVENT_STREAM_STARTED: + status = a2dp_subevent_stream_started_get_status(packet); + if (status != 0){ + printf(" -- a2dp sink demo: stream cannot be started, status 0x%02X\n", status); + app_state = AVDTP_APPLICATION_IDLE; + break; + } + // TODO: check it it the correct a2dp cid + a2dp_cid = a2dp_subevent_stream_started_get_a2dp_cid(packet); + printf(" -- a2dp sink demo: streaming, a2dp cid 0x%02X\n", status); break; - case AVDTP_SUBEVENT_SIGNALING_ACCEPT: + + case A2DP_SUBEVENT_STREAM_SUSPENDED: + status = a2dp_subevent_stream_suspended_get_status(packet); + if (status != 0){ + printf(" -- a2dp sink demo: stream cannot be paused, status 0x%02X\n", status); + break; + } + // TODO: check it it the correct a2dp cid + a2dp_cid = a2dp_subevent_stream_started_get_a2dp_cid(packet); + printf(" -- a2dp sink demo: stream paused, a2dp cid 0x%02X\n", status); break; + + case A2DP_SUBEVENT_STREAM_RELEASED: + status = a2dp_subevent_stream_released_get_status(packet); + if (status != 0){ + printf(" -- a2dp sink demo: stream cannot be released, status 0x%02X\n", status); + break; + } + // TODO: check it it the correct a2dp cid + a2dp_cid = a2dp_subevent_stream_released_get_a2dp_cid(packet); + app_state = AVDTP_APPLICATION_IDLE; + printf(" -- a2dp sink demo: stream released, a2dp cid 0x%02X\n", status); + media_processing_close(); + break; + default: printf(" not implemented\n"); break; @@ -814,19 +801,6 @@ static void show_usage(void){ printf("c - AVRCP create connection to addr %s\n", device_addr_string); printf("C - AVRCP disconnect\n"); - printf("\n--- Bluetooth AVDTP SINK Commands %s ---\n", bd_addr_to_str(iut_address)); - printf("d - discover stream endpoints\n"); - printf("g - get capabilities\n"); - printf("a - get all capabilities\n"); - printf("s - set configuration\n"); - printf("f - get configuration\n"); - printf("R - reconfigure stream with %d\n", sep.seid); - printf("o - open stream with seid %d\n", sep.seid); - printf("m - start stream with %d\n", sep.seid); - printf("A - abort stream with %d\n", sep.seid); - printf("S - stop stream with %d\n", sep.seid); - printf("P - suspend stream with %d\n", sep.seid); - printf("\n--- Bluetooth AVRCP Commands %s ---\n", bd_addr_to_str(iut_address)); printf("O - get play status\n"); printf("j - get now playing info\n"); @@ -869,22 +843,16 @@ static uint8_t media_sbc_codec_configuration[] = { 2, 53 }; -static uint8_t media_sbc_codec_reconfiguration[] = { - (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO, - (AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_SNR, - 2, 53 -}; - static void stdin_process(char cmd){ sep.seid = 1; switch (cmd){ case 'b': - printf("Creating L2CAP Connection to %s, BLUETOOTH_PROTOCOL_AVDTP\n", device_addr_string); - avdtp_sink_connect(device_addr); + printf("Creating L2CAP Connection to %s, PSM_AVDTP\n", bd_addr_to_str(device_addr)); + a2dp_sink_establish_stream(device_addr, local_seid); break; case 'B': printf("Disconnect\n"); - avdtp_sink_disconnect(avdtp_cid); + avdtp_sink_disconnect(a2dp_cid); break; case 'c': printf(" - Create AVRCP connection to addr %s.\n", bd_addr_to_str(device_addr)); @@ -896,50 +864,6 @@ static void stdin_process(char cmd){ avrcp_disconnect(avrcp_cid); break; - case 'd': - avdtp_sink_discover_stream_endpoints(avdtp_cid); - break; - case 'g': - avdtp_sink_get_capabilities(avdtp_cid, sep.seid); - break; - case 'a': - avdtp_sink_get_all_capabilities(avdtp_cid, sep.seid); - break; - case 'f': - avdtp_sink_get_configuration(avdtp_cid, sep.seid); - break; - case 's': - remote_configuration_bitmap = store_bit16(remote_configuration_bitmap, AVDTP_MEDIA_CODEC, 1); - remote_configuration.media_codec.media_type = AVDTP_AUDIO; - remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC; - remote_configuration.media_codec.media_codec_information_len = sizeof(media_sbc_codec_configuration); - remote_configuration.media_codec.media_codec_information = media_sbc_codec_configuration; - avdtp_sink_set_configuration(avdtp_cid, local_stream_endpoint->sep.seid, sep.seid, remote_configuration_bitmap, remote_configuration); - break; - case 'R': - remote_configuration_bitmap = store_bit16(remote_configuration_bitmap, AVDTP_MEDIA_CODEC, 1); - remote_configuration.media_codec.media_type = AVDTP_AUDIO; - remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC; - remote_configuration.media_codec.media_codec_information_len = sizeof(media_sbc_codec_reconfiguration); - remote_configuration.media_codec.media_codec_information = media_sbc_codec_reconfiguration; - avdtp_sink_reconfigure(avdtp_cid, local_stream_endpoint->sep.seid, sep.seid, remote_configuration_bitmap, remote_configuration); - break; - case 'o': - avdtp_sink_open_stream(avdtp_cid, local_stream_endpoint->sep.seid, sep.seid); - break; - case 'm': - avdtp_sink_start_stream(local_stream_endpoint->sep.seid); - break; - case 'A': - avdtp_sink_abort_stream(local_stream_endpoint->sep.seid); - break; - case 'S': - avdtp_sink_stop_stream(local_stream_endpoint->sep.seid); - break; - case 'P': - avdtp_sink_suspend(local_stream_endpoint->sep.seid); - break; - case '\n': case '\r': break; diff --git a/src/btstack_defines.h b/src/btstack_defines.h index 3cb1f5acc..d48aa6c87 100644 --- a/src/btstack_defines.h +++ b/src/btstack_defines.h @@ -1262,12 +1262,11 @@ typedef uint8_t sm_key_t[16]; /** AVDTP Subevent */ /** - * @format 12111 + * @format 1211 * @param subevent_code * @param avdtp_cid - * @param int_seid + * @param local_seid * @param signal_identifier - * @param status 0 == OK */ #define AVDTP_SUBEVENT_SIGNALING_ACCEPT 0x01 @@ -1421,11 +1420,44 @@ typedef uint8_t sm_key_t[16]; /** * @format 121 Sent only by A2DP source. * @param subevent_code - * @param avdtp_cid + * @param a2dp_cid * @param local_seid */ #define A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW 0x01 +/** + * @format 12111121111111 + * @param subevent_code + * @param a2dp_cid + * @param int_seid + * @param acp_seid + * @param reconfigure + * @param media_type + * @param sampling_frequency + * @param channel_mode + * @param num_channels + * @param block_length + * @param subbands + * @param allocation_method + * @param min_bitpool_value + * @param max_bitpool_value + */ +#define A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION 0x02 + +/** + * @format 1211112LV + * @param subevent_code + * @param a2dp_cid + * @param int_seid + * @param acp_seid + * @param reconfigure + * @param media_type + * @param media_codec_type + * @param media_codec_information_len + * @param media_codec_information + */ +#define A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION 0x03 + /** * @format 12111 Stream is opened byt not started. * @param subevent_code @@ -1434,31 +1466,34 @@ typedef uint8_t sm_key_t[16]; * @param remote_seid * @param status */ -#define A2DP_SUBEVENT_STREAM_ESTABLISHED 0x02 +#define A2DP_SUBEVENT_STREAM_ESTABLISHED 0x04 /** - * @format 121 Indicates that media transfer is started. + * @format 1211 Indicates that media transfer is started. * @param subevent_code * @param a2dp_cid * @param local_seid + * @param status */ -#define A2DP_SUBEVENT_STREAM_STARTED 0x03 +#define A2DP_SUBEVENT_STREAM_STARTED 0x05 /** - * @format 121 Stream is paused. + * @format 1211 Stream is paused. * @param subevent_code * @param a2dp_cid * @param local_seid + * @param status */ -#define A2DP_SUBEVENT_STREAM_SUSPENDED 0x04 +#define A2DP_SUBEVENT_STREAM_SUSPENDED 0x06 /** - * @format 121 Stream is released. + * @format 1211 Stream is released. * @param subevent_code - * @param avdtp_cid + * @param a2dp_cid * @param local_seid + * @param status */ -#define A2DP_SUBEVENT_STREAM_RELEASED 0x05 +#define A2DP_SUBEVENT_STREAM_RELEASED 0x07 diff --git a/src/btstack_event.h b/src/btstack_event.h index 27db3467a..8a82c3eec 100644 --- a/src/btstack_event.h +++ b/src/btstack_event.h @@ -3989,12 +3989,12 @@ static inline uint16_t avdtp_subevent_signaling_accept_get_avdtp_cid(const uint8 return little_endian_read_16(event, 3); } /** - * @brief Get field int_seid from event AVDTP_SUBEVENT_SIGNALING_ACCEPT + * @brief Get field local_seid from event AVDTP_SUBEVENT_SIGNALING_ACCEPT * @param event packet - * @return int_seid + * @return local_seid * @note: btstack_type 1 */ -static inline uint8_t avdtp_subevent_signaling_accept_get_int_seid(const uint8_t * event){ +static inline uint8_t avdtp_subevent_signaling_accept_get_local_seid(const uint8_t * event){ return event[5]; } /** @@ -4006,15 +4006,6 @@ static inline uint8_t avdtp_subevent_signaling_accept_get_int_seid(const uint8_t static inline uint8_t avdtp_subevent_signaling_accept_get_signal_identifier(const uint8_t * event){ return event[6]; } -/** - * @brief Get field status from event AVDTP_SUBEVENT_SIGNALING_ACCEPT - * @param event packet - * @return status - * @note: btstack_type 1 - */ -static inline uint8_t avdtp_subevent_signaling_accept_get_status(const uint8_t * event){ - return event[7]; -} /** * @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_REJECT @@ -4587,12 +4578,12 @@ static inline uint16_t avdtp_subevent_streaming_can_send_media_packet_now_get_se } /** - * @brief Get field avdtp_cid from event A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW * @param event packet - * @return avdtp_cid + * @return a2dp_cid * @note: btstack_type 2 */ -static inline uint16_t a2dp_subevent_streaming_can_send_media_packet_now_get_avdtp_cid(const uint8_t * event){ +static inline uint16_t a2dp_subevent_streaming_can_send_media_packet_now_get_a2dp_cid(const uint8_t * event){ return little_endian_read_16(event, 3); } /** @@ -4605,6 +4596,197 @@ static inline uint8_t a2dp_subevent_streaming_can_send_media_packet_now_get_loca return event[5]; } +/** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ +static inline uint16_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_a2dp_cid(const uint8_t * event){ + return little_endian_read_16(event, 3); +} +/** + * @brief Get field int_seid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return int_seid + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_int_seid(const uint8_t * event){ + return event[5]; +} +/** + * @brief Get field acp_seid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return acp_seid + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_acp_seid(const uint8_t * event){ + return event[6]; +} +/** + * @brief Get field reconfigure from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return reconfigure + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(const uint8_t * event){ + return event[7]; +} +/** + * @brief Get field media_type from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return media_type + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_media_type(const uint8_t * event){ + return event[8]; +} +/** + * @brief Get field sampling_frequency from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return sampling_frequency + * @note: btstack_type 2 + */ +static inline uint16_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(const uint8_t * event){ + return little_endian_read_16(event, 9); +} +/** + * @brief Get field channel_mode from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return channel_mode + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(const uint8_t * event){ + return event[11]; +} +/** + * @brief Get field num_channels from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return num_channels + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(const uint8_t * event){ + return event[12]; +} +/** + * @brief Get field block_length from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return block_length + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(const uint8_t * event){ + return event[13]; +} +/** + * @brief Get field subbands from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return subbands + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(const uint8_t * event){ + return event[14]; +} +/** + * @brief Get field allocation_method from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return allocation_method + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(const uint8_t * event){ + return event[15]; +} +/** + * @brief Get field min_bitpool_value from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return min_bitpool_value + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(const uint8_t * event){ + return event[16]; +} +/** + * @brief Get field max_bitpool_value from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION + * @param event packet + * @return max_bitpool_value + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(const uint8_t * event){ + return event[17]; +} + +/** + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return a2dp_cid + * @note: btstack_type 2 + */ +static inline uint16_t a2dp_subevent_signaling_media_codec_other_configuration_get_a2dp_cid(const uint8_t * event){ + return little_endian_read_16(event, 3); +} +/** + * @brief Get field int_seid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return int_seid + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_other_configuration_get_int_seid(const uint8_t * event){ + return event[5]; +} +/** + * @brief Get field acp_seid from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return acp_seid + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_other_configuration_get_acp_seid(const uint8_t * event){ + return event[6]; +} +/** + * @brief Get field reconfigure from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return reconfigure + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_other_configuration_get_reconfigure(const uint8_t * event){ + return event[7]; +} +/** + * @brief Get field media_type from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_type + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_signaling_media_codec_other_configuration_get_media_type(const uint8_t * event){ + return event[8]; +} +/** + * @brief Get field media_codec_type from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_codec_type + * @note: btstack_type 2 + */ +static inline uint16_t a2dp_subevent_signaling_media_codec_other_configuration_get_media_codec_type(const uint8_t * event){ + return little_endian_read_16(event, 9); +} +/** + * @brief Get field media_codec_information_len from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_codec_information_len + * @note: btstack_type L + */ +static inline int a2dp_subevent_signaling_media_codec_other_configuration_get_media_codec_information_len(const uint8_t * event){ + return little_endian_read_16(event, 11); +} +/** + * @brief Get field media_codec_information from event A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION + * @param event packet + * @return media_codec_information + * @note: btstack_type V + */ +static inline const uint8_t * a2dp_subevent_signaling_media_codec_other_configuration_get_media_codec_information(const uint8_t * event){ + return &event[13]; +} + /** * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_ESTABLISHED * @param event packet @@ -4660,6 +4842,15 @@ static inline uint16_t a2dp_subevent_stream_started_get_a2dp_cid(const uint8_t * static inline uint8_t a2dp_subevent_stream_started_get_local_seid(const uint8_t * event){ return event[5]; } +/** + * @brief Get field status from event A2DP_SUBEVENT_STREAM_STARTED + * @param event packet + * @return status + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_stream_started_get_status(const uint8_t * event){ + return event[6]; +} /** * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_SUSPENDED @@ -4679,14 +4870,23 @@ static inline uint16_t a2dp_subevent_stream_suspended_get_a2dp_cid(const uint8_t static inline uint8_t a2dp_subevent_stream_suspended_get_local_seid(const uint8_t * event){ return event[5]; } +/** + * @brief Get field status from event A2DP_SUBEVENT_STREAM_SUSPENDED + * @param event packet + * @return status + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_stream_suspended_get_status(const uint8_t * event){ + return event[6]; +} /** - * @brief Get field avdtp_cid from event A2DP_SUBEVENT_STREAM_RELEASED + * @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_RELEASED * @param event packet - * @return avdtp_cid + * @return a2dp_cid * @note: btstack_type 2 */ -static inline uint16_t a2dp_subevent_stream_released_get_avdtp_cid(const uint8_t * event){ +static inline uint16_t a2dp_subevent_stream_released_get_a2dp_cid(const uint8_t * event){ return little_endian_read_16(event, 3); } /** @@ -4698,6 +4898,15 @@ static inline uint16_t a2dp_subevent_stream_released_get_avdtp_cid(const uint8_t static inline uint8_t a2dp_subevent_stream_released_get_local_seid(const uint8_t * event){ return event[5]; } +/** + * @brief Get field status from event A2DP_SUBEVENT_STREAM_RELEASED + * @param event packet + * @return status + * @note: btstack_type 1 + */ +static inline uint8_t a2dp_subevent_stream_released_get_status(const uint8_t * event){ + return event[6]; +} /** * @brief Get field status from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED diff --git a/src/classic/a2dp_sink.c b/src/classic/a2dp_sink.c index a742af8c3..dc786353c 100644 --- a/src/classic/a2dp_sink.c +++ b/src/classic/a2dp_sink.c @@ -140,8 +140,8 @@ void a2dp_sink_create_sdp_record(uint8_t * service, uint32_t service_record_han } void a2dp_sink_register_packet_handler(btstack_packet_handler_t callback){ - avdtp_sink_register_packet_handler(callback); - return; + // avdtp_sink_register_packet_handler(callback); + // return; if (callback == NULL){ log_error("a2dp_sink_register_packet_handler called with NULL callback"); return; @@ -189,15 +189,53 @@ void a2dp_sink_disconnect(uint16_t a2dp_cid){ avdtp_disconnect(a2dp_cid, &a2dp_sink_context); } - -static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ +static void a2dp_streaming_emit_connection_established(btstack_packet_handler_t callback, uint8_t * event, uint16_t event_size){ + if (!callback) return; + if (event_size < 8) return; + event[0] = HCI_EVENT_A2DP_META; + event[2] = A2DP_SUBEVENT_STREAM_ESTABLISHED; + (*callback)(HCI_EVENT_PACKET, 0, event, event_size); +} +static inline void a2dp_signaling_emit_media_codec_sbc(btstack_packet_handler_t callback, uint8_t * event, uint16_t event_size){ + if (!callback) return; + if (event_size < 18) return; + event[0] = HCI_EVENT_A2DP_META; + event[2] = A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION; + (*callback)(HCI_EVENT_PACKET, 0, event, event_size); +} + +static inline void avdtp_signaling_emit_media_codec_other(btstack_packet_handler_t callback, uint8_t * event, uint16_t event_size){ + if (!callback) return; + if (event_size < 112) return; + event[0] = HCI_EVENT_A2DP_META; + event[2] = A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION; +} + +static inline void a2dp_emit_stream_event(btstack_packet_handler_t callback, uint16_t a2dp_cid, uint8_t eventID, uint8_t local_seid, uint8_t status){ + uint8_t event[7]; + int pos = 0; + event[pos++] = HCI_EVENT_A2DP_META; + event[pos++] = sizeof(event) - 2; + event[pos++] = eventID; + little_endian_store_16(event, pos, a2dp_cid); + pos += 2; + event[pos++] = local_seid; + event[pos++] = status; + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + +} + +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); UNUSED(size); - bd_addr_t event_addr; + uint8_t status; + uint8_t signal_identifier; + uint16_t cid; + uint8_t local_seid; + switch (packet_type) { - case HCI_EVENT_PACKET: switch (hci_event_packet_get_type(packet)) { case HCI_EVENT_PIN_CODE_REQUEST: @@ -209,68 +247,92 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe case HCI_EVENT_DISCONNECTION_COMPLETE: // connection closed -> quit test app app_state = A2DP_IDLE; - printf("\n --- avdtp_test: HCI_EVENT_DISCONNECTION_COMPLETE ---\n"); + printf("\n --- a2dp sink: HCI_EVENT_DISCONNECTION_COMPLETE ---\n"); break; case HCI_EVENT_AVDTP_META: switch (packet[2]){ case AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED: + status = avdtp_subevent_signaling_connection_established_get_status(packet); + if (status != 0){ + log_info(" --- a2dp sink --- AVDTP_SUBEVENT_SIGNALING_CONNECTION could not be established, status %d ---", status); + break; + } app_state = A2DP_CONNECTED; avdtp_cid = avdtp_subevent_signaling_connection_established_get_avdtp_cid(packet); - printf("\n --- avdtp_test: AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED, cid 0x%02x ---\n", avdtp_cid); + log_info(" --- a2dp sink --- AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED, avdtp cid 0x%02x ---", avdtp_cid); break; - case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND: - if (app_state < A2DP_CONNECTED) return; - // sep.seid = avdtp_subevent_signaling_sep_found_get_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); - // printf("Found sep: seid %u, in_use %d, media type %d, sep type %d (1-SNK)\n", sep.seid, sep.in_use, sep.media_type, sep.type); - break; - case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY: - if (app_state < A2DP_CONNECTED) return; - // sbc_capability.sampling_frequency_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet); - // sbc_capability.channel_mode_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet); - // sbc_capability.block_length_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet); - // sbc_capability.subbands_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(packet); - // sbc_capability.allocation_method_bitmap = avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(packet); - // sbc_capability.min_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet); - // sbc_capability.max_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet); - // dump_sbc_capability(sbc_capability); - break; - case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{ - if (app_state < A2DP_CONNECTED) return; - // sbc_configuration.reconfigure = avdtp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet); - // sbc_configuration.num_channels = avdtp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet); - // sbc_configuration.sampling_frequency = avdtp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet); - // sbc_configuration.channel_mode = avdtp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet); - // sbc_configuration.block_length = avdtp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet); - // sbc_configuration.subbands = avdtp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet); - // sbc_configuration.allocation_method = avdtp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet); - // sbc_configuration.min_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet); - // sbc_configuration.max_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet); - // sbc_configuration.frames_per_buffer = sbc_configuration.subbands * sbc_configuration.block_length; - // dump_sbc_configuration(sbc_configuration); - // // // TODO: use actual config - // btstack_sbc_encoder_init(&local_stream_endpoint->sbc_encoder_state, SBC_MODE_STANDARD, 16, 8, 2, 44100, 53); - // if (sbc_configuration.reconfigure){ - // media_processing_close(); - // media_processing_init(sbc_configuration); - // } else { - // media_processing_init(sbc_configuration); - // } + case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION: + log_info(" --- a2dp sink --- received non SBC codec. not implemented"); + avdtp_signaling_emit_media_codec_other(a2dp_sink_context.a2dp_callback, packet, size); break; - } + + case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION: + if (app_state < A2DP_CONNECTED) return; + a2dp_signaling_emit_media_codec_sbc(a2dp_sink_context.a2dp_callback, packet, size); + break; + case AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED: - app_state = A2DP_STREAMING_OPENED; - break; - case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY: - printf(" received non SBC codec. not implemented\n"); + status = avdtp_subevent_streaming_connection_established_get_status(packet); + if (status != 0){ + app_state = A2DP_CONNECTED; + } else { + app_state = A2DP_STREAMING_OPENED; + } + a2dp_streaming_emit_connection_established(a2dp_sink_context.a2dp_callback, packet, size); break; + case AVDTP_SUBEVENT_SIGNALING_ACCEPT: + if (!a2dp_sink_context.a2dp_callback) return; + status = 0; + signal_identifier = avdtp_subevent_signaling_accept_get_signal_identifier(packet); + cid = avdtp_subevent_signaling_accept_get_avdtp_cid(packet); + local_seid = avdtp_subevent_signaling_accept_get_local_seid(packet); + printf(" --- a2dp sink --- Accepted %d, a2dp sink cid 0x%2x, local seid %d\n", signal_identifier, cid, local_seid); + + switch (signal_identifier){ + case AVDTP_SI_START: + a2dp_emit_stream_event(a2dp_sink_context.a2dp_callback, cid, A2DP_SUBEVENT_STREAM_STARTED, local_seid, status); + break; + case AVDTP_SI_SUSPEND: + a2dp_emit_stream_event(a2dp_sink_context.a2dp_callback, cid, A2DP_SUBEVENT_STREAM_SUSPENDED, local_seid, status); + break; + case AVDTP_SI_ABORT: + case AVDTP_SI_CLOSE: + a2dp_emit_stream_event(a2dp_sink_context.a2dp_callback, cid, A2DP_SUBEVENT_STREAM_RELEASED, local_seid, status); + break; + default: + break; + } + break; + + case AVDTP_SUBEVENT_SIGNALING_REJECT: + case AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT: + if (!a2dp_sink_context.a2dp_callback) return; + status = 1; + signal_identifier = avdtp_subevent_signaling_accept_get_signal_identifier(packet); + cid = avdtp_subevent_signaling_accept_get_avdtp_cid(packet); + local_seid = avdtp_subevent_signaling_accept_get_local_seid(packet); + printf(" --- a2dp sink --- Rejected %d, a2dp sink cid 0x%2x, local seid %d\n", signal_identifier, cid, local_seid); + + switch (signal_identifier){ + case AVDTP_SI_START: + a2dp_emit_stream_event(a2dp_sink_context.a2dp_callback, cid, A2DP_SUBEVENT_STREAM_STARTED, local_seid, status); + break; + case AVDTP_SI_SUSPEND: + a2dp_emit_stream_event(a2dp_sink_context.a2dp_callback, cid, A2DP_SUBEVENT_STREAM_SUSPENDED, local_seid, status); + break; + case AVDTP_SI_ABORT: + case AVDTP_SI_CLOSE: + a2dp_emit_stream_event(a2dp_sink_context.a2dp_callback, cid, A2DP_SUBEVENT_STREAM_RELEASED, local_seid, status); + break; + default: + break; + } break; default: - printf(" not implemented\n"); + app_state = A2DP_IDLE; + log_info(" --- a2dp sink --- not implemented"); break; } break; diff --git a/src/classic/a2dp_source.c b/src/classic/a2dp_source.c index 1597f56a3..febfd8ae6 100644 --- a/src/classic/a2dp_source.c +++ b/src/classic/a2dp_source.c @@ -269,7 +269,6 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe case AVDTP_SUBEVENT_SIGNALING_ACCEPT: signal_identifier = avdtp_subevent_signaling_accept_get_signal_identifier(packet); - status = avdtp_subevent_signaling_accept_get_status(packet); log_info(" --- a2dp source --- Accepted %d", signal_identifier); switch (app_state){