From 67673f1cc201341f9ffbfc67d22aa84e26381efe Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Wed, 12 Jul 2017 15:24:11 +0200 Subject: [PATCH] a2dp source demo: cleanup --- example/a2dp_source_demo.c | 296 +++++++++++++++++-------------------- example/hfp_hf_demo.c | 4 - src/classic/a2dp_source.c | 5 - src/classic/a2dp_source.h | 7 - 4 files changed, 137 insertions(+), 175 deletions(-) diff --git a/example/a2dp_source_demo.c b/example/a2dp_source_demo.c index fe61301df..26823b18f 100644 --- a/example/a2dp_source_demo.c +++ b/example/a2dp_source_demo.c @@ -46,25 +46,32 @@ #include "hxcmod.h" #include "mods/mod.h" -#define NUM_CHANNELS 2 -#define A2DP_SAMPLE_RATE 44100 -#define BYTES_PER_AUDIO_SAMPLE (2*NUM_CHANNELS) -#define FILL_AUDIO_BUFFER_TIMEOUT_MS 10 - -#ifndef M_PI -#define M_PI 3.14159265 -#endif -#define TABLE_SIZE_441HZ 100 - -typedef struct { - int left_phase; - int right_phase; -} paTestData; +#define NUM_CHANNELS 2 +#define A2DP_SAMPLE_RATE 44100 +#define BYTES_PER_AUDIO_SAMPLE (2*NUM_CHANNELS) +#define AUDIO_TIMEOUT_MS 10 +#define TABLE_SIZE_441HZ 100 typedef enum { STREAM_SINE, STREAM_MOD } stream_data_source_t; + +typedef struct { + uint16_t a2dp_cid; + uint8_t local_seid; + + uint32_t time_audio_data_sent; // ms + uint32_t acc_num_missed_samples; + uint32_t samples_ready; + btstack_timer_source_t audio_timer; + uint8_t streaming; + int max_media_payload_size; + + uint8_t sbc_storage[1030]; + uint16_t sbc_storage_count; + uint8_t sbc_ready_to_send; +} a2dp_media_sending_context_t; static uint8_t media_sbc_codec_capabilities[] = { (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO, @@ -88,135 +95,47 @@ static const int16_t sine_int16[] = { static char * device_name = "A2DP Source BTstack"; #ifdef HAVE_BTSTACK_STDIN -// mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3}; -// pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5}; -// mac 2013: static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15}; -// phone 2013: static bd_addr_t remote = {0xD8, 0xBB, 0x2C, 0xDF, 0xF0, 0xF2}; +// mac 2011: static const char * device_addr_string = "04:0C:CE:E4:85:D3"; +// pts: static const char * device_addr_string = "00:1B:DC:08:0A:A5"; +// 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 bd_addr_t remote = {0x00, 0x21, 0x3c, 0xac, 0xf7, 0x38}; -// head phones: static bd_addr_t remote = {0x00, 0x18, 0x09, 0x28, 0x50, 0x18}; -// bt dongle: -u 02-04-01 -// static bd_addr_t remote = {0x00, 0x15, 0x83, 0x5F, 0x9D, 0x46}; +static const char * device_addr_string = "00:21:3C:AC:F7:38"; +// head phones: static const char * device_addr_string = "00:18:09:28:50:18"; +// bt dongle: static const char * device_addr_string = "00:15:83:5F:9D:46"; #endif -static uint8_t sdp_avdtp_source_service_buffer[150]; +static bd_addr_t device_addr; +static uint8_t sdp_a2dp_source_service_buffer[150]; static uint8_t media_sbc_codec_configuration[4]; - -typedef struct { - uint16_t a2dp_cid; - uint8_t local_seid; - - uint32_t time_audio_data_sent; // ms - uint32_t acc_num_missed_samples; - uint32_t samples_ready; - btstack_timer_source_t fill_audio_buffer_timer; - uint8_t streaming; - - int max_media_payload_size; - - uint8_t sbc_storage[1030]; - uint16_t sbc_storage_count; - uint8_t sbc_ready_to_send; - -} a2dp_media_sending_context_t; - static a2dp_media_sending_context_t media_tracker; -static paTestData sin_data; +static stream_data_source_t data_source; -static int hxcmod_initialized = 0; +static int sine_phase; + +static int hxcmod_initialized; static modcontext mod_context; static tracker_buffer_state trkbuf; -static uint8_t local_seid = 0; -stream_data_source_t data_source = STREAM_SINE; - -static btstack_packet_callback_registration_t hci_event_callback_registration; - -static void a2dp_fill_audio_buffer_timer_start(a2dp_media_sending_context_t * context); -static void a2dp_fill_audio_buffer_timer_stop(a2dp_media_sending_context_t * context); -static void a2dp_fill_audio_buffer_timer_pause(a2dp_media_sending_context_t * context); - -static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ - UNUSED(channel); - UNUSED(size); - uint8_t status; - switch (packet_type) { - - case HCI_EVENT_PACKET: - switch (hci_event_packet_get_type(packet)) { - case HCI_EVENT_A2DP_META: - switch (packet[2]){ - case A2DP_SUBEVENT_STREAM_ESTABLISHED: - status = a2dp_subevent_stream_established_get_status(packet); - if (status){ - printf("Stream establishment failed: status 0x%02x.\n", status); - break; - } - media_tracker.local_seid = a2dp_subevent_stream_established_get_local_seid(packet); - media_tracker.a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet); - printf("Stream established: a2dp cid 0x%02x, local seid %d, remote seid %d.\n", - media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet)); - break; - - case A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:{ - if (local_seid != media_tracker.local_seid) break; - - int num_bytes_in_frame = btstack_sbc_encoder_sbc_buffer_length(); - int bytes_in_storage = media_tracker.sbc_storage_count; - uint8_t num_frames = bytes_in_storage / num_bytes_in_frame; - - a2dp_source_stream_send_media_payload(media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0); - media_tracker.sbc_storage_count = 0; - media_tracker.sbc_ready_to_send = 0; - break; - } - case A2DP_SUBEVENT_STREAM_STARTED: - if (local_seid != media_tracker.local_seid) break; - if (!a2dp_source_stream_endpoint_ready(media_tracker.a2dp_cid, media_tracker.local_seid)) break; - a2dp_fill_audio_buffer_timer_start(&media_tracker); - printf("Stream started.\n"); - break; - - case A2DP_SUBEVENT_STREAM_SUSPENDED: - printf("Stream paused.\n"); - a2dp_fill_audio_buffer_timer_pause(&media_tracker); - break; - - case A2DP_SUBEVENT_STREAM_RELEASED: - printf("Stream released.\n"); - a2dp_fill_audio_buffer_timer_stop(&media_tracker); - break; - default: - printf("AVDTP Source demo: event 0x%02x is not implemented\n", packet[2]); - break; - } - break; - default: - break; - } - break; - default: - // other packet type - break; - } +static void a2dp_demo_send_media_packet(void){ + int num_bytes_in_frame = btstack_sbc_encoder_sbc_buffer_length(); + int bytes_in_storage = media_tracker.sbc_storage_count; + uint8_t num_frames = bytes_in_storage / num_bytes_in_frame; + a2dp_source_stream_send_media_payload(media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0); + media_tracker.sbc_storage_count = 0; + media_tracker.sbc_ready_to_send = 0; } -static void produce_sine_audio(int16_t * pcm_buffer, void *user_data, int num_samples_to_write){ - paTestData *data = (paTestData*)user_data; +static void produce_sine_audio(int16_t * pcm_buffer, int num_samples_to_write){ int count; for (count = 0; count < num_samples_to_write ; count++){ - pcm_buffer[count * 2] = sine_int16[data->left_phase]; - pcm_buffer[count * 2 + 1] = sine_int16[data->right_phase]; - - data->left_phase += 1; - if (data->left_phase >= TABLE_SIZE_441HZ){ - data->left_phase -= TABLE_SIZE_441HZ; + pcm_buffer[count * 2] = sine_int16[sine_phase]; + pcm_buffer[count * 2 + 1] = sine_int16[sine_phase]; + sine_phase++; + if (sine_phase >= TABLE_SIZE_441HZ){ + sine_phase -= TABLE_SIZE_441HZ; } - data->right_phase += 1; - if (data->right_phase >= TABLE_SIZE_441HZ){ - data->right_phase -= TABLE_SIZE_441HZ; - } } } @@ -227,7 +146,7 @@ static void produce_mod_audio(int16_t * pcm_buffer, int num_samples_to_write){ static void produce_audio(int16_t * pcm_buffer, int num_samples){ switch (data_source){ case STREAM_SINE: - produce_sine_audio(pcm_buffer, &sin_data, num_samples); + produce_sine_audio(pcm_buffer, num_samples); break; case STREAM_MOD: produce_mod_audio(pcm_buffer, num_samples); @@ -258,13 +177,13 @@ static int fill_sbc_audio_buffer(a2dp_media_sending_context_t * context){ return total_num_bytes_read; } -static void avdtp_fill_audio_buffer_timeout_handler(btstack_timer_source_t * timer){ +static void avdtp_audio_timeout_handler(btstack_timer_source_t * timer){ a2dp_media_sending_context_t * context = (a2dp_media_sending_context_t *) btstack_run_loop_get_timer_context(timer); - btstack_run_loop_set_timer(&context->fill_audio_buffer_timer, FILL_AUDIO_BUFFER_TIMEOUT_MS); - btstack_run_loop_add_timer(&context->fill_audio_buffer_timer); + btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS); + btstack_run_loop_add_timer(&context->audio_timer); uint32_t now = btstack_run_loop_get_time_ms(); - uint32_t update_period_ms = FILL_AUDIO_BUFFER_TIMEOUT_MS; + uint32_t update_period_ms = AUDIO_TIMEOUT_MS; if (context->time_audio_data_sent > 0){ update_period_ms = now - context->time_audio_data_sent; } @@ -290,40 +209,102 @@ static void avdtp_fill_audio_buffer_timeout_handler(btstack_timer_source_t * tim } } -static void a2dp_fill_audio_buffer_timer_start(a2dp_media_sending_context_t * context){ +static void a2dp_demo_timer_start(a2dp_media_sending_context_t * context){ context->max_media_payload_size = a2dp_max_media_payload_size(context->local_seid); context->sbc_storage_count = 0; context->sbc_ready_to_send = 0; context->streaming = 1; - btstack_run_loop_remove_timer(&context->fill_audio_buffer_timer); - btstack_run_loop_set_timer_handler(&context->fill_audio_buffer_timer, avdtp_fill_audio_buffer_timeout_handler); - btstack_run_loop_set_timer_context(&context->fill_audio_buffer_timer, context); - btstack_run_loop_set_timer(&context->fill_audio_buffer_timer, FILL_AUDIO_BUFFER_TIMEOUT_MS); - btstack_run_loop_add_timer(&context->fill_audio_buffer_timer); + btstack_run_loop_remove_timer(&context->audio_timer); + btstack_run_loop_set_timer_handler(&context->audio_timer, avdtp_audio_timeout_handler); + btstack_run_loop_set_timer_context(&context->audio_timer, context); + btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS); + btstack_run_loop_add_timer(&context->audio_timer); } -static void a2dp_fill_audio_buffer_timer_stop(a2dp_media_sending_context_t * context){ +static void a2dp_demo_timer_stop(a2dp_media_sending_context_t * context){ context->time_audio_data_sent = 0; context->acc_num_missed_samples = 0; context->samples_ready = 0; context->streaming = 1; context->sbc_storage_count = 0; context->sbc_ready_to_send = 0; - btstack_run_loop_remove_timer(&context->fill_audio_buffer_timer); + btstack_run_loop_remove_timer(&context->audio_timer); } -static void a2dp_fill_audio_buffer_timer_pause(a2dp_media_sending_context_t * context){ - // context->time_audio_data_sent = 0; - btstack_run_loop_remove_timer(&context->fill_audio_buffer_timer); +static void a2dp_demo_timer_pause(a2dp_media_sending_context_t * context){ + btstack_run_loop_remove_timer(&context->audio_timer); } + +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + UNUSED(channel); + UNUSED(size); + uint8_t status; + uint8_t local_seid; + + switch (packet_type) { + + case HCI_EVENT_PACKET: + switch (hci_event_packet_get_type(packet)) { + case HCI_EVENT_A2DP_META: + switch (packet[2]){ + case A2DP_SUBEVENT_STREAM_ESTABLISHED: + status = a2dp_subevent_stream_established_get_status(packet); + if (status){ + printf("Stream establishment failed: status 0x%02x.\n", status); + break; + } + local_seid = a2dp_subevent_stream_established_get_local_seid(packet); + if (local_seid != media_tracker.local_seid){ + printf("Stream establishment failed: wrong local seid %d, expected %d.\n", local_seid, media_tracker.local_seid); + break; + } + + media_tracker.a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet); + printf("Stream established: a2dp cid 0x%02x, local seid %d, remote seid %d.\n", + media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet)); + break; + + case A2DP_SUBEVENT_STREAM_STARTED: + a2dp_demo_timer_start(&media_tracker); + printf("Stream started.\n"); + break; + + case A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW: + a2dp_demo_send_media_packet(); + break; + + case A2DP_SUBEVENT_STREAM_SUSPENDED: + printf("Stream paused.\n"); + a2dp_demo_timer_pause(&media_tracker); + break; + + case A2DP_SUBEVENT_STREAM_RELEASED: + printf("Stream released.\n"); + a2dp_demo_timer_stop(&media_tracker); + break; + default: + printf("AVDTP Source demo: event 0x%02x is not implemented\n", packet[2]); + break; + } + break; + default: + break; + } + break; + default: + // other packet type + break; + } +} + #ifdef HAVE_BTSTACK_STDIN static void show_usage(void){ bd_addr_t iut_address; gap_local_bd_addr(iut_address); - printf("\n--- Bluetooth AVDTP SOURCE Test Console %s ---\n", bd_addr_to_str(iut_address)); - printf("c - create connection to addr %s\n", bd_addr_to_str(remote)); + printf("\n--- Bluetooth A2DP Source Test Console %s ---\n", bd_addr_to_str(iut_address)); + printf("c - create connection to addr %s\n", device_addr_string); printf("x - start streaming sine\n"); if (hxcmod_initialized){ printf("z - start streaming '%s'\n", mod_name); @@ -337,8 +318,8 @@ static void show_usage(void){ static void stdin_process(char cmd){ switch (cmd){ case 'c': - printf("Creating L2CAP Connection to %s, PSM_AVDTP\n", bd_addr_to_str(remote)); - a2dp_source_establish_stream(remote, local_seid, &media_tracker.a2dp_cid); + printf("Creating L2CAP Connection to %s, PSM_AVDTP\n", device_addr_string); + a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid); break; case 'x': printf("Playing sine.\n"); @@ -371,22 +352,18 @@ int btstack_main(int argc, const char * argv[]){ UNUSED(argc); (void)argv; - /* Register for HCI events */ - hci_event_callback_registration.callback = &packet_handler; - hci_add_event_handler(&hci_event_callback_registration); - l2cap_init(); // Initialize AVDTP Source a2dp_source_init(); a2dp_source_register_packet_handler(&packet_handler); - local_seid = a2dp_source_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)); + media_tracker.local_seid = a2dp_source_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)); // Initialize SDP sdp_init(); - memset(sdp_avdtp_source_service_buffer, 0, sizeof(sdp_avdtp_source_service_buffer)); - a2dp_source_create_sdp_record(sdp_avdtp_source_service_buffer, 0x10002, 1, NULL, NULL); - sdp_register_service(sdp_avdtp_source_service_buffer); + memset(sdp_a2dp_source_service_buffer, 0, sizeof(sdp_a2dp_source_service_buffer)); + a2dp_source_create_sdp_record(sdp_a2dp_source_service_buffer, 0x10002, 1, NULL, NULL); + sdp_register_service(sdp_a2dp_source_service_buffer); gap_set_local_name(device_name); gap_discoverable_control(1); @@ -399,11 +376,12 @@ int btstack_main(int argc, const char * argv[]){ printf("loaded mod '%s', size %u\n", mod_name, mod_len); } - // turn on! - hci_power_control(HCI_POWER_ON); - #ifdef HAVE_BTSTACK_STDIN + // parse human readable Bluetooth address + sscanf_bd_addr(device_addr_string, device_addr); btstack_stdin_setup(stdin_process); #endif + // turn on! + hci_power_control(HCI_POWER_ON); return 0; } diff --git a/example/hfp_hf_demo.c b/example/hfp_hf_demo.c index 923e369d7..9f23d43c7 100644 --- a/example/hfp_hf_demo.c +++ b/example/hfp_hf_demo.c @@ -62,10 +62,6 @@ #include "sco_demo_util.h" -#ifdef HAVE_BTSTACK_STDIN -#include "btstack_stdin.h" -#endif - uint8_t hfp_service_buffer[150]; const uint8_t rfcomm_channel_nr = 1; const char hfp_hf_service_name[] = "BTstack HFP HF Demo"; diff --git a/src/classic/a2dp_source.c b/src/classic/a2dp_source.c index fd369b67e..101b8f985 100644 --- a/src/classic/a2dp_source.c +++ b/src/classic/a2dp_source.c @@ -459,10 +459,6 @@ uint8_t a2dp_source_start_stream(uint16_t avdtp_cid, uint8_t local_seid){ return avdtp_start_stream(avdtp_cid, local_seid, &a2dp_source_context); } -uint8_t a2dp_source_release_stream(uint16_t avdtp_cid, uint8_t local_seid){ - return avdtp_stop_stream(avdtp_cid, local_seid, &a2dp_source_context); -} - uint8_t a2dp_source_pause_stream(uint16_t avdtp_cid, uint8_t local_seid){ return avdtp_suspend_stream(avdtp_cid, local_seid, &a2dp_source_context); } @@ -477,7 +473,6 @@ uint8_t a2dp_source_stream_endpoint_ready(uint16_t avdtp_cid, uint8_t local_seid return (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING); } - static void a2dp_source_setup_media_header(uint8_t * media_packet, int size, int *offset, uint8_t marker, uint16_t sequence_number){ if (size < AVDTP_MEDIA_PAYLOAD_HEADER_SIZE){ log_error("small outgoing buffer"); diff --git a/src/classic/a2dp_source.h b/src/classic/a2dp_source.h index 6ab56fadd..3e81bc6c7 100644 --- a/src/classic/a2dp_source.h +++ b/src/classic/a2dp_source.h @@ -95,13 +95,6 @@ uint8_t a2dp_source_start_stream(uint16_t avdtp_cid, uint8_t local_seid); */ uint8_t a2dp_source_pause_stream(uint16_t avdtp_cid, uint8_t local_seid); -/** - * @brief Close stream - * @param avdtp_cid - * @param seid - */ -uint8_t a2dp_source_release_stream(uint16_t avdtp_cid, uint8_t local_seid); - /** * @brief Disconnect from device with cid. * @param avdtp_cid