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