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