1 /* 2 * Copyright (C) 2016 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "a2dp_source_demo.c" 39 40 /* 41 * a2dp_source_demo.c 42 */ 43 44 // ***************************************************************************** 45 /* EXAMPLE_START(a2dp_source_demo): Serve audio stream and handle remote playback control and queries. 46 * 47 * @text This A2DP Source example demonstrates how to send an audio data stream 48 * to a remote A2DP Sink device and how to switch between two audio data sources. 49 * In addition, the AVRCP Target is used to answer queries on currently played media, 50 * as well as to handle remote playback control, i.e. play, stop, repeat, etc. 51 * 52 * @test To test with a remote device, e.g. a Bluetooth speaker, 53 * set the device_addr_string to the Bluetooth address of your 54 * remote device in the code, and use the UI to connect and start playback. 55 * Tap SPACE on the console to show the available commands. 56 */ 57 // ***************************************************************************** 58 59 60 #include <stdint.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 65 #include "btstack.h" 66 #include "hxcmod.h" 67 #include "mods/mod.h" 68 69 // logarithmic volume reduction, samples are divided by 2^x 70 // #define VOLUME_REDUCTION 3 71 // #undef HAVE_BTSTACK_STDIN 72 73 //#define AVRCP_BROWSING_ENABLED 74 75 #define NUM_CHANNELS 2 76 #define BYTES_PER_AUDIO_SAMPLE (2*NUM_CHANNELS) 77 #define AUDIO_TIMEOUT_MS 10 78 #define TABLE_SIZE_441HZ 100 79 80 #define SBC_STORAGE_SIZE 1030 81 82 typedef enum { 83 STREAM_SINE = 0, 84 STREAM_MOD, 85 STREAM_PTS_TEST 86 } stream_data_source_t; 87 88 typedef struct { 89 uint16_t a2dp_cid; 90 uint8_t local_seid; 91 uint8_t stream_opened; 92 uint16_t avrcp_cid; 93 94 uint32_t time_audio_data_sent; // ms 95 uint32_t acc_num_missed_samples; 96 uint32_t samples_ready; 97 btstack_timer_source_t audio_timer; 98 uint8_t streaming; 99 int max_media_payload_size; 100 101 uint8_t sbc_storage[SBC_STORAGE_SIZE]; 102 uint16_t sbc_storage_count; 103 uint8_t sbc_ready_to_send; 104 } a2dp_media_sending_context_t; 105 106 static uint8_t media_sbc_codec_capabilities[] = { 107 (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO, 108 0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS, 109 2, 53 110 }; 111 112 // input signal: pre-computed int16 sine wave, 44100 Hz at 441 Hz 113 static const int16_t sine_int16_44100[] = { 114 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 115 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 116 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 117 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 118 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 119 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 120 -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 121 -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 122 -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 123 -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 124 }; 125 126 static const int num_samples_sine_int16_44100 = sizeof(sine_int16_44100) / 2; 127 128 // input signal: pre-computed int16 sine wave, 48000 Hz at 441 Hz 129 static const int16_t sine_int16_48000[] = { 130 0, 1905, 3804, 5690, 7557, 9398, 11207, 12978, 14706, 16383, 131 18006, 19567, 21062, 22486, 23834, 25101, 26283, 27376, 28377, 29282, 132 30087, 30791, 31390, 31884, 32269, 32545, 32712, 32767, 32712, 32545, 133 32269, 31884, 31390, 30791, 30087, 29282, 28377, 27376, 26283, 25101, 134 23834, 22486, 21062, 19567, 18006, 16383, 14706, 12978, 11207, 9398, 135 7557, 5690, 3804, 1905, 0, -1905, -3804, -5690, -7557, -9398, 136 -11207, -12978, -14706, -16384, -18006, -19567, -21062, -22486, -23834, -25101, 137 -26283, -27376, -28377, -29282, -30087, -30791, -31390, -31884, -32269, -32545, 138 -32712, -32767, -32712, -32545, -32269, -31884, -31390, -30791, -30087, -29282, 139 -28377, -27376, -26283, -25101, -23834, -22486, -21062, -19567, -18006, -16384, 140 -14706, -12978, -11207, -9398, -7557, -5690, -3804, -1905, }; 141 142 static const int num_samples_sine_int16_48000 = sizeof(sine_int16_48000) / 2; 143 144 typedef struct { 145 int reconfigure; 146 int num_channels; 147 int sampling_frequency; 148 int channel_mode; 149 int block_length; 150 int subbands; 151 int allocation_method; 152 int min_bitpool_value; 153 int max_bitpool_value; 154 int frames_per_buffer; 155 } avdtp_media_codec_configuration_sbc_t; 156 157 static btstack_packet_callback_registration_t hci_event_callback_registration; 158 159 // pts: static const char * device_addr_string = "00:1B:DC:08:0A:A5"; 160 // pts: static const char * device_addr_string = "00:1B:DC:08:E2:72"; 161 // mac 2013: static const char * device_addr_string = "84:38:35:65:d1:15"; 162 // phone 2013: static const char * device_addr_string = "D8:BB:2C:DF:F0:F2"; 163 // Minijambox: 164 static const char * device_addr_string = "00:21:3C:AC:F7:38"; 165 // Philips SHB9100: static const char * device_addr_string = "00:22:37:05:FD:E8"; 166 // RT-B6: static const char * device_addr_string = "00:75:58:FF:C9:7D"; 167 // BT dongle: static const char * device_addr_string = "00:1A:7D:DA:71:0A"; 168 // Sony MDR-ZX330BT static const char * device_addr_string = "00:18:09:28:50:18"; 169 // Panda (BM6) static const char * device_addr_string = "4F:3F:66:52:8B:E0"; 170 171 static bd_addr_t device_addr; 172 static uint8_t sdp_a2dp_source_service_buffer[150]; 173 static uint8_t sdp_avrcp_target_service_buffer[200]; 174 static uint8_t sdp_avrcp_controller_service_buffer[200]; 175 176 static avdtp_media_codec_configuration_sbc_t sbc_configuration; 177 static btstack_sbc_encoder_state_t sbc_encoder_state; 178 179 static uint8_t media_sbc_codec_configuration[4]; 180 static a2dp_media_sending_context_t media_tracker; 181 182 static stream_data_source_t data_source; 183 184 static int sine_phase; 185 static int sample_rate = 44100; 186 187 static int hxcmod_initialized; 188 static modcontext mod_context; 189 static tracker_buffer_state trkbuf; 190 191 static uint16_t avrcp_controller_cid = 0; 192 193 /* AVRCP Target context START */ 194 static const uint8_t subunit_info[] = { 195 0,0,0,0, 196 1,1,1,1, 197 2,2,2,2, 198 3,3,3,3, 199 4,4,4,4, 200 5,5,5,5, 201 6,6,6,6, 202 7,7,7,7 203 }; 204 205 static uint32_t company_id = 0x112233; 206 static uint8_t companies_num = 1; 207 static uint8_t companies[] = { 208 0x00, 0x19, 0x58 //BT SIG registered CompanyID 209 }; 210 211 static uint8_t events_num = 13; 212 static uint8_t events[] = { 213 AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED, 214 AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED, 215 AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_END, 216 AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_START, 217 AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED, 218 AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED, 219 AVRCP_NOTIFICATION_EVENT_SYSTEM_STATUS_CHANGED, 220 AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED, 221 AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED, 222 AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED, 223 AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED, 224 AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED, 225 AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED 226 }; 227 228 typedef struct { 229 uint8_t track_id[8]; 230 uint32_t song_length_ms; 231 avrcp_playback_status_t status; 232 uint32_t song_position_ms; // 0xFFFFFFFF if not supported 233 } avrcp_play_status_info_t; 234 235 // python -c "print('a'*512)" 236 static const char title[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 237 238 avrcp_track_t tracks[] = { 239 {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 1, "Sine", "Generated", "A2DP Source Demo", "monotone", 12345}, 240 {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, 2, "Nao-deceased", "Decease", "A2DP Source Demo", "vivid", 12345}, 241 {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, 3, (char *)title, "Decease", "A2DP Source Demo", "vivid", 12345}, 242 }; 243 int current_track_index; 244 avrcp_play_status_info_t play_info; 245 246 /* AVRCP Target context END */ 247 248 /* @section Main Application Setup 249 * 250 * @text The Listing MainConfiguration shows how to setup AD2P Source and AVRCP Target services. 251 */ 252 253 /* LISTING_START(MainConfiguration): Setup Audio Source and AVRCP Target services */ 254 static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size); 255 static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 256 static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 257 #ifdef HAVE_BTSTACK_STDIN 258 static void stdin_process(char cmd); 259 #endif 260 261 static void a2dp_demo_reconfigure_sample_rate(int new_sample_rate){ 262 if (!hxcmod_initialized){ 263 hxcmod_initialized = hxcmod_init(&mod_context); 264 if (!hxcmod_initialized) { 265 printf("could not initialize hxcmod\n"); 266 return; 267 } 268 } 269 sample_rate = new_sample_rate; 270 media_tracker.sbc_storage_count = 0; 271 media_tracker.samples_ready = 0; 272 hxcmod_unload(&mod_context); 273 hxcmod_setcfg(&mod_context, sample_rate, 16, 1, 1, 1); 274 hxcmod_load(&mod_context, (void *) &mod_data, mod_len); 275 } 276 277 static int a2dp_source_and_avrcp_services_init(void){ 278 279 l2cap_init(); 280 // Initialize A2DP Source. 281 a2dp_source_init(); 282 a2dp_source_register_packet_handler(&a2dp_source_packet_handler); 283 284 // Create stream endpoint. 285 avdtp_stream_endpoint_t * local_stream_endpoint = 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)); 286 if (!local_stream_endpoint){ 287 printf("A2DP Source: not enough memory to create local stream endpoint\n"); 288 return 1; 289 } 290 media_tracker.local_seid = avdtp_local_seid(local_stream_endpoint); 291 avdtp_source_register_delay_reporting_category(media_tracker.local_seid); 292 293 // Initialize AVRCP Target. 294 avrcp_target_init(); 295 avrcp_target_register_packet_handler(&avrcp_target_packet_handler); 296 // Initialize AVRCP Controller 297 avrcp_controller_init(); 298 avrcp_controller_register_packet_handler(&avrcp_controller_packet_handler); 299 300 // Initialize SDP, 301 sdp_init(); 302 303 // Create A2DP Source service record and register it with SDP. 304 memset(sdp_a2dp_source_service_buffer, 0, sizeof(sdp_a2dp_source_service_buffer)); 305 a2dp_source_create_sdp_record(sdp_a2dp_source_service_buffer, 0x10002, 1, NULL, NULL); 306 sdp_register_service(sdp_a2dp_source_service_buffer); 307 308 // Create AVRCP target service record and register it with SDP. 309 memset(sdp_avrcp_target_service_buffer, 0, sizeof(sdp_avrcp_target_service_buffer)); 310 uint16_t supported_features = (1 << AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_PLAYER_OR_RECORDER); 311 #ifdef AVRCP_BROWSING_ENABLED 312 supported_features |= (1 << AVRCP_TARGET_SUPPORTED_FEATURE_BROWSING); 313 #endif 314 avrcp_target_create_sdp_record(sdp_avrcp_target_service_buffer, 0x10001, supported_features, NULL, NULL); 315 sdp_register_service(sdp_avrcp_target_service_buffer); 316 317 // setup AVRCP Controller 318 memset(sdp_avrcp_controller_service_buffer, 0, sizeof(sdp_avrcp_controller_service_buffer)); 319 uint16_t controller_supported_features = (1 << AVRCP_CONTROLLER_SUPPORTED_FEATURE_CATEGORY_MONITOR_OR_AMPLIFIER); 320 avrcp_controller_create_sdp_record(sdp_avrcp_controller_service_buffer, 0x10002, controller_supported_features, NULL, NULL); 321 sdp_register_service(sdp_avrcp_controller_service_buffer); 322 323 // Set local name with a template Bluetooth address, that will be automatically 324 // replaced with a actual address once it is available, i.e. when BTstack boots 325 // up and starts talking to a Bluetooth module. 326 gap_set_local_name("A2DP Source 00:00:00:00:00:00"); 327 gap_discoverable_control(1); 328 gap_set_class_of_device(0x200408); 329 330 // Register for HCI events. 331 hci_event_callback_registration.callback = &a2dp_source_packet_handler; 332 hci_add_event_handler(&hci_event_callback_registration); 333 334 a2dp_demo_reconfigure_sample_rate(sample_rate); 335 336 // Parse human readable Bluetooth address. 337 sscanf_bd_addr(device_addr_string, device_addr); 338 339 #ifdef HAVE_BTSTACK_STDIN 340 btstack_stdin_setup(stdin_process); 341 #endif 342 return 0; 343 } 344 /* LISTING_END */ 345 346 static void a2dp_demo_send_media_packet(void){ 347 int num_bytes_in_frame = btstack_sbc_encoder_sbc_buffer_length(); 348 int bytes_in_storage = media_tracker.sbc_storage_count; 349 uint8_t num_frames = bytes_in_storage / num_bytes_in_frame; 350 a2dp_source_stream_send_media_payload(media_tracker.a2dp_cid, media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0); 351 media_tracker.sbc_storage_count = 0; 352 media_tracker.sbc_ready_to_send = 0; 353 } 354 355 static void produce_sine_audio(int16_t * pcm_buffer, int num_samples_to_write){ 356 int count; 357 for (count = 0; count < num_samples_to_write ; count++){ 358 switch (sample_rate){ 359 case 44100: 360 pcm_buffer[count * 2] = sine_int16_44100[sine_phase]; 361 pcm_buffer[count * 2 + 1] = sine_int16_44100[sine_phase]; 362 sine_phase++; 363 if (sine_phase >= num_samples_sine_int16_44100){ 364 sine_phase -= num_samples_sine_int16_44100; 365 } 366 break; 367 case 48000: 368 pcm_buffer[count * 2] = sine_int16_48000[sine_phase]; 369 pcm_buffer[count * 2 + 1] = sine_int16_48000[sine_phase]; 370 sine_phase++; 371 if (sine_phase >= num_samples_sine_int16_48000){ 372 sine_phase -= num_samples_sine_int16_48000; 373 } 374 break; 375 default: 376 break; 377 } 378 379 380 } 381 } 382 383 static void produce_mod_audio(int16_t * pcm_buffer, int num_samples_to_write){ 384 hxcmod_fillbuffer(&mod_context, (unsigned short *) &pcm_buffer[0], num_samples_to_write, &trkbuf); 385 } 386 387 static void produce_audio(int16_t * pcm_buffer, int num_samples){ 388 switch (data_source){ 389 case STREAM_SINE: 390 produce_sine_audio(pcm_buffer, num_samples); 391 break; 392 case STREAM_MOD: 393 produce_mod_audio(pcm_buffer, num_samples); 394 break; 395 default: 396 break; 397 } 398 #ifdef VOLUME_REDUCTION 399 int i; 400 for (i=0;i<num_samples*2;i++){ 401 if (pcm_buffer[i] > 0){ 402 pcm_buffer[i] = pcm_buffer[i] >> VOLUME_REDUCTION; 403 } else { 404 pcm_buffer[i] = -((-pcm_buffer[i]) >> VOLUME_REDUCTION); 405 } 406 } 407 #endif 408 } 409 410 static int a2dp_demo_fill_sbc_audio_buffer(a2dp_media_sending_context_t * context){ 411 // perform sbc encodin 412 int total_num_bytes_read = 0; 413 unsigned int num_audio_samples_per_sbc_buffer = btstack_sbc_encoder_num_audio_frames(); 414 while (context->samples_ready >= num_audio_samples_per_sbc_buffer 415 && (context->max_media_payload_size - context->sbc_storage_count) >= btstack_sbc_encoder_sbc_buffer_length()){ 416 417 int16_t pcm_frame[256*NUM_CHANNELS]; 418 419 produce_audio(pcm_frame, num_audio_samples_per_sbc_buffer); 420 btstack_sbc_encoder_process_data(pcm_frame); 421 422 uint16_t sbc_frame_size = btstack_sbc_encoder_sbc_buffer_length(); 423 uint8_t * sbc_frame = btstack_sbc_encoder_sbc_buffer(); 424 425 total_num_bytes_read += num_audio_samples_per_sbc_buffer; 426 memcpy(&context->sbc_storage[context->sbc_storage_count], sbc_frame, sbc_frame_size); 427 context->sbc_storage_count += sbc_frame_size; 428 context->samples_ready -= num_audio_samples_per_sbc_buffer; 429 } 430 return total_num_bytes_read; 431 } 432 433 static void a2dp_demo_audio_timeout_handler(btstack_timer_source_t * timer){ 434 a2dp_media_sending_context_t * context = (a2dp_media_sending_context_t *) btstack_run_loop_get_timer_context(timer); 435 btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS); 436 btstack_run_loop_add_timer(&context->audio_timer); 437 uint32_t now = btstack_run_loop_get_time_ms(); 438 439 uint32_t update_period_ms = AUDIO_TIMEOUT_MS; 440 if (context->time_audio_data_sent > 0){ 441 update_period_ms = now - context->time_audio_data_sent; 442 } 443 444 uint32_t num_samples = (update_period_ms * sample_rate) / 1000; 445 context->acc_num_missed_samples += (update_period_ms * sample_rate) % 1000; 446 447 while (context->acc_num_missed_samples >= 1000){ 448 num_samples++; 449 context->acc_num_missed_samples -= 1000; 450 } 451 context->time_audio_data_sent = now; 452 context->samples_ready += num_samples; 453 454 if (context->sbc_ready_to_send) return; 455 456 a2dp_demo_fill_sbc_audio_buffer(context); 457 458 if ((context->sbc_storage_count + btstack_sbc_encoder_sbc_buffer_length()) > context->max_media_payload_size){ 459 // schedule sending 460 context->sbc_ready_to_send = 1; 461 a2dp_source_stream_endpoint_request_can_send_now(context->a2dp_cid, context->local_seid); 462 } 463 } 464 465 static void a2dp_demo_timer_start(a2dp_media_sending_context_t * context){ 466 context->max_media_payload_size = btstack_min(a2dp_max_media_payload_size(context->a2dp_cid, context->local_seid), SBC_STORAGE_SIZE); 467 context->sbc_storage_count = 0; 468 context->sbc_ready_to_send = 0; 469 context->streaming = 1; 470 btstack_run_loop_remove_timer(&context->audio_timer); 471 btstack_run_loop_set_timer_handler(&context->audio_timer, a2dp_demo_audio_timeout_handler); 472 btstack_run_loop_set_timer_context(&context->audio_timer, context); 473 btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS); 474 btstack_run_loop_add_timer(&context->audio_timer); 475 } 476 477 static void a2dp_demo_timer_stop(a2dp_media_sending_context_t * context){ 478 context->time_audio_data_sent = 0; 479 context->acc_num_missed_samples = 0; 480 context->samples_ready = 0; 481 context->streaming = 1; 482 context->sbc_storage_count = 0; 483 context->sbc_ready_to_send = 0; 484 btstack_run_loop_remove_timer(&context->audio_timer); 485 } 486 487 static void dump_sbc_configuration(avdtp_media_codec_configuration_sbc_t * configuration){ 488 printf("Received media codec configuration:\n"); 489 printf(" - num_channels: %d\n", configuration->num_channels); 490 printf(" - sampling_frequency: %d\n", configuration->sampling_frequency); 491 printf(" - channel_mode: %d\n", configuration->channel_mode); 492 printf(" - block_length: %d\n", configuration->block_length); 493 printf(" - subbands: %d\n", configuration->subbands); 494 printf(" - allocation_method: %d\n", configuration->allocation_method); 495 printf(" - bitpool_value [%d, %d] \n", configuration->min_bitpool_value, configuration->max_bitpool_value); 496 } 497 498 static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 499 UNUSED(channel); 500 UNUSED(size); 501 uint8_t status; 502 uint8_t local_seid; 503 bd_addr_t address; 504 uint16_t cid; 505 506 if (packet_type != HCI_EVENT_PACKET) return; 507 508 #ifndef HAVE_BTSTACK_STDIN 509 if (hci_event_packet_get_type(packet) == BTSTACK_EVENT_STATE){ 510 if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; 511 printf("Create A2DP Source connection to addr %s.\n", bd_addr_to_str(device_addr)); 512 status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid); 513 if (status != ERROR_CODE_SUCCESS){ 514 printf("Could not perform command, status 0x%2x\n", status); 515 } 516 return; 517 } 518 #endif 519 if (hci_event_packet_get_type(packet) == HCI_EVENT_PIN_CODE_REQUEST) { 520 printf("Pin code request - using '0000'\n"); 521 hci_event_pin_code_request_get_bd_addr(packet, address); 522 gap_pin_code_response(address, "0000"); 523 return; 524 } 525 526 if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return; 527 528 switch (hci_event_a2dp_meta_get_subevent_code(packet)){ 529 case A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED: 530 a2dp_subevent_signaling_connection_established_get_bd_addr(packet, address); 531 cid = a2dp_subevent_signaling_connection_established_get_a2dp_cid(packet); 532 status = a2dp_subevent_signaling_connection_established_get_status(packet); 533 534 if (status != ERROR_CODE_SUCCESS){ 535 printf("A2DP Source: Connection failed, status 0x%02x, cid 0x%02x, a2dp_cid 0x%02x \n", status, cid, media_tracker.a2dp_cid); 536 media_tracker.a2dp_cid = 0; 537 break; 538 } 539 media_tracker.a2dp_cid = cid; 540 printf("A2DP Source: Connected to address %s, a2dp cid 0x%02x.\n", bd_addr_to_str(address), media_tracker.a2dp_cid); 541 break; 542 543 case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{ 544 cid = avdtp_subevent_signaling_media_codec_sbc_configuration_get_avdtp_cid(packet); 545 if (cid != media_tracker.a2dp_cid) return; 546 547 sbc_configuration.reconfigure = a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet); 548 sbc_configuration.num_channels = a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet); 549 sbc_configuration.sampling_frequency = a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet); 550 sbc_configuration.channel_mode = a2dp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet); 551 sbc_configuration.block_length = a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet); 552 sbc_configuration.subbands = a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet); 553 sbc_configuration.allocation_method = a2dp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet); 554 sbc_configuration.min_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet); 555 sbc_configuration.max_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet); 556 sbc_configuration.frames_per_buffer = sbc_configuration.subbands * sbc_configuration.block_length; 557 printf("A2DP Source: Received SBC codec configuration, sampling frequency %u.\n", sbc_configuration.sampling_frequency); 558 559 // Adapt Bluetooth spec definition to SBC Encoder expected input 560 sbc_configuration.allocation_method -= 1; 561 sbc_configuration.num_channels = 2; 562 switch (sbc_configuration.channel_mode){ 563 case AVDTP_SBC_JOINT_STEREO: 564 sbc_configuration.channel_mode = 3; 565 break; 566 case AVDTP_SBC_STEREO: 567 sbc_configuration.channel_mode = 2; 568 break; 569 case AVDTP_SBC_DUAL_CHANNEL: 570 sbc_configuration.channel_mode = 1; 571 break; 572 case AVDTP_SBC_MONO: 573 sbc_configuration.channel_mode = 0; 574 sbc_configuration.num_channels = 1; 575 break; 576 } 577 dump_sbc_configuration(&sbc_configuration); 578 579 btstack_sbc_encoder_init(&sbc_encoder_state, SBC_MODE_STANDARD, 580 sbc_configuration.block_length, sbc_configuration.subbands, 581 sbc_configuration.allocation_method, sbc_configuration.sampling_frequency, 582 sbc_configuration.max_bitpool_value, 583 sbc_configuration.channel_mode); 584 break; 585 } 586 587 case A2DP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY: 588 printf("A2DP Source: remote supports delay report\n"); 589 break; 590 case A2DP_SUBEVENT_SIGNALING_CAPABILITIES_DONE: 591 printf("A2DP Source: All capabilities reported\n"); 592 break; 593 594 case A2DP_SUBEVENT_SIGNALING_DELAY_REPORT: 595 printf("A2DP Source: Received delay report of %d.%0d ms, local seid %d\n", 596 avdtp_subevent_signaling_delay_report_get_delay_100us(packet)/10, avdtp_subevent_signaling_delay_report_get_delay_100us(packet)%10, 597 avdtp_subevent_signaling_delay_report_get_local_seid(packet)); 598 break; 599 600 case A2DP_SUBEVENT_STREAM_ESTABLISHED: 601 a2dp_subevent_stream_established_get_bd_addr(packet, address); 602 status = a2dp_subevent_stream_established_get_status(packet); 603 if (status){ 604 printf("A2DP Source: Stream failed, status 0x%02x.\n", status); 605 break; 606 } 607 local_seid = a2dp_subevent_stream_established_get_local_seid(packet); 608 if (local_seid != media_tracker.local_seid){ 609 printf("A2DP Source: Stream failed, wrong local seid %d, expected %d.\n", local_seid, media_tracker.local_seid); 610 break; 611 } 612 printf("A2DP Source: Stream established, address %s, a2dp cid 0x%02x, local seid %d, remote seid %d.\n", bd_addr_to_str(address), 613 media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet)); 614 media_tracker.stream_opened = 1; 615 data_source = STREAM_MOD; 616 status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 617 break; 618 619 case A2DP_SUBEVENT_STREAM_RECONFIGURED: 620 status = a2dp_subevent_stream_reconfigured_get_status(packet); 621 printf("A2DP Source: Reconfigured, status 0x%02x\n", status); 622 break; 623 624 case A2DP_SUBEVENT_STREAM_STARTED: 625 play_info.status = AVRCP_PLAYBACK_STATUS_PLAYING; 626 if (media_tracker.avrcp_cid){ 627 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t)); 628 avrcp_target_set_playback_status(media_tracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_PLAYING); 629 } 630 a2dp_demo_timer_start(&media_tracker); 631 printf("A2DP Source: Stream started.\n"); 632 break; 633 634 case A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW: 635 a2dp_demo_send_media_packet(); 636 break; 637 638 case A2DP_SUBEVENT_STREAM_SUSPENDED: 639 play_info.status = AVRCP_PLAYBACK_STATUS_PAUSED; 640 if (media_tracker.avrcp_cid){ 641 avrcp_target_set_playback_status(media_tracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_PAUSED); 642 } 643 printf("A2DP Source: Stream paused.\n"); 644 a2dp_demo_timer_stop(&media_tracker); 645 break; 646 647 case A2DP_SUBEVENT_STREAM_RELEASED: 648 play_info.status = AVRCP_PLAYBACK_STATUS_STOPPED; 649 cid = a2dp_subevent_stream_released_get_a2dp_cid(packet); 650 if (cid == media_tracker.a2dp_cid) { 651 media_tracker.stream_opened = 0; 652 printf("A2DP Source: Stream released.\n"); 653 } 654 if (media_tracker.avrcp_cid){ 655 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t)); 656 avrcp_target_set_playback_status(media_tracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_STOPPED); 657 } 658 a2dp_demo_timer_stop(&media_tracker); 659 break; 660 case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED: 661 cid = a2dp_subevent_signaling_connection_released_get_a2dp_cid(packet); 662 if (cid == media_tracker.a2dp_cid) { 663 media_tracker.avrcp_cid = 0; 664 media_tracker.a2dp_cid = 0; 665 printf("A2DP Source: Signaling released.\n\n"); 666 } 667 break; 668 default: 669 break; 670 } 671 } 672 673 static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 674 UNUSED(channel); 675 UNUSED(size); 676 bd_addr_t event_addr; 677 uint16_t local_cid; 678 uint8_t status = ERROR_CODE_SUCCESS; 679 680 if (packet_type != HCI_EVENT_PACKET) return; 681 if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return; 682 683 switch (packet[2]){ 684 case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: { 685 local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet); 686 // if (avrcp_cid != 0 && avrcp_cid != local_cid) { 687 // printf("AVRCP Target: Connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", avrcp_cid, local_cid); 688 // return; 689 // } 690 // if (avrcp_cid != local_cid) break; 691 692 status = avrcp_subevent_connection_established_get_status(packet); 693 if (status != ERROR_CODE_SUCCESS){ 694 printf("AVRCP Target: Connection failed, status 0x%02x\n", status); 695 return; 696 } 697 media_tracker.avrcp_cid = local_cid; 698 avrcp_subevent_connection_established_get_bd_addr(packet, event_addr); 699 printf("AVRCP Target: Connected to %s, avrcp_cid 0x%02x\n", bd_addr_to_str(event_addr), local_cid); 700 701 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t)); 702 avrcp_target_set_unit_info(media_tracker.avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, company_id); 703 avrcp_target_set_subunit_info(media_tracker.avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, (uint8_t *)subunit_info, sizeof(subunit_info)); 704 return; 705 } 706 case AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED: 707 printf("AVRCP Target: new volume %d\n", avrcp_subevent_notification_volume_changed_get_absolute_volume(packet)); 708 break; 709 case AVRCP_SUBEVENT_EVENT_IDS_QUERY: 710 status = avrcp_target_supported_events(media_tracker.avrcp_cid, events_num, events, sizeof(events)); 711 break; 712 case AVRCP_SUBEVENT_COMPANY_IDS_QUERY: 713 status = avrcp_target_supported_companies(media_tracker.avrcp_cid, companies_num, companies, sizeof(companies)); 714 break; 715 case AVRCP_SUBEVENT_PLAY_STATUS_QUERY: 716 status = avrcp_target_play_status(media_tracker.avrcp_cid, play_info.song_length_ms, play_info.song_position_ms, play_info.status); 717 break; 718 // case AVRCP_SUBEVENT_NOW_PLAYING_INFO_QUERY: 719 // status = avrcp_target_now_playing_info(avrcp_cid); 720 // break; 721 case AVRCP_SUBEVENT_OPERATION:{ 722 avrcp_operation_id_t operation_id = avrcp_subevent_operation_get_operation_id(packet); 723 switch (operation_id){ 724 case AVRCP_OPERATION_ID_PLAY: 725 printf("AVRCP Target: PLAY\n"); 726 status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 727 break; 728 case AVRCP_OPERATION_ID_PAUSE: 729 printf("AVRCP Target: PAUSE\n"); 730 status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 731 break; 732 case AVRCP_OPERATION_ID_STOP: 733 printf("AVRCP Target: STOP\n"); 734 status = a2dp_source_disconnect(media_tracker.a2dp_cid); 735 break; 736 default: 737 printf("AVRCP Target: operation 0x%2x is not handled\n", operation_id); 738 return; 739 } 740 break; 741 } 742 case AVRCP_SUBEVENT_CONNECTION_RELEASED: 743 printf("AVRCP Target: Disconnected, avrcp_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet)); 744 media_tracker.avrcp_cid = 0; 745 return; 746 default: 747 break; 748 } 749 750 if (status != ERROR_CODE_SUCCESS){ 751 printf("Responding to event 0x%02x failed with status 0x%02x\n", packet[2], status); 752 } 753 } 754 755 static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 756 UNUSED(channel); 757 UNUSED(size); 758 uint16_t local_cid; 759 uint8_t status = 0xFF; 760 bd_addr_t adress; 761 762 if (packet_type != HCI_EVENT_PACKET) return; 763 if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return; 764 switch (packet[2]){ 765 case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: { 766 local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet); 767 if (avrcp_controller_cid != 0 && avrcp_controller_cid != local_cid) { 768 printf("AVRCP Controller: Connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", avrcp_controller_cid, local_cid); 769 return; 770 } 771 772 status = avrcp_subevent_connection_established_get_status(packet); 773 if (status != ERROR_CODE_SUCCESS){ 774 printf("AVRCP Controller: Connection failed: status 0x%02x\n", status); 775 avrcp_controller_cid = 0; 776 return; 777 } 778 779 avrcp_controller_cid = local_cid; 780 avrcp_subevent_connection_established_get_bd_addr(packet, adress); 781 printf("AVRCP Controller: Channel successfully opened: %s, avrcp_controller_cid 0x%02x\n", bd_addr_to_str(adress), avrcp_controller_cid); 782 783 // automatically enable notifications 784 avrcp_controller_enable_notification(avrcp_controller_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED); 785 return; 786 } 787 case AVRCP_SUBEVENT_CONNECTION_RELEASED: 788 printf("AVRCP Controller: Channel released: avrcp_controller_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet)); 789 avrcp_controller_cid = 0; 790 return; 791 default: 792 break; 793 } 794 795 status = packet[5]; 796 if (!avrcp_controller_cid) return; 797 798 // ignore INTERIM status 799 if (status == AVRCP_CTYPE_RESPONSE_INTERIM) return; 800 801 switch (packet[2]){ 802 case AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED:{ 803 int volume_percentage = avrcp_subevent_notification_volume_changed_get_absolute_volume(packet) * 100 / 127; 804 printf("AVRCP Controller: notification absolute volume changed %d %%\n", volume_percentage); 805 return; 806 } 807 default: 808 break; 809 } 810 } 811 812 #ifdef HAVE_BTSTACK_STDIN 813 static void show_usage(void){ 814 bd_addr_t iut_address; 815 gap_local_bd_addr(iut_address); 816 printf("\n--- Bluetooth A2DP Source/AVRCP Target Demo %s ---\n", bd_addr_to_str(iut_address)); 817 printf("b - A2DP Source create connection to addr %s\n", device_addr_string); 818 printf("B - A2DP Source disconnect\n"); 819 printf("c - AVRCP Target create connection to addr %s\n", device_addr_string); 820 printf("C - AVRCP Target disconnect\n"); 821 822 printf("x - start streaming sine\n"); 823 if (hxcmod_initialized){ 824 printf("z - start streaming '%s'\n", mod_name); 825 } 826 printf("p - pause streaming\n"); 827 printf("w - reconfigure stream for 44100 Hz\n"); 828 printf("e - reconfigure stream for 48000 Hz\n"); 829 printf("t - volume up\n"); 830 printf("T - volume down\n"); 831 printf("v - absolute volume of 50 percent\n"); 832 833 printf("\n--- Bluetooth AVRCP Target Commands %s ---\n", bd_addr_to_str(iut_address)); 834 printf("---\n"); 835 } 836 837 static void stdin_process(char cmd){ 838 uint8_t status = ERROR_CODE_SUCCESS; 839 switch (cmd){ 840 case 'b': 841 status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid); 842 printf("%c - Create A2DP Source connection to addr %s, cid 0x%02x.\n", cmd, bd_addr_to_str(device_addr), media_tracker.a2dp_cid); 843 break; 844 case 'B': 845 printf("%c - A2DP Source Disconnect from cid 0x%2x\n", cmd, media_tracker.a2dp_cid); 846 status = a2dp_source_disconnect(media_tracker.a2dp_cid); 847 break; 848 case 'c': 849 printf("%c - Create AVRCP Target connection to addr %s.\n", cmd, bd_addr_to_str(device_addr)); 850 status = avrcp_target_connect(device_addr, &media_tracker.avrcp_cid); 851 break; 852 case 'C': 853 printf("%c - AVRCP Target disconnect\n", cmd); 854 status = avrcp_target_disconnect(media_tracker.avrcp_cid); 855 break; 856 857 case '\n': 858 case '\r': 859 break; 860 861 case 't': 862 printf(" - volume up\n"); 863 status = avrcp_controller_volume_up(avrcp_controller_cid); 864 break; 865 case 'T': 866 printf(" - volume down\n"); 867 status = avrcp_controller_volume_down(avrcp_controller_cid); 868 break; 869 case 'v': 870 printf(" - absolute volume of 50%% (64)\n"); 871 status = avrcp_controller_set_absolute_volume(avrcp_controller_cid, 64); 872 break; 873 874 case 'x': 875 if (media_tracker.avrcp_cid){ 876 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t)); 877 } 878 printf("%c - Play sine.\n", cmd); 879 data_source = STREAM_SINE; 880 if (!media_tracker.stream_opened) break; 881 status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 882 break; 883 case 'z': 884 if (media_tracker.avrcp_cid){ 885 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t)); 886 } 887 printf("%c - Play mod.\n", cmd); 888 data_source = STREAM_MOD; 889 if (!media_tracker.stream_opened) break; 890 status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 891 if (status == ERROR_CODE_SUCCESS){ 892 a2dp_demo_reconfigure_sample_rate(sample_rate); 893 } 894 break; 895 896 case 'p': 897 if (!media_tracker.stream_opened) break; 898 printf("%c - Pause stream.\n", cmd); 899 status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 900 break; 901 902 case 'w': 903 if (!media_tracker.stream_opened) break; 904 if (play_info.status == AVRCP_PLAYBACK_STATUS_PLAYING){ 905 printf("Stream cannot be reconfigured while playing, please pause stream first\n"); 906 break; 907 } 908 printf("%c - Reconfigure for %d Hz.\n", cmd, sample_rate); 909 status = a2dp_source_reconfigure_stream_sampling_frequency(media_tracker.a2dp_cid, 44100); 910 if (status == ERROR_CODE_SUCCESS){ 911 a2dp_demo_reconfigure_sample_rate(44100); 912 } 913 break; 914 915 case 'e': 916 if (!media_tracker.stream_opened) break; 917 if (play_info.status == AVRCP_PLAYBACK_STATUS_PLAYING){ 918 printf("Stream cannot be reconfigured while playing, please pause stream first\n"); 919 break; 920 } 921 printf("%c - Reconfigure for %d Hz.\n", cmd, sample_rate); 922 status = a2dp_source_reconfigure_stream_sampling_frequency(media_tracker.a2dp_cid, 48000); 923 if (status == ERROR_CODE_SUCCESS){ 924 a2dp_demo_reconfigure_sample_rate(48000); 925 } 926 break; 927 928 default: 929 show_usage(); 930 return; 931 } 932 if (status != ERROR_CODE_SUCCESS){ 933 printf("Could not perform command \'%c\', status 0x%2x\n", cmd, status); 934 } 935 } 936 #endif 937 938 939 int btstack_main(int argc, const char * argv[]); 940 int btstack_main(int argc, const char * argv[]){ 941 (void)argc; 942 (void)argv; 943 944 int err = a2dp_source_and_avrcp_services_init(); 945 if (err) return err; 946 // turn on! 947 hci_power_control(HCI_POWER_ON); 948 return 0; 949 } 950 /* EXAMPLE_END */ 951