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