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