diff --git a/example/a2dp_sink_demo.c b/example/a2dp_sink_demo.c index d8e7ae9b8..ee55b2654 100644 --- a/example/a2dp_sink_demo.c +++ b/example/a2dp_sink_demo.c @@ -161,10 +161,11 @@ static uint8_t companies[] = { 0x00, 0x19, 0x58 //BT SIG registered CompanyID }; #ifdef HAVE_BTSTACK_STDIN -// pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5}; +// pts: +static const char * device_addr_string = "00:1B:DC:08:E2:72"; // mac 2013: static const char * device_addr_string = "84:38:35:65:d1:15"; // iPhone 5S: -static const char * device_addr_string = "54:E4:3A:26:A2:39"; +// static const char * device_addr_string = "54:E4:3A:26:A2:39"; #endif static uint8_t sdp_avdtp_sink_service_buffer[150]; @@ -234,13 +235,14 @@ static int a2dp_and_avrcp_setup(void){ a2dp_sink_register_packet_handler(&a2dp_sink_packet_handler); a2dp_sink_register_media_handler(&handle_l2cap_media_data_packet); - uint8_t status = a2dp_sink_create_stream_endpoint(AVDTP_AUDIO, - AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities), - media_sbc_codec_configuration, sizeof(media_sbc_codec_configuration), &a2dp_local_seid); - if (status != ERROR_CODE_SUCCESS){ - printf("A2DP Sink : not enough memory to create local stream endpoint\n"); + avdtp_stream_endpoint_t * local_stream_endpoint = a2dp_sink_create_stream_endpoint(AVDTP_AUDIO, + AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities), + media_sbc_codec_configuration, sizeof(media_sbc_codec_configuration)); + if (!local_stream_endpoint){ + printf("A2DP Sink: not enough memory to create local stream endpoint\n"); return 1; } + a2dp_local_seid = avdtp_local_seid(local_stream_endpoint); // Initialize AVRCP Controller avrcp_controller_init(); avrcp_controller_register_packet_handler(&avrcp_controller_packet_handler); @@ -934,6 +936,8 @@ static void show_usage(void){ printf("d - AVRCP Target create connection to addr %s\n", bd_addr_to_str(device_addr)); printf("D - AVRCP Target disconnect\n"); + printf("w - delay report\n"); + 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"); @@ -999,6 +1003,10 @@ static void stdin_process(char cmd){ case '\n': case '\r': break; + case 'w': + printf("Send delay report\n"); + avdtp_sink_delay_report(a2dp_cid, a2dp_local_seid, 100); + break; // Volume Control case 't': volume_percentage = volume_percentage <= 90 ? volume_percentage + 10 : 100; diff --git a/example/a2dp_source_demo.c b/example/a2dp_source_demo.c index 3cefa0874..9484d55b6 100644 --- a/example/a2dp_source_demo.c +++ b/example/a2dp_source_demo.c @@ -139,10 +139,11 @@ typedef struct { static btstack_packet_callback_registration_t hci_event_callback_registration; // pts: static const char * device_addr_string = "00:1B:DC:08:0A:A5"; +// pts: +static const char * device_addr_string = "00:1B:DC:08:E2:72"; // mac 2013: static const char * device_addr_string = "84:38:35:65:d1:15"; // phone 2013: static const char * device_addr_string = "D8:BB:2C:DF:F0:F2"; -// Minijambox: -static const char * device_addr_string = "00:21:3C:AC:F7:38"; +// Minijambox: static const char * device_addr_string = "00:21:3C:AC:F7:38"; // Philips SHB9100: static const char * device_addr_string = "00:22:37:05:FD:E8"; // RT-B6: static const char * device_addr_string = "00:75:58:FF:C9:7D"; // BT dongle: static const char * device_addr_string = "00:1A:7D:DA:71:0A"; @@ -252,7 +253,6 @@ static int a2dp_source_and_avrcp_services_init(void){ return 1; } media_tracker.local_seid = avdtp_local_seid(local_stream_endpoint); - // Initialize AVRCP Target. avrcp_target_init(); avrcp_target_register_packet_handler(&avrcp_target_packet_handler); @@ -502,6 +502,12 @@ static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, ui break; } + case A2DP_SUBEVENT_SIGNALING_DELAY_REPORT: + printf("A2DP Source: received delay report of %d.%0d ms, local seid %d\n", + avdtp_subevent_signaling_delay_report_get_delay_100us(packet)/10, avdtp_subevent_signaling_delay_report_get_delay_100us(packet)%10, + avdtp_subevent_signaling_delay_report_get_local_seid(packet)); + break; + case A2DP_SUBEVENT_STREAM_ESTABLISHED: a2dp_subevent_stream_established_get_bd_addr(packet, address); status = a2dp_subevent_stream_established_get_status(packet); diff --git a/src/classic/a2dp_sink.c b/src/classic/a2dp_sink.c index b7c4082d0..e8e90bbb0 100644 --- a/src/classic/a2dp_sink.c +++ b/src/classic/a2dp_sink.c @@ -161,21 +161,20 @@ void a2dp_sink_init(void){ avdtp_sink_init(&a2dp_sink_context); } -uint8_t a2dp_sink_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, +avdtp_stream_endpoint_t * a2dp_sink_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * codec_capabilities, uint16_t codec_capabilities_len, - uint8_t * media_codec_info, uint16_t media_codec_info_len, uint8_t * local_seid){ - *local_seid = 0; + uint8_t * media_codec_info, uint16_t media_codec_info_len){ avdtp_stream_endpoint_t * local_stream_endpoint = avdtp_sink_create_stream_endpoint(AVDTP_SINK, media_type); if (!local_stream_endpoint){ - return BTSTACK_MEMORY_ALLOC_FAILED; + return NULL; } - *local_seid = avdtp_local_seid(local_stream_endpoint); avdtp_sink_register_media_transport_category(avdtp_stream_endpoint_seid(local_stream_endpoint)); avdtp_sink_register_media_codec_category(avdtp_stream_endpoint_seid(local_stream_endpoint), media_type, media_codec_type, codec_capabilities, codec_capabilities_len); local_stream_endpoint->remote_configuration.media_codec.media_codec_information = media_codec_info; local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = media_codec_info_len; - return ERROR_CODE_SUCCESS; + avdtp_sink_register_delay_reporting_category(avdtp_stream_endpoint_seid(local_stream_endpoint)); + return local_stream_endpoint; } uint8_t a2dp_sink_establish_stream(bd_addr_t bd_addr, uint8_t local_seid, uint16_t * avdtp_cid){ diff --git a/src/classic/a2dp_sink.h b/src/classic/a2dp_sink.h index 76493a0e6..3675e3035 100644 --- a/src/classic/a2dp_sink.h +++ b/src/classic/a2dp_sink.h @@ -78,13 +78,12 @@ void a2dp_sink_init(void); * @param codec_capabilities_len media codec capabilities length * @param codec_configuration default media codec configuration * @param codec_configuration_len media codec configuration length - * @param out_local_seid Assigned stream endpoint ID used in further A2DP commands. * - * @return status ERROR_CODE_SUCCESS if sucessful + * @return local_stream_endpoint */ -uint8_t a2dp_sink_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, +avdtp_stream_endpoint_t * a2dp_sink_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * codec_capabilities, uint16_t codec_capabilities_len, - uint8_t * codec_configuration, uint16_t codec_configuration_len, uint8_t * out_local_seid); + uint8_t * codec_configuration, uint16_t codec_configuration_len); /** * @brief Register callback for the A2DP Sink client. It will receive following subevents of HCI_EVENT_A2DP_META HCI event type: diff --git a/src/classic/a2dp_source.c b/src/classic/a2dp_source.c index 76bd7a6f3..3efabab24 100644 --- a/src/classic/a2dp_source.c +++ b/src/classic/a2dp_source.c @@ -213,6 +213,7 @@ static void a2dp_signaling_emit_reconfigured(btstack_packet_handler_t callback, (*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); @@ -267,6 +268,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe uint8_t max_bitpool_value = avdtp_choose_sbc_max_bitpool_value(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet)); uint8_t min_bitpool_value = avdtp_choose_sbc_min_bitpool_value(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet)); + sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[0] = (sampling_frequency << 4) | channel_mode; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[1] = (block_length << 4) | (subbands << 2) | allocation_method; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[2] = min_bitpool_value; @@ -276,6 +278,16 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe sc.local_stream_endpoint->remote_configuration.media_codec.media_type = AVDTP_AUDIO; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC; + // printf(" - num_channels: %d\n", num_channels); + printf(" - sampling_frequency: %d\n", sampling_frequency); + printf(" - channel_mode: %d\n", channel_mode); + printf(" - block_length: %d\n", block_length); + printf(" - subbands: %d\n", subbands); + printf(" - allocation_method: %d\n", allocation_method); + printf(" - bitpool_value orig [%d, %d] \n", avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet), avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet)); + printf(" - bitpool_value [%d, %d] \n", min_bitpool_value, max_bitpool_value); + printf("\n"); + app_state = A2DP_W2_SET_CONFIGURATION; break; } @@ -307,6 +319,11 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe case AVDTP_SUBEVENT_SIGNALING_CAPABILITY_DONE: break; + case AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT: + // forward packet: + packet[2] = A2DP_SUBEVENT_SIGNALING_DELAY_REPORT; + (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, packet, size); + break; case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{ // TODO check cid sc.sampling_frequency = avdtp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet); @@ -472,9 +489,11 @@ avdtp_stream_endpoint_t * a2dp_source_create_stream_endpoint(avdtp_media_type_t avdtp_source_register_media_transport_category(avdtp_stream_endpoint_seid(local_stream_endpoint)); avdtp_source_register_media_codec_category(avdtp_stream_endpoint_seid(local_stream_endpoint), media_type, media_codec_type, codec_capabilities, codec_capabilities_len); + local_stream_endpoint->remote_configuration.media_codec.media_codec_information = media_codec_info; local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = media_codec_info_len; sc.local_stream_endpoint = local_stream_endpoint; + avdtp_source_register_delay_reporting_category(avdtp_stream_endpoint_seid(local_stream_endpoint)); return local_stream_endpoint; } diff --git a/src/classic/a2dp_source.h b/src/classic/a2dp_source.h index eeeec58c2..e177a9448 100644 --- a/src/classic/a2dp_source.h +++ b/src/classic/a2dp_source.h @@ -78,9 +78,8 @@ void a2dp_source_init(void); * @param codec_capabilities_len Media codec capabilities length. * @param codec_configuration Default media codec configuration. * @param codec_configuration_len Media codec configuration length. - * @param out_local_seid Assigned stream endpoint ID used in further A2DP commands. * - * @return status ERROR_CODE_SUCCESS if sucessful. + * @return local_stream_endpoint */ avdtp_stream_endpoint_t * a2dp_source_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * codec_capabilities, uint16_t codec_capabilities_len, diff --git a/src/classic/avdtp_sink.c b/src/classic/avdtp_sink.c index 458729a05..3b02bde1e 100644 --- a/src/classic/avdtp_sink.c +++ b/src/classic/avdtp_sink.c @@ -193,27 +193,32 @@ uint8_t avdtp_sink_reconfigure(uint16_t avdtp_cid, uint8_t local_seid, uint8_t r } uint8_t avdtp_sink_delay_report(uint16_t avdtp_cid, uint8_t local_seid, uint16_t delay_ms){ + printf("send delay_report\n"); avdtp_connection_t * connection = avdtp_connection_for_avdtp_cid(avdtp_cid, avdtp_sink_context); if (!connection){ log_error("delay_report: no connection for signaling cid 0x%02x found", avdtp_cid); return AVDTP_CONNECTION_DOES_NOT_EXIST; } + printf("send delay_report 1\n"); if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED || connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE) { log_error("delay_report: connection in wrong state, state %d, initiator state %d", connection->state, connection->initiator_connection_state); return AVDTP_CONNECTION_IN_WRONG_STATE; } + printf("send delay_report 2\n"); avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_with_seid(local_seid, avdtp_sink_context); if (!stream_endpoint) { log_error("delay_report: no stream_endpoint with seid %d found", local_seid); return AVDTP_SEID_DOES_NOT_EXIST; } + printf("send delay_report 3\n"); if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED){ log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state); return AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE; } + printf("send delay_report 4\n"); connection->initiator_transaction_label++; connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_DELAY_REPORT;