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