1 /* 2 * Copyright (C) 2022 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 BLUEKITCHEN 24 * GMBH 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__ "le_audio_unicast_sink.c" 39 40 /* 41 * LE Audio Unicast Sink 42 * Until GATT Services are available, we encode LC3 config in advertising 43 */ 44 45 46 #include "btstack_config.h" 47 48 #include <stdint.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 53 #include "ad_parser.h" 54 #include "bluetooth_data_types.h" 55 #include "bluetooth_company_id.h" 56 #include "btstack_debug.h" 57 #include "btstack_event.h" 58 #include "btstack_stdin.h" 59 #include "gap.h" 60 #include "hci.h" 61 #include "le_audio_demo_util_sink.h" 62 #include "le_audio_demo_util_source.h" 63 64 // max config 65 #define MAX_CHANNELS 2 66 #define MAX_SAMPLES_PER_FRAME 480 67 68 static void show_usage(void); 69 70 static enum { 71 APP_W4_WORKING, 72 APP_W4_SOURCE_ADV, 73 APP_W4_CIG_COMPLETE, 74 APP_W4_CIS_CREATED, 75 APP_STREAMING, 76 APP_IDLE, 77 } app_state = APP_W4_WORKING; 78 79 // 80 static btstack_packet_callback_registration_t hci_event_callback_registration; 81 82 // remote info 83 static char remote_name[20]; 84 static bd_addr_t remote_addr; 85 static bd_addr_type_t remote_type; 86 static hci_con_handle_t remote_handle; 87 88 static le_audio_cig_t cig; 89 static le_audio_cig_params_t cig_params; 90 91 // iso info 92 static bool framed_pdus; 93 static uint16_t frame_duration_us; 94 95 static uint8_t num_cis; 96 static hci_con_handle_t cis_con_handles[MAX_CHANNELS]; 97 static bool cis_established[MAX_CHANNELS]; 98 99 // lc3 codec config 100 static uint16_t sampling_frequency_hz; 101 static btstack_lc3_frame_duration_t frame_duration; 102 static uint16_t number_samples_per_frame; 103 static uint16_t octets_per_frame; 104 static uint8_t num_channels; 105 106 // microphone 107 static bool microphone_enable; 108 109 static void start_scanning() { 110 app_state = APP_W4_SOURCE_ADV; 111 gap_set_scan_params(1, 0x30, 0x30, 0); 112 gap_start_scan(); 113 printf("Start scan..\n"); 114 } 115 116 static void create_cig() { 117 if (sampling_frequency_hz == 44100){ 118 framed_pdus = 1; 119 // same config as for 48k -> frame is longer by 48/44.1 120 frame_duration_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8163 : 10884; 121 } else { 122 framed_pdus = 0; 123 frame_duration_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 7500 : 10000; 124 } 125 126 printf("Send: LE Set CIG Parameters\n"); 127 128 num_cis = 1; 129 cig_params.cig_id = 0; 130 cig_params.num_cis = 1; 131 cig_params.sdu_interval_c_to_p = frame_duration_us; 132 cig_params.sdu_interval_p_to_c = frame_duration_us; 133 cig_params.worst_case_sca = 0; // 251 ppm to 500 ppm 134 cig_params.packing = 0; // sequential 135 cig_params.framing = framed_pdus; 136 cig_params.max_transport_latency_c_to_p = 40; 137 cig_params.max_transport_latency_p_to_c = 40; 138 uint8_t i; 139 uint16_t max_sdu_c_to_p = microphone_enable ? octets_per_frame : 0; 140 for (i=0; i < num_cis; i++){ 141 cig_params.cis_params[i].cis_id = i; 142 cig_params.cis_params[i].max_sdu_c_to_p = max_sdu_c_to_p; 143 cig_params.cis_params[i].max_sdu_p_to_c = num_channels * octets_per_frame; 144 cig_params.cis_params[i].phy_c_to_p = 2; // 2M 145 cig_params.cis_params[i].phy_p_to_c = 2; // 2M 146 cig_params.cis_params[i].rtn_c_to_p = 2; 147 cig_params.cis_params[i].rtn_p_to_c = 2; 148 } 149 150 app_state = APP_W4_CIG_COMPLETE; 151 gap_cig_create(&cig, &cig_params); 152 } 153 154 static void enter_streaming(void){ 155 // init source 156 if (microphone_enable){ 157 le_audio_demo_util_source_configure(1, 1, sampling_frequency_hz, frame_duration, octets_per_frame); 158 le_audio_demo_util_source_generate_iso_frame(AUDIO_SOURCE_SINE); 159 } 160 // init sink 161 uint16_t iso_interval_1250us = frame_duration_us / 1250; 162 uint8_t flush_timeout = 1; 163 le_audio_demo_util_sink_configure_unicast(1, num_channels, sampling_frequency_hz, frame_duration, octets_per_frame, 164 iso_interval_1250us, flush_timeout); 165 printf("Configure: %u channels, sampling rate %u, samples per frame %u\n", num_channels, sampling_frequency_hz, number_samples_per_frame); 166 } 167 168 169 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 170 UNUSED(channel); 171 bd_addr_t event_addr; 172 hci_con_handle_t cis_handle; 173 unsigned int i; 174 uint8_t status; 175 if (packet_type != HCI_EVENT_PACKET) return; 176 switch (packet[0]) { 177 case BTSTACK_EVENT_STATE: 178 switch(btstack_event_state_get_state(packet)) { 179 case HCI_STATE_WORKING: 180 #ifdef ENABLE_DEMO_MODE 181 if (app_state != APP_W4_WORKING) break; 182 start_scanning(); 183 #else 184 show_usage(); 185 #endif 186 break; 187 case HCI_STATE_OFF: 188 printf("Goodbye\n"); 189 exit(0); 190 break; 191 default: 192 break; 193 } 194 break; 195 case HCI_EVENT_DISCONNECTION_COMPLETE: 196 if (hci_event_disconnection_complete_get_connection_handle(packet) == remote_handle){ 197 printf("Disconnected, back to scanning\n"); 198 le_audio_demo_util_sink_close(); 199 start_scanning(); 200 } 201 break; 202 case GAP_EVENT_ADVERTISING_REPORT: 203 { 204 if (app_state != APP_W4_SOURCE_ADV) break; 205 206 gap_event_advertising_report_get_address(packet, remote_addr); 207 uint8_t adv_size = gap_event_advertising_report_get_data_length(packet); 208 const uint8_t * adv_data = gap_event_advertising_report_get_data(packet); 209 210 ad_context_t context; 211 bool found = false; 212 remote_name[0] = '\0'; 213 uint16_t uuid; 214 uint16_t company_id; 215 for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)) { 216 uint8_t data_type = ad_iterator_get_data_type(&context); 217 uint8_t size = ad_iterator_get_data_len(&context); 218 const uint8_t *data = ad_iterator_get_data(&context); 219 switch (data_type){ 220 case BLUETOOTH_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA: 221 company_id = little_endian_read_16(data, 0); 222 if (company_id == BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH){ 223 // subtype = 0 -> le audio unicast source 224 uint8_t subtype = data[2]; 225 if (subtype != 0) break; 226 // flags 227 uint8_t flags = data[3]; 228 // num channels 229 num_channels = data[4]; 230 if (num_channels > 2) break; 231 // sampling frequency 232 sampling_frequency_hz = 1000 * data[5]; 233 // frame duration 234 frame_duration = data[6] == 0 ? BTSTACK_LC3_FRAME_DURATION_7500US : BTSTACK_LC3_FRAME_DURATION_10000US; 235 // octets per frame 236 octets_per_frame = data[7]; 237 // done 238 found = true; 239 } 240 break; 241 case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME: 242 case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME: 243 size = btstack_min(sizeof(remote_name) - 1, size); 244 memcpy(remote_name, data, size); 245 remote_name[size] = 0; 246 break; 247 default: 248 break; 249 } 250 } 251 if (!found) break; 252 remote_type = gap_event_advertising_report_get_address_type(packet); 253 printf("Remote Unicast source found, addr %s, name: '%s'\n", bd_addr_to_str(remote_addr), remote_name); 254 // stop scanning 255 app_state = APP_W4_CIS_CREATED; 256 gap_stop_scan(); 257 gap_connect(remote_addr, remote_type); 258 break; 259 } 260 261 case HCI_EVENT_LE_META: 262 switch(hci_event_le_meta_get_subevent_code(packet)) { 263 case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: 264 hci_subevent_le_connection_complete_get_peer_address(packet, event_addr); 265 remote_handle = hci_subevent_le_connection_complete_get_connection_handle(packet); 266 printf("Connected, remote %s, handle %04x\n", bd_addr_to_str(event_addr), remote_handle); 267 create_cig(); 268 break; 269 default: 270 break; 271 } 272 break; 273 case HCI_EVENT_META_GAP: 274 switch (hci_event_gap_meta_get_subevent_code(packet)){ 275 case GAP_SUBEVENT_CIG_CREATED: 276 if (app_state == APP_W4_CIG_COMPLETE){ 277 printf("CIS Connection Handles: "); 278 for (i=0; i < num_cis; i++){ 279 cis_con_handles[i] = gap_subevent_cig_created_get_cis_con_handles(packet, i); 280 printf("0x%04x ", cis_con_handles[i]); 281 } 282 printf("\n"); 283 284 printf("Create CIS\n"); 285 hci_con_handle_t acl_connection_handles[MAX_CHANNELS]; 286 for (i=0; i < num_cis; i++){ 287 acl_connection_handles[i] = remote_handle; 288 } 289 gap_cis_create(cig_params.cig_id, cis_con_handles, acl_connection_handles); 290 app_state = APP_W4_CIS_CREATED; 291 } 292 break; 293 case GAP_SUBEVENT_CIS_CREATED: 294 status = gap_subevent_big_created_get_status(packet); 295 cis_handle = gap_subevent_cis_created_get_cis_con_handle(packet); 296 if (status == ERROR_CODE_SUCCESS){ 297 // only look for cis handle 298 for (i=0; i < num_cis; i++){ 299 if (cis_handle == cis_con_handles[i]){ 300 cis_established[i] = true; 301 } 302 } 303 // check for complete 304 bool complete = true; 305 for (i=0; i < num_cis; i++) { 306 complete &= cis_established[i]; 307 } 308 if (complete) { 309 printf("All CIS Established\n"); 310 app_state = APP_STREAMING; 311 enter_streaming(); 312 // start sending 313 if (microphone_enable){ 314 hci_request_cis_can_send_now_events(cis_con_handles[0]); 315 } 316 } 317 } else { 318 printf("CIS Create failed with status 0x%02x for con handle 0x%04x\n", status, cis_handle); 319 } 320 break; 321 default: 322 break; 323 } 324 break; 325 case HCI_EVENT_CIS_CAN_SEND_NOW: 326 le_audio_demo_util_source_send(0, cis_con_handles[0]); 327 le_audio_demo_util_source_generate_iso_frame(AUDIO_SOURCE_SINE); 328 hci_request_cis_can_send_now_events(cis_con_handles[0]); 329 break; 330 default: 331 break; 332 } 333 } 334 335 static void iso_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 336 le_audio_demo_util_sink_receive(0, packet, size); 337 } 338 339 static void show_usage(void){ 340 printf("\n--- LE Audio Unicast Sink Test Console ---\n"); 341 printf("s - start scanning\n"); 342 #ifdef HAVE_LC3PLUS 343 printf("q - use LC3plus decoder if 10 ms ISO interval is used\n"); 344 #endif 345 printf("m - enable virtual microphone\n"); 346 printf("---\n"); 347 } 348 349 static void stdin_process(char c){ 350 switch (c){ 351 case 's': 352 if (app_state != APP_W4_WORKING) break; 353 start_scanning(); 354 break; 355 #ifdef HAVE_LC3PLUS 356 case 'q': 357 printf("Use LC3 Plust for 10 ms frames\n"); 358 le_audio_demo_util_sink_enable_lc3plus(true); 359 break; 360 #endif 361 case 'm': 362 printf("Enable virtual microphone\n"); 363 microphone_enable = true; 364 break; 365 case '\n': 366 case '\r': 367 break; 368 default: 369 show_usage(); 370 break; 371 372 } 373 } 374 375 int btstack_main(int argc, const char * argv[]); 376 int btstack_main(int argc, const char * argv[]){ 377 (void) argv; 378 (void) argc; 379 380 // register for HCI events 381 hci_event_callback_registration.callback = &packet_handler; 382 hci_add_event_handler(&hci_event_callback_registration); 383 384 // register for ISO Packet 385 hci_register_iso_packet_handler(&iso_packet_handler); 386 387 // setup audio processing 388 le_audio_demo_util_sink_init("le_audio_unicast_sink.wav"); 389 le_audio_demo_util_source_init(); 390 391 // turn on! 392 hci_power_control(HCI_POWER_ON); 393 394 btstack_stdin_setup(stdin_process); 395 return 0; 396 } 397