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