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 0 74 75 #define NUM_CHANNELS 2 76 #define A2DP_SAMPLE_RATE 44100 77 #define BYTES_PER_AUDIO_SAMPLE (2*NUM_CHANNELS) 78 #define AUDIO_TIMEOUT_MS 10 79 #define TABLE_SIZE_441HZ 100 80 81 #define SBC_STORAGE_SIZE 1030 82 83 typedef enum { 84 STREAM_SINE = 0, 85 STREAM_MOD, 86 STREAM_PTS_TEST 87 } stream_data_source_t; 88 89 typedef struct { 90 uint16_t a2dp_cid; 91 uint8_t local_seid; 92 uint8_t stream_opened; 93 uint16_t avrcp_cid; 94 95 uint32_t time_audio_data_sent; // ms 96 uint32_t acc_num_missed_samples; 97 uint32_t samples_ready; 98 btstack_timer_source_t audio_timer; 99 uint8_t streaming; 100 int max_media_payload_size; 101 102 uint8_t sbc_storage[SBC_STORAGE_SIZE]; 103 uint16_t sbc_storage_count; 104 uint8_t sbc_ready_to_send; 105 } a2dp_media_sending_context_t; 106 107 static uint8_t media_sbc_codec_capabilities[] = { 108 (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO, 109 0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS, 110 2, 53 111 }; 112 113 static const int16_t sine_int16[] = { 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 typedef struct { 127 int reconfigure; 128 int num_channels; 129 int sampling_frequency; 130 int channel_mode; 131 int block_length; 132 int subbands; 133 int allocation_method; 134 int min_bitpool_value; 135 int max_bitpool_value; 136 int frames_per_buffer; 137 } avdtp_media_codec_configuration_sbc_t; 138 139 static btstack_packet_callback_registration_t hci_event_callback_registration; 140 141 // pts: static const char * device_addr_string = "00:1B:DC:08:0A:A5"; 142 // mac 2013: static const char * device_addr_string = "84:38:35:65:d1:15"; 143 // phone 2013: static const char * device_addr_string = "D8:BB:2C:DF:F0:F2"; 144 // Minijambox: 145 static const char * device_addr_string = "00:21:3C:AC:F7:38"; 146 // Philips SHB9100: static const char * device_addr_string = "00:22:37:05:FD:E8"; 147 // RT-B6: static const char * device_addr_string = "00:75:58:FF:C9:7D"; 148 // BT dongle: static const char * device_addr_string = "00:1A:7D:DA:71:0A"; 149 // Sony MDR-ZX330BT static const char * device_addr_string = "00:18:09:28:50:18"; 150 // Panda (BM6) static const char * device_addr_string = "4F:3F:66:52:8B:E0"; 151 152 static bd_addr_t device_addr; 153 static uint8_t sdp_a2dp_source_service_buffer[150]; 154 static uint8_t sdp_avrcp_target_service_buffer[200]; 155 static avdtp_media_codec_configuration_sbc_t sbc_configuration; 156 static btstack_sbc_encoder_state_t sbc_encoder_state; 157 158 static uint8_t media_sbc_codec_configuration[4]; 159 static a2dp_media_sending_context_t media_tracker; 160 161 static stream_data_source_t data_source; 162 163 static int sine_phase; 164 165 static int hxcmod_initialized; 166 static modcontext mod_context; 167 static tracker_buffer_state trkbuf; 168 169 170 /* AVRCP Target context START */ 171 static const uint8_t subunit_info[] = { 172 0,0,0,0, 173 1,1,1,1, 174 2,2,2,2, 175 3,3,3,3, 176 4,4,4,4, 177 5,5,5,5, 178 6,6,6,6, 179 7,7,7,7 180 }; 181 182 static uint32_t company_id = 0x112233; 183 static uint8_t companies_num = 1; 184 static uint8_t companies[] = { 185 0x00, 0x19, 0x58 //BT SIG registered CompanyID 186 }; 187 188 static uint8_t events_num = 13; 189 static uint8_t events[] = { 190 AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED, 191 AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED, 192 AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_END, 193 AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_START, 194 AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED, 195 AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED, 196 AVRCP_NOTIFICATION_EVENT_SYSTEM_STATUS_CHANGED, 197 AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED, 198 AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED, 199 AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED, 200 AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED, 201 AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED, 202 AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED 203 }; 204 205 typedef struct { 206 uint8_t track_id[8]; 207 uint32_t song_length_ms; 208 avrcp_playback_status_t status; 209 uint32_t song_position_ms; // 0xFFFFFFFF if not supported 210 } avrcp_play_status_info_t; 211 212 // python -c "print('a'*512)" 213 static const char title[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 214 215 avrcp_track_t tracks[] = { 216 {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 1, "Sine", "Generated", "AVRCP Demo", "monotone", 12345}, 217 {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, 2, "Nao-deceased", "Decease", "AVRCP Demo", "vivid", 12345}, 218 {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, 3, (char *)title, "Decease", "AVRCP Demo", "vivid", 12345}, 219 }; 220 int current_track_index; 221 avrcp_play_status_info_t play_info; 222 223 /* AVRCP Target context END */ 224 225 /* @section Main Application Setup 226 * 227 * @text The Listing MainConfiguration shows how to setup AD2P Source and AVRCP Target services. 228 */ 229 230 /* LISTING_START(MainConfiguration): Setup Audio Source and AVRCP Target services */ 231 static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size); 232 static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 233 #ifdef HAVE_BTSTACK_STDIN 234 static void stdin_process(char cmd); 235 #endif 236 237 static int a2dp_source_and_avrcp_services_init(void){ 238 // Register for HCI events. 239 hci_event_callback_registration.callback = &a2dp_source_packet_handler; 240 hci_add_event_handler(&hci_event_callback_registration); 241 242 l2cap_init(); 243 // Initialize A2DP Source. 244 a2dp_source_init(); 245 a2dp_source_register_packet_handler(&a2dp_source_packet_handler); 246 247 // Create stream endpoint. 248 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)); 249 if (!local_stream_endpoint){ 250 printf("A2DP Source: not enough memory to create local stream endpoint\n"); 251 return 1; 252 } 253 media_tracker.local_seid = avdtp_local_seid(local_stream_endpoint); 254 255 // Initialize AVRCP Target. 256 avrcp_target_init(); 257 avrcp_target_register_packet_handler(&avrcp_target_packet_handler); 258 259 // Initialize SDP, 260 sdp_init(); 261 262 // Create A2DP Source service record and register it with SDP. 263 memset(sdp_a2dp_source_service_buffer, 0, sizeof(sdp_a2dp_source_service_buffer)); 264 a2dp_source_create_sdp_record(sdp_a2dp_source_service_buffer, 0x10002, 1, NULL, NULL); 265 sdp_register_service(sdp_a2dp_source_service_buffer); 266 267 // Create AVRCP target service record and register it with SDP. 268 memset(sdp_avrcp_target_service_buffer, 0, sizeof(sdp_avrcp_target_service_buffer)); 269 avrcp_target_create_sdp_record(sdp_avrcp_target_service_buffer, 0x10001, AVRCP_BROWSING_ENABLED, 1, NULL, NULL); 270 sdp_register_service(sdp_avrcp_target_service_buffer); 271 272 // Set local name with a template Bluetooth address, that will be automatically 273 // replaced with a actual address once it is available, i.e. when BTstack boots 274 // up and starts talking to a Bluetooth module. 275 gap_set_local_name("A2DP Source 00:00:00:00:00:00"); 276 gap_discoverable_control(1); 277 gap_set_class_of_device(0x200408); 278 279 hxcmod_initialized = hxcmod_init(&mod_context); 280 if (hxcmod_initialized){ 281 hxcmod_setcfg(&mod_context, A2DP_SAMPLE_RATE, 16, 1, 1, 1); 282 hxcmod_load(&mod_context, (void *) &mod_data, mod_len); 283 printf("loaded mod '%s', size %u\n", mod_name, mod_len); 284 } 285 286 // Parse human readable Bluetooth address. 287 sscanf_bd_addr(device_addr_string, device_addr); 288 289 #ifdef HAVE_BTSTACK_STDIN 290 btstack_stdin_setup(stdin_process); 291 #endif 292 return 0; 293 } 294 /* LISTING_END */ 295 296 static void a2dp_demo_send_media_packet(void){ 297 int num_bytes_in_frame = btstack_sbc_encoder_sbc_buffer_length(); 298 int bytes_in_storage = media_tracker.sbc_storage_count; 299 uint8_t num_frames = bytes_in_storage / num_bytes_in_frame; 300 a2dp_source_stream_send_media_payload(media_tracker.a2dp_cid, media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0); 301 media_tracker.sbc_storage_count = 0; 302 media_tracker.sbc_ready_to_send = 0; 303 } 304 305 static void produce_sine_audio(int16_t * pcm_buffer, int num_samples_to_write){ 306 int count; 307 for (count = 0; count < num_samples_to_write ; count++){ 308 pcm_buffer[count * 2] = sine_int16[sine_phase]; 309 pcm_buffer[count * 2 + 1] = sine_int16[sine_phase]; 310 sine_phase++; 311 if (sine_phase >= TABLE_SIZE_441HZ){ 312 sine_phase -= TABLE_SIZE_441HZ; 313 } 314 } 315 } 316 317 static void produce_mod_audio(int16_t * pcm_buffer, int num_samples_to_write){ 318 hxcmod_fillbuffer(&mod_context, (unsigned short *) &pcm_buffer[0], num_samples_to_write, &trkbuf); 319 } 320 321 static void produce_audio(int16_t * pcm_buffer, int num_samples){ 322 switch (data_source){ 323 case STREAM_SINE: 324 produce_sine_audio(pcm_buffer, num_samples); 325 break; 326 case STREAM_MOD: 327 produce_mod_audio(pcm_buffer, num_samples); 328 break; 329 default: 330 break; 331 } 332 #ifdef VOLUME_REDUCTION 333 int i; 334 for (i=0;i<num_samples*2;i++){ 335 if (pcm_buffer[i] > 0){ 336 pcm_buffer[i] = pcm_buffer[i] >> VOLUME_REDUCTION; 337 } else { 338 pcm_buffer[i] = -((-pcm_buffer[i]) >> VOLUME_REDUCTION); 339 } 340 } 341 #endif 342 } 343 344 static int a2dp_demo_fill_sbc_audio_buffer(a2dp_media_sending_context_t * context){ 345 // perform sbc encodin 346 int total_num_bytes_read = 0; 347 unsigned int num_audio_samples_per_sbc_buffer = btstack_sbc_encoder_num_audio_frames(); 348 while (context->samples_ready >= num_audio_samples_per_sbc_buffer 349 && (context->max_media_payload_size - context->sbc_storage_count) >= btstack_sbc_encoder_sbc_buffer_length()){ 350 351 int16_t pcm_frame[256*NUM_CHANNELS]; 352 353 produce_audio(pcm_frame, num_audio_samples_per_sbc_buffer); 354 btstack_sbc_encoder_process_data(pcm_frame); 355 356 uint16_t sbc_frame_size = btstack_sbc_encoder_sbc_buffer_length(); 357 uint8_t * sbc_frame = btstack_sbc_encoder_sbc_buffer(); 358 359 total_num_bytes_read += num_audio_samples_per_sbc_buffer; 360 memcpy(&context->sbc_storage[context->sbc_storage_count], sbc_frame, sbc_frame_size); 361 context->sbc_storage_count += sbc_frame_size; 362 context->samples_ready -= num_audio_samples_per_sbc_buffer; 363 } 364 return total_num_bytes_read; 365 } 366 367 static void a2dp_demo_audio_timeout_handler(btstack_timer_source_t * timer){ 368 a2dp_media_sending_context_t * context = (a2dp_media_sending_context_t *) btstack_run_loop_get_timer_context(timer); 369 btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS); 370 btstack_run_loop_add_timer(&context->audio_timer); 371 uint32_t now = btstack_run_loop_get_time_ms(); 372 373 uint32_t update_period_ms = AUDIO_TIMEOUT_MS; 374 if (context->time_audio_data_sent > 0){ 375 update_period_ms = now - context->time_audio_data_sent; 376 } 377 378 uint32_t num_samples = (update_period_ms * A2DP_SAMPLE_RATE) / 1000; 379 context->acc_num_missed_samples += (update_period_ms * A2DP_SAMPLE_RATE) % 1000; 380 381 while (context->acc_num_missed_samples >= 1000){ 382 num_samples++; 383 context->acc_num_missed_samples -= 1000; 384 } 385 context->time_audio_data_sent = now; 386 context->samples_ready += num_samples; 387 388 if (context->sbc_ready_to_send) return; 389 390 a2dp_demo_fill_sbc_audio_buffer(context); 391 392 if ((context->sbc_storage_count + btstack_sbc_encoder_sbc_buffer_length()) > context->max_media_payload_size){ 393 // schedule sending 394 context->sbc_ready_to_send = 1; 395 a2dp_source_stream_endpoint_request_can_send_now(context->a2dp_cid, context->local_seid); 396 } 397 } 398 399 static void a2dp_demo_timer_start(a2dp_media_sending_context_t * context){ 400 context->max_media_payload_size = btstack_min(a2dp_max_media_payload_size(context->a2dp_cid, context->local_seid), SBC_STORAGE_SIZE); 401 context->sbc_storage_count = 0; 402 context->sbc_ready_to_send = 0; 403 context->streaming = 1; 404 btstack_run_loop_remove_timer(&context->audio_timer); 405 btstack_run_loop_set_timer_handler(&context->audio_timer, a2dp_demo_audio_timeout_handler); 406 btstack_run_loop_set_timer_context(&context->audio_timer, context); 407 btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS); 408 btstack_run_loop_add_timer(&context->audio_timer); 409 } 410 411 static void a2dp_demo_timer_stop(a2dp_media_sending_context_t * context){ 412 context->time_audio_data_sent = 0; 413 context->acc_num_missed_samples = 0; 414 context->samples_ready = 0; 415 context->streaming = 1; 416 context->sbc_storage_count = 0; 417 context->sbc_ready_to_send = 0; 418 btstack_run_loop_remove_timer(&context->audio_timer); 419 } 420 421 static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 422 UNUSED(channel); 423 UNUSED(size); 424 uint8_t status; 425 uint8_t local_seid; 426 bd_addr_t address; 427 uint16_t cid; 428 429 if (packet_type != HCI_EVENT_PACKET) return; 430 431 #ifndef HAVE_BTSTACK_STDIN 432 if (hci_event_packet_get_type(packet) == BTSTACK_EVENT_STATE){ 433 if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; 434 printf("Create AVDTP Source connection to addr %s.\n", bd_addr_to_str(device_addr)); 435 status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid); 436 if (status != ERROR_CODE_SUCCESS){ 437 printf("Could not perform command, status 0x%2x\n", status); 438 } 439 return; 440 } 441 #endif 442 if (hci_event_packet_get_type(packet) == HCI_EVENT_PIN_CODE_REQUEST) { 443 printf("Pin code request - using '0000'\n"); 444 hci_event_pin_code_request_get_bd_addr(packet, address); 445 gap_pin_code_response(address, "0000"); 446 return; 447 } 448 449 if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return; 450 switch (packet[2]){ 451 case A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED: 452 a2dp_subevent_signaling_connection_established_get_bd_addr(packet, address); 453 cid = a2dp_subevent_signaling_connection_established_get_a2dp_cid(packet); 454 status = a2dp_subevent_signaling_connection_established_get_status(packet); 455 456 if (status != ERROR_CODE_SUCCESS){ 457 printf("A2DP Source: Connection failed, status 0x%02x, cid 0x%02x, a2dp_cid 0x%02x \n", status, cid, media_tracker.a2dp_cid); 458 media_tracker.a2dp_cid = 0; 459 break; 460 } 461 media_tracker.a2dp_cid = cid; 462 printf("A2DP Source: Connected to address %s, a2dp cid 0x%02x.\n", bd_addr_to_str(address), media_tracker.a2dp_cid); 463 break; 464 465 case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{ 466 printf("A2DP Source: Received SBC codec configuration.\n"); 467 sbc_configuration.reconfigure = a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet); 468 sbc_configuration.num_channels = a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet); 469 sbc_configuration.sampling_frequency = a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet); 470 sbc_configuration.channel_mode = a2dp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet); 471 sbc_configuration.block_length = a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet); 472 sbc_configuration.subbands = a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet); 473 sbc_configuration.allocation_method = a2dp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet); 474 sbc_configuration.min_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet); 475 sbc_configuration.max_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet); 476 sbc_configuration.frames_per_buffer = sbc_configuration.subbands * sbc_configuration.block_length; 477 478 btstack_sbc_encoder_init(&sbc_encoder_state, SBC_MODE_STANDARD, 479 sbc_configuration.block_length, sbc_configuration.subbands, 480 sbc_configuration.allocation_method, sbc_configuration.sampling_frequency, 481 sbc_configuration.max_bitpool_value, 482 sbc_configuration.channel_mode); 483 484 // status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid); 485 // if (status != ERROR_CODE_SUCCESS){ 486 // printf("Could not perform command, status 0x%2x\n", status); 487 // } 488 break; 489 } 490 491 case A2DP_SUBEVENT_STREAM_ESTABLISHED: 492 a2dp_subevent_stream_established_get_bd_addr(packet, address); 493 status = a2dp_subevent_stream_established_get_status(packet); 494 if (status){ 495 printf("A2DP Source: Stream failed, status 0x%02x.\n", status); 496 break; 497 } 498 local_seid = a2dp_subevent_stream_established_get_local_seid(packet); 499 if (local_seid != media_tracker.local_seid){ 500 printf("A2DP Source: Stream failed, wrong local seid %d, expected %d.\n", local_seid, media_tracker.local_seid); 501 break; 502 } 503 printf("A2DP Source: Stream established, address %s, a2dp cid 0x%02x, local seid %d, remote seid %d.\n", bd_addr_to_str(address), 504 media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet)); 505 printf("A2DP Source: Start playing mod, a2dp cid 0x%02x.\n", media_tracker.a2dp_cid); 506 media_tracker.stream_opened = 1; 507 data_source = STREAM_MOD; 508 status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 509 break; 510 511 case A2DP_SUBEVENT_STREAM_STARTED: 512 play_info.status = AVRCP_PLAYBACK_STATUS_PLAYING; 513 if (media_tracker.avrcp_cid){ 514 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t)); 515 avrcp_target_set_playback_status(media_tracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_PLAYING); 516 } 517 a2dp_demo_timer_start(&media_tracker); 518 printf("A2DP Source: Stream started.\n"); 519 break; 520 521 case A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW: 522 a2dp_demo_send_media_packet(); 523 break; 524 525 case A2DP_SUBEVENT_STREAM_SUSPENDED: 526 play_info.status = AVRCP_PLAYBACK_STATUS_PAUSED; 527 if (media_tracker.avrcp_cid){ 528 avrcp_target_set_playback_status(media_tracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_PAUSED); 529 } 530 printf("A2DP Source: Stream paused.\n"); 531 a2dp_demo_timer_stop(&media_tracker); 532 break; 533 534 case A2DP_SUBEVENT_STREAM_RELEASED: 535 play_info.status = AVRCP_PLAYBACK_STATUS_STOPPED; 536 cid = a2dp_subevent_stream_released_get_a2dp_cid(packet); 537 if (cid == media_tracker.a2dp_cid) { 538 media_tracker.stream_opened = 0; 539 printf("A2DP Source: Stream released.\n"); 540 } 541 if (media_tracker.avrcp_cid){ 542 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t)); 543 avrcp_target_set_playback_status(media_tracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_STOPPED); 544 } 545 a2dp_demo_timer_stop(&media_tracker); 546 break; 547 case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED: 548 cid = a2dp_subevent_signaling_connection_released_get_a2dp_cid(packet); 549 if (cid == media_tracker.a2dp_cid) { 550 media_tracker.avrcp_cid = 0; 551 media_tracker.a2dp_cid = 0; 552 printf("A2DP Source: Signaling released.\n\n"); 553 } 554 break; 555 default: 556 break; 557 } 558 } 559 560 static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 561 UNUSED(channel); 562 UNUSED(size); 563 bd_addr_t event_addr; 564 uint16_t local_cid; 565 uint8_t status = ERROR_CODE_SUCCESS; 566 567 if (packet_type != HCI_EVENT_PACKET) return; 568 if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return; 569 570 switch (packet[2]){ 571 case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: { 572 local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet); 573 // if (avrcp_cid != 0 && avrcp_cid != local_cid) { 574 // printf("AVRCP Target: Connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", avrcp_cid, local_cid); 575 // return; 576 // } 577 // if (avrcp_cid != local_cid) break; 578 579 status = avrcp_subevent_connection_established_get_status(packet); 580 if (status != ERROR_CODE_SUCCESS){ 581 printf("AVRCP Target: Connection failed, status 0x%02x\n", status); 582 return; 583 } 584 media_tracker.avrcp_cid = local_cid; 585 avrcp_subevent_connection_established_get_bd_addr(packet, event_addr); 586 printf("AVRCP Target: Connected to %s, avrcp_cid 0x%02x\n", bd_addr_to_str(event_addr), local_cid); 587 588 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t)); 589 avrcp_target_set_unit_info(media_tracker.avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, company_id); 590 avrcp_target_set_subunit_info(media_tracker.avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, (uint8_t *)subunit_info, sizeof(subunit_info)); 591 return; 592 } 593 594 case AVRCP_SUBEVENT_EVENT_IDS_QUERY: 595 status = avrcp_target_supported_events(media_tracker.avrcp_cid, events_num, events, sizeof(events)); 596 break; 597 case AVRCP_SUBEVENT_COMPANY_IDS_QUERY: 598 status = avrcp_target_supported_companies(media_tracker.avrcp_cid, companies_num, companies, sizeof(companies)); 599 break; 600 case AVRCP_SUBEVENT_PLAY_STATUS_QUERY: 601 status = avrcp_target_play_status(media_tracker.avrcp_cid, play_info.song_length_ms, play_info.song_position_ms, play_info.status); 602 break; 603 // case AVRCP_SUBEVENT_NOW_PLAYING_INFO_QUERY: 604 // status = avrcp_target_now_playing_info(avrcp_cid); 605 // break; 606 case AVRCP_SUBEVENT_OPERATION:{ 607 avrcp_operation_id_t operation_id = avrcp_subevent_operation_get_operation_id(packet); 608 switch (operation_id){ 609 case AVRCP_OPERATION_ID_PLAY: 610 printf("AVRCP Target: PLAY\n"); 611 status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 612 break; 613 case AVRCP_OPERATION_ID_PAUSE: 614 printf("AVRCP Target: PAUSE\n"); 615 status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 616 break; 617 case AVRCP_OPERATION_ID_STOP: 618 printf("AVRCP Target: STOP\n"); 619 status = a2dp_source_disconnect(media_tracker.a2dp_cid); 620 break; 621 default: 622 printf("AVRCP Target: operation 0x%2x is not handled\n", operation_id); 623 return; 624 } 625 break; 626 } 627 case AVRCP_SUBEVENT_CONNECTION_RELEASED: 628 printf("AVRCP Target: Disconnected, avrcp_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet)); 629 media_tracker.avrcp_cid = 0; 630 return; 631 default: 632 break; 633 } 634 635 if (status != ERROR_CODE_SUCCESS){ 636 printf("Responding to event 0x%02x failed with status 0x%02x\n", packet[2], status); 637 } 638 } 639 640 #ifdef HAVE_BTSTACK_STDIN 641 static void show_usage(void){ 642 bd_addr_t iut_address; 643 gap_local_bd_addr(iut_address); 644 printf("\n--- Bluetooth A2DP Source/AVRCP Target Demo %s ---\n", bd_addr_to_str(iut_address)); 645 printf("b - AVDTP Source create connection to addr %s\n", device_addr_string); 646 printf("B - AVDTP Source disconnect\n"); 647 printf("c - AVRCP Target create connection to addr %s\n", device_addr_string); 648 printf("C - AVRCP Target disconnect\n"); 649 650 printf("x - start streaming sine\n"); 651 if (hxcmod_initialized){ 652 printf("z - start streaming '%s'\n", mod_name); 653 } 654 printf("p - pause streaming\n"); 655 656 printf("\n--- Bluetooth AVRCP Target Commands %s ---\n", bd_addr_to_str(iut_address)); 657 printf("---\n"); 658 } 659 660 static void stdin_process(char cmd){ 661 uint8_t status = ERROR_CODE_SUCCESS; 662 switch (cmd){ 663 case 'b': 664 status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid); 665 printf("%c - Create AVDTP Source connection to addr %s, cid 0x%02x.\n", cmd, bd_addr_to_str(device_addr), media_tracker.a2dp_cid); 666 break; 667 case 'B': 668 printf("%c - AVDTP Source Disconnect from cid 0x%2x\n", cmd, media_tracker.a2dp_cid); 669 status = a2dp_source_disconnect(media_tracker.a2dp_cid); 670 break; 671 case 'c': 672 printf("%c - Create AVRCP Target connection to addr %s.\n", cmd, bd_addr_to_str(device_addr)); 673 status = avrcp_target_connect(device_addr, &media_tracker.avrcp_cid); 674 break; 675 case 'C': 676 printf("%c - AVRCP Target disconnect\n", cmd); 677 status = avrcp_target_disconnect(media_tracker.avrcp_cid); 678 break; 679 680 case '\n': 681 case '\r': 682 break; 683 684 case 'x': 685 if (media_tracker.avrcp_cid){ 686 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t)); 687 } 688 printf("%c - Play sine.\n", cmd); 689 data_source = STREAM_SINE; 690 if (!media_tracker.stream_opened) break; 691 status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 692 break; 693 case 'z': 694 if (media_tracker.avrcp_cid){ 695 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t)); 696 } 697 printf("%c - Play mod.\n", cmd); 698 data_source = STREAM_MOD; 699 if (!media_tracker.stream_opened) break; 700 status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 701 break; 702 703 case 'p': 704 if (!media_tracker.stream_opened) break; 705 printf("%c - Pause stream.\n", cmd); 706 status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 707 break; 708 709 default: 710 show_usage(); 711 return; 712 } 713 if (status != ERROR_CODE_SUCCESS){ 714 printf("Could not perform command \'%c\', status 0x%2x\n", cmd, status); 715 } 716 } 717 #endif 718 719 720 int btstack_main(int argc, const char * argv[]); 721 int btstack_main(int argc, const char * argv[]){ 722 (void)argc; 723 (void)argv; 724 725 int err = a2dp_source_and_avrcp_services_init(); 726 if (err) return err; 727 // turn on! 728 hci_power_control(HCI_POWER_ON); 729 return 0; 730 } 731 /* EXAMPLE_END */ 732