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 status = avrcp_subevent_connection_established_get_status(packet); 730 if (status != ERROR_CODE_SUCCESS){ 731 printf("AVRCP: Connection failed, status 0x%02x\n", status); 732 return; 733 } 734 media_tracker.avrcp_cid = local_cid; 735 avrcp_subevent_connection_established_get_bd_addr(packet, event_addr); 736 737 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t)); 738 avrcp_target_set_unit_info(media_tracker.avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, company_id); 739 avrcp_target_set_subunit_info(media_tracker.avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, (uint8_t *)subunit_info, sizeof(subunit_info)); 740 741 // automatically enable notifications 742 avrcp_controller_enable_notification(media_tracker.avrcp_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED); 743 printf("AVRCP: Channel successfully opened: media_tracker.avrcp_cid 0x%02x\n", media_tracker.avrcp_cid); 744 return; 745 746 case AVRCP_SUBEVENT_CONNECTION_RELEASED: 747 printf("AVRCP Target: Disconnected, avrcp_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet)); 748 media_tracker.avrcp_cid = 0; 749 return; 750 default: 751 break; 752 } 753 754 if (status != ERROR_CODE_SUCCESS){ 755 printf("Responding to event 0x%02x failed with status 0x%02x\n", packet[2], status); 756 } 757 } 758 759 static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 760 UNUSED(channel); 761 UNUSED(size); 762 uint8_t status = ERROR_CODE_SUCCESS; 763 764 if (packet_type != HCI_EVENT_PACKET) return; 765 if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return; 766 767 switch (packet[2]){ 768 case AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED: 769 printf("AVRCP Target: new volume %d\n", avrcp_subevent_notification_volume_changed_get_absolute_volume(packet)); 770 break; 771 case AVRCP_SUBEVENT_EVENT_IDS_QUERY: 772 status = avrcp_target_supported_events(media_tracker.avrcp_cid, events_num, events, sizeof(events)); 773 break; 774 case AVRCP_SUBEVENT_COMPANY_IDS_QUERY: 775 status = avrcp_target_supported_companies(media_tracker.avrcp_cid, companies_num, companies, sizeof(companies)); 776 break; 777 case AVRCP_SUBEVENT_PLAY_STATUS_QUERY: 778 status = avrcp_target_play_status(media_tracker.avrcp_cid, play_info.song_length_ms, play_info.song_position_ms, play_info.status); 779 break; 780 // case AVRCP_SUBEVENT_NOW_PLAYING_INFO_QUERY: 781 // status = avrcp_target_now_playing_info(avrcp_cid); 782 // break; 783 case AVRCP_SUBEVENT_OPERATION:{ 784 avrcp_operation_id_t operation_id = avrcp_subevent_operation_get_operation_id(packet); 785 switch (operation_id){ 786 case AVRCP_OPERATION_ID_PLAY: 787 printf("AVRCP Target: PLAY\n"); 788 status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 789 break; 790 case AVRCP_OPERATION_ID_PAUSE: 791 printf("AVRCP Target: PAUSE\n"); 792 status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 793 break; 794 case AVRCP_OPERATION_ID_STOP: 795 printf("AVRCP Target: STOP\n"); 796 status = a2dp_source_disconnect(media_tracker.a2dp_cid); 797 break; 798 default: 799 printf("AVRCP Target: operation 0x%2x is not handled\n", operation_id); 800 return; 801 } 802 break; 803 } 804 805 default: 806 break; 807 } 808 809 if (status != ERROR_CODE_SUCCESS){ 810 printf("Responding to event 0x%02x failed with status 0x%02x\n", packet[2], status); 811 } 812 } 813 814 static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 815 UNUSED(channel); 816 UNUSED(size); 817 uint8_t status = 0xFF; 818 819 if (packet_type != HCI_EVENT_PACKET) return; 820 if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return; 821 822 status = packet[5]; 823 if (!media_tracker.avrcp_cid) return; 824 825 // ignore INTERIM status 826 if (status == AVRCP_CTYPE_RESPONSE_INTERIM) return; 827 828 switch (packet[2]){ 829 case AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED:{ 830 int volume_percentage = avrcp_subevent_notification_volume_changed_get_absolute_volume(packet) * 100 / 127; 831 printf("AVRCP Controller: notification absolute volume changed %d %%\n", volume_percentage); 832 return; 833 } 834 default: 835 break; 836 } 837 } 838 839 #ifdef HAVE_BTSTACK_STDIN 840 static void show_usage(void){ 841 bd_addr_t iut_address; 842 gap_local_bd_addr(iut_address); 843 printf("\n--- Bluetooth A2DP Source/AVRCP Demo %s ---\n", bd_addr_to_str(iut_address)); 844 printf("b - A2DP Source create connection to addr %s\n", device_addr_string); 845 printf("B - A2DP Source disconnect\n"); 846 printf("c - AVRCP create connection to addr %s\n", device_addr_string); 847 printf("C - AVRCP disconnect\n"); 848 849 printf("x - start streaming sine\n"); 850 if (hxcmod_initialized){ 851 printf("z - start streaming '%s'\n", mod_name); 852 } 853 printf("p - pause streaming\n"); 854 printf("w - reconfigure stream for 44100 Hz\n"); 855 printf("e - reconfigure stream for 48000 Hz\n"); 856 printf("t - volume up\n"); 857 printf("T - volume down\n"); 858 printf("v - absolute volume of 50 percent\n"); 859 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 connection to addr %s.\n", cmd, bd_addr_to_str(device_addr)); 876 status = avrcp_connect(device_addr, &media_tracker.avrcp_cid); 877 break; 878 case 'C': 879 printf("%c - AVRCP disconnect\n", cmd); 880 status = avrcp_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(media_tracker.avrcp_cid); 890 break; 891 case 'T': 892 printf(" - volume down\n"); 893 status = avrcp_controller_volume_down(media_tracker.avrcp_cid); 894 break; 895 case 'v': 896 printf(" - absolute volume of 50%% (64)\n"); 897 status = avrcp_controller_set_absolute_volume(media_tracker.avrcp_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