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