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