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