110277393SMatthias Ringwald /* 210277393SMatthias Ringwald * Copyright (C) 2022 BlueKitchen GmbH 310277393SMatthias Ringwald * 410277393SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 510277393SMatthias Ringwald * modification, are permitted provided that the following conditions 610277393SMatthias Ringwald * are met: 710277393SMatthias Ringwald * 810277393SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 910277393SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 1010277393SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 1110277393SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 1210277393SMatthias Ringwald * documentation and/or other materials provided with the distribution. 1310277393SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 1410277393SMatthias Ringwald * contributors may be used to endorse or promote products derived 1510277393SMatthias Ringwald * from this software without specific prior written permission. 1610277393SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 1710277393SMatthias Ringwald * personal benefit and not for any commercial purpose or for 1810277393SMatthias Ringwald * monetary gain. 1910277393SMatthias Ringwald * 2010277393SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 2110277393SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2210277393SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2310277393SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 2410277393SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2510277393SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2610277393SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2710277393SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2810277393SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2910277393SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3010277393SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3110277393SMatthias Ringwald * SUCH DAMAGE. 3210277393SMatthias Ringwald * 3310277393SMatthias Ringwald * Please inquire about commercial licensing options at 3410277393SMatthias Ringwald * [email protected] 3510277393SMatthias Ringwald * 3610277393SMatthias Ringwald */ 3710277393SMatthias Ringwald 3810277393SMatthias Ringwald #define BTSTACK_FILE__ "le_audio_broadcast_source.c" 3910277393SMatthias Ringwald 4010277393SMatthias Ringwald /* 4110277393SMatthias Ringwald * LE Audio Broadcast Source 4210277393SMatthias Ringwald */ 4310277393SMatthias Ringwald 4410277393SMatthias Ringwald #include <stdint.h> 4510277393SMatthias Ringwald #include <stdio.h> 4610277393SMatthias Ringwald #include <string.h> 4710277393SMatthias Ringwald #include <btstack_debug.h> 4810277393SMatthias Ringwald 4910277393SMatthias Ringwald #include "bluetooth_data_types.h" 5010277393SMatthias Ringwald #include "btstack_stdin.h" 5110277393SMatthias Ringwald #include "btstack_event.h" 5210277393SMatthias Ringwald #include "btstack_run_loop.h" 5310277393SMatthias Ringwald #include "gap.h" 5410277393SMatthias Ringwald #include "hci.h" 5510277393SMatthias Ringwald #include "hci_cmd.h" 5610277393SMatthias Ringwald #include "hci_dump.h" 572fd68da2SMatthias Ringwald #include "btstack_lc3.h" 58e40ee29aSMatthias Ringwald #include "btstack_lc3_google.h" 594a06e23fSMatthias Ringwald #include "le-audio/le_audio_base_builder.h" 6010277393SMatthias Ringwald 6110277393SMatthias Ringwald #include "hxcmod.h" 6210277393SMatthias Ringwald #include "mods/mod.h" 63bb81690eSMatthias Ringwald #include "le_audio_demo_util_source.h" 6410277393SMatthias Ringwald 65*0c30abb2SDirk Helbig // Interoperability with Nordic LE Audio demo 66*0c30abb2SDirk Helbig //#define NRF5340_BROADCAST_MODE 67*0c30abb2SDirk Helbig 6810277393SMatthias Ringwald // PTS mode 6910277393SMatthias Ringwald // #define PTS_MODE 7010277393SMatthias Ringwald 7110277393SMatthias Ringwald // Count mode - send packet count as test data for manual analysis 7210277393SMatthias Ringwald // #define COUNT_MODE 7310277393SMatthias Ringwald 7410277393SMatthias Ringwald // max config 7510277393SMatthias Ringwald #define MAX_NUM_BIS 2 7610277393SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480 773f485d09SMatthias Ringwald #define MAX_LC3_FRAME_BYTES 155 7810277393SMatthias Ringwald 7910277393SMatthias Ringwald static const uint8_t adv_sid = 0; 8010277393SMatthias Ringwald 8110277393SMatthias Ringwald static le_advertising_set_t le_advertising_set; 8210277393SMatthias Ringwald 83dcd1707aSDirk Helbig static le_extended_advertising_parameters_t extended_params = { 8410277393SMatthias Ringwald .advertising_event_properties = 0, 8510277393SMatthias Ringwald .primary_advertising_interval_min = 0x4b0, // 750 ms 8610277393SMatthias Ringwald .primary_advertising_interval_max = 0x4b0, // 750 ms 8710277393SMatthias Ringwald .primary_advertising_channel_map = 7, 88dcd1707aSDirk Helbig .own_address_type = BD_ADDR_TYPE_LE_PUBLIC, 8910277393SMatthias Ringwald .peer_address_type = 0, 90c52eeb3dSMatthias Ringwald .peer_address = { 0 }, 9110277393SMatthias Ringwald .advertising_filter_policy = 0, 9210277393SMatthias Ringwald .advertising_tx_power = 10, // 10 dBm 9310277393SMatthias Ringwald .primary_advertising_phy = 1, // LE 1M PHY 9410277393SMatthias Ringwald .secondary_advertising_max_skip = 0, 9510277393SMatthias Ringwald .secondary_advertising_phy = 1, // LE 1M PHY 9610277393SMatthias Ringwald .advertising_sid = adv_sid, 9710277393SMatthias Ringwald .scan_request_notification_enable = 0, 9810277393SMatthias Ringwald }; 9910277393SMatthias Ringwald 10070718632SMatthias Ringwald // Random Broadcast ID, valid for lifetime of BIG 10170718632SMatthias Ringwald #define BROADCAST_ID (0x112233u) 10270718632SMatthias Ringwald 10310277393SMatthias Ringwald static const uint8_t extended_adv_data[] = { 10410277393SMatthias Ringwald // 16 bit service data, ORG_BLUETOOTH_SERVICE_BASIC_AUDIO_ANNOUNCEMENT_SERVICE, Broadcast ID 10570718632SMatthias Ringwald 6, BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID, 0x52, 0x18, 10670718632SMatthias Ringwald BROADCAST_ID >> 16, 10770718632SMatthias Ringwald (BROADCAST_ID >> 8) & 0xff, 10870718632SMatthias Ringwald BROADCAST_ID & 0xff, 10910277393SMatthias Ringwald // name 11010277393SMatthias Ringwald #ifdef PTS_MODE 111*0c30abb2SDirk Helbig 7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'P', 'T', 'S', '-', 'x', 'x', 112*0c30abb2SDirk Helbig 7, BLUETOOTH_DATA_TYPE_BROADCAST_NAME , 'P', 'T', 'S', '-', 'x', 'x', 11310277393SMatthias Ringwald #elif defined(COUNT_MODE) 114*0c30abb2SDirk Helbig 6, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'C', 'O', 'U', 'N', 'T', 115*0c30abb2SDirk Helbig 6, BLUETOOTH_DATA_TYPE_BROADCAST_NAME, 'C', 'O', 'U', 'N', 'T', 116*0c30abb2SDirk Helbig #elif defined(NRF5340_BROADCAST_MODE) 117*0c30abb2SDirk Helbig 20, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'N','R','F','5','3','4','0','_','B','R','O','A','D','C','A','S','T','E','R', 118*0c30abb2SDirk Helbig 20, BLUETOOTH_DATA_TYPE_BROADCAST_NAME, 'N','R','F','5','3','4','0','_','B','R','O','A','D','C','A','S','T','E','R', 11910277393SMatthias Ringwald #else 120*0c30abb2SDirk Helbig 7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'S', 'o', 'u', 'r', 'c', 'e', 121*0c30abb2SDirk Helbig 7, BLUETOOTH_DATA_TYPE_BROADCAST_NAME, 'S', 'o', 'u', 'r', 'c', 'e', 12210277393SMatthias Ringwald #endif 12310277393SMatthias Ringwald }; 12410277393SMatthias Ringwald 12510277393SMatthias Ringwald static const le_periodic_advertising_parameters_t periodic_params = { 12610277393SMatthias Ringwald .periodic_advertising_interval_min = 0x258, // 375 ms 12710277393SMatthias Ringwald .periodic_advertising_interval_max = 0x258, // 375 ms 12810277393SMatthias Ringwald .periodic_advertising_properties = 0 12910277393SMatthias Ringwald }; 13010277393SMatthias Ringwald 13110277393SMatthias Ringwald static bd_addr_t remote; 13210277393SMatthias Ringwald static const char * remote_addr_string = "00:1B:DC:08:E2:72"; 13310277393SMatthias Ringwald 13410277393SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 1354a06e23fSMatthias Ringwald static uint8_t period_adv_data[255]; 1364a06e23fSMatthias Ringwald static uint16_t period_adv_data_len; 13710277393SMatthias Ringwald 13810277393SMatthias Ringwald static uint8_t adv_handle = 0; 13910277393SMatthias Ringwald static unsigned int next_bis_index; 14010277393SMatthias Ringwald static hci_con_handle_t bis_con_handles[MAX_NUM_BIS]; 14110277393SMatthias Ringwald static uint16_t packet_sequence_numbers[MAX_NUM_BIS]; 14210277393SMatthias Ringwald static uint8_t framed_pdus; 14310277393SMatthias Ringwald static bool bis_can_send[MAX_NUM_BIS]; 14410277393SMatthias Ringwald static bool bis_has_data[MAX_NUM_BIS]; 14510277393SMatthias Ringwald static uint8_t iso_frame_counter; 14610277393SMatthias Ringwald static uint16_t frame_duration_us; 14710277393SMatthias Ringwald 148cd0bedb1SMatthias Ringwald static le_audio_big_t big_storage; 149cd0bedb1SMatthias Ringwald static le_audio_big_params_t big_params; 150cd0bedb1SMatthias Ringwald 15110277393SMatthias Ringwald // time stamping 15210277393SMatthias Ringwald #ifdef COUNT_MODE 15310277393SMatthias Ringwald #define MAX_PACKET_INTERVAL_BINS_MS 50 15410277393SMatthias Ringwald static uint32_t send_time_bins[MAX_PACKET_INTERVAL_BINS_MS]; 15510277393SMatthias Ringwald static uint32_t send_last_ms; 15610277393SMatthias Ringwald #endif 15710277393SMatthias Ringwald 15810277393SMatthias Ringwald // lc3 codec config 159c52eeb3dSMatthias Ringwald static uint16_t sampling_frequency_hz; 1602fd68da2SMatthias Ringwald static btstack_lc3_frame_duration_t frame_duration; 16110277393SMatthias Ringwald static uint16_t number_samples_per_frame; 16210277393SMatthias Ringwald static uint16_t octets_per_frame; 16310277393SMatthias Ringwald static uint8_t num_bis = 1; 16410277393SMatthias Ringwald 16510277393SMatthias Ringwald // codec menu 16610277393SMatthias Ringwald static uint8_t menu_sampling_frequency; 16710277393SMatthias Ringwald static uint8_t menu_variant; 16810277393SMatthias Ringwald 169ac95ea81SMatthias Ringwald // encryption 170ac95ea81SMatthias Ringwald static uint8_t encryption = 0; 171166aee19SMatthias Ringwald static uint8_t broadcast_code [] = {0x01, 0x02, 0x68, 0x05, 0x53, 0xF1, 0x41, 0x5A, 0xA2, 0x65, 0xBB, 0xAF, 0xC6, 0xEA, 0x03, 0xB8, }; 172ac95ea81SMatthias Ringwald 17310277393SMatthias Ringwald // audio producer 174*0c30abb2SDirk Helbig #ifdef COUNT_MODE 175*0c30abb2SDirk Helbig static le_audio_demo_source_generator audio_source = AUDIO_SOURCE_COUNTER; 176*0c30abb2SDirk Helbig #else 177bb81690eSMatthias Ringwald static le_audio_demo_source_generator audio_source = AUDIO_SOURCE_MODPLAYER; 178*0c30abb2SDirk Helbig #endif 17910277393SMatthias Ringwald 18010277393SMatthias Ringwald static enum { 18110277393SMatthias Ringwald APP_IDLE, 18210277393SMatthias Ringwald APP_W4_CREATE_BIG_COMPLETE, 183b9b9e477SMatthias Ringwald APP_STREAMING, 18410277393SMatthias Ringwald } app_state = APP_IDLE; 18510277393SMatthias Ringwald 18610277393SMatthias Ringwald // enumerate default codec configs 18710277393SMatthias Ringwald static struct { 188c52eeb3dSMatthias Ringwald uint16_t samplingrate_hz; 18910277393SMatthias Ringwald uint8_t samplingrate_index; 19010277393SMatthias Ringwald uint8_t num_variants; 19110277393SMatthias Ringwald struct { 19210277393SMatthias Ringwald const char * name; 1932fd68da2SMatthias Ringwald btstack_lc3_frame_duration_t frame_duration; 19410277393SMatthias Ringwald uint16_t octets_per_frame; 19510277393SMatthias Ringwald } variants[6]; 19610277393SMatthias Ringwald } codec_configurations[] = { 19710277393SMatthias Ringwald { 19810277393SMatthias Ringwald 8000, 0x01, 2, 19910277393SMatthias Ringwald { 2002fd68da2SMatthias Ringwald { "8_1", BTSTACK_LC3_FRAME_DURATION_7500US, 26}, 2012fd68da2SMatthias Ringwald { "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30} 20210277393SMatthias Ringwald } 20310277393SMatthias Ringwald }, 20410277393SMatthias Ringwald { 20510277393SMatthias Ringwald 16000, 0x03, 2, 20610277393SMatthias Ringwald { 2072fd68da2SMatthias Ringwald { "16_1", BTSTACK_LC3_FRAME_DURATION_7500US, 30}, 2082fd68da2SMatthias Ringwald { "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40} 20910277393SMatthias Ringwald } 21010277393SMatthias Ringwald }, 21110277393SMatthias Ringwald { 21210277393SMatthias Ringwald 24000, 0x05, 2, 21310277393SMatthias Ringwald { 2142fd68da2SMatthias Ringwald { "24_1", BTSTACK_LC3_FRAME_DURATION_7500US, 45}, 2152fd68da2SMatthias Ringwald { "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60} 21610277393SMatthias Ringwald } 21710277393SMatthias Ringwald }, 21810277393SMatthias Ringwald { 21910277393SMatthias Ringwald 32000, 0x06, 2, 22010277393SMatthias Ringwald { 2212fd68da2SMatthias Ringwald { "32_1", BTSTACK_LC3_FRAME_DURATION_7500US, 60}, 2222fd68da2SMatthias Ringwald { "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80} 22310277393SMatthias Ringwald } 22410277393SMatthias Ringwald }, 22510277393SMatthias Ringwald { 22610277393SMatthias Ringwald 44100, 0x07, 2, 22710277393SMatthias Ringwald { 2282fd68da2SMatthias Ringwald { "441_1", BTSTACK_LC3_FRAME_DURATION_7500US, 97}, 2292fd68da2SMatthias Ringwald { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130} 23010277393SMatthias Ringwald } 23110277393SMatthias Ringwald }, 23210277393SMatthias Ringwald { 23310277393SMatthias Ringwald 48000, 0x08, 6, 23410277393SMatthias Ringwald { 2352fd68da2SMatthias Ringwald { "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75}, 2362fd68da2SMatthias Ringwald { "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100}, 2372fd68da2SMatthias Ringwald { "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90}, 2382fd68da2SMatthias Ringwald { "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120}, 2392fd68da2SMatthias Ringwald { "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117}, 2402fd68da2SMatthias Ringwald { "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155} 24110277393SMatthias Ringwald } 24210277393SMatthias Ringwald }, 24310277393SMatthias Ringwald }; 24410277393SMatthias Ringwald 24510277393SMatthias Ringwald static void show_usage(void); 24610277393SMatthias Ringwald 24710277393SMatthias Ringwald static void print_config(void) { 248ac95ea81SMatthias Ringwald printf("Config '%s_%u': %u, %s ms, %u octets - %s%s\n", 24910277393SMatthias Ringwald codec_configurations[menu_sampling_frequency].variants[menu_variant].name, 25010277393SMatthias Ringwald num_bis, 25110277393SMatthias Ringwald codec_configurations[menu_sampling_frequency].samplingrate_hz, 2522fd68da2SMatthias Ringwald codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10", 25310277393SMatthias Ringwald codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame, 254ac95ea81SMatthias Ringwald audio_source == AUDIO_SOURCE_SINE ? "Sine" : "Modplayer", encryption ? " (encrypted)" : ""); 25510277393SMatthias Ringwald } 25610277393SMatthias Ringwald 25744959aebSMatthias Ringwald static void setup_advertising() { 258dcd1707aSDirk Helbig bd_addr_t local_addr; 259dcd1707aSDirk Helbig gap_local_bd_addr(local_addr); 2606d708481SDirk Helbig bool local_address_invalid = btstack_is_null_bd_addr( local_addr ); 261dcd1707aSDirk Helbig if( local_address_invalid ) { 262dcd1707aSDirk Helbig extended_params.own_address_type = BD_ADDR_TYPE_LE_RANDOM; 263dcd1707aSDirk Helbig } 26444959aebSMatthias Ringwald gap_extended_advertising_setup(&le_advertising_set, &extended_params, &adv_handle); 265dcd1707aSDirk Helbig if( local_address_invalid ) { 266dcd1707aSDirk Helbig bd_addr_t random_address = { 0xC1, 0x01, 0x01, 0x01, 0x01, 0x01 }; 267dcd1707aSDirk Helbig gap_extended_advertising_set_random_address( adv_handle, random_address ); 268dcd1707aSDirk Helbig } 26944959aebSMatthias Ringwald gap_extended_advertising_set_adv_data(adv_handle, sizeof(extended_adv_data), extended_adv_data); 27044959aebSMatthias Ringwald gap_periodic_advertising_set_params(adv_handle, &periodic_params); 2714a06e23fSMatthias Ringwald gap_periodic_advertising_set_data(adv_handle, period_adv_data_len, period_adv_data); 27244959aebSMatthias Ringwald gap_periodic_advertising_start(adv_handle, 0); 27344959aebSMatthias Ringwald gap_extended_advertising_start(adv_handle, 0, 0); 27444959aebSMatthias Ringwald } 27544959aebSMatthias Ringwald 27644959aebSMatthias Ringwald static void setup_big(void){ 277cd0bedb1SMatthias Ringwald // Create BIG 278cd0bedb1SMatthias Ringwald big_params.big_handle = 0; 279cd0bedb1SMatthias Ringwald big_params.advertising_handle = adv_handle; 280cd0bedb1SMatthias Ringwald big_params.num_bis = num_bis; 281cd0bedb1SMatthias Ringwald big_params.max_sdu = octets_per_frame; 282cd0bedb1SMatthias Ringwald big_params.max_transport_latency_ms = 31; 283cd0bedb1SMatthias Ringwald big_params.rtn = 2; 284cd0bedb1SMatthias Ringwald big_params.phy = 2; 285cd0bedb1SMatthias Ringwald big_params.packing = 0; 286ac95ea81SMatthias Ringwald big_params.encryption = encryption; 287ac95ea81SMatthias Ringwald if (encryption) { 288ac95ea81SMatthias Ringwald memcpy(big_params.broadcast_code, &broadcast_code[0], 16); 289ac95ea81SMatthias Ringwald } else { 290cd0bedb1SMatthias Ringwald memset(big_params.broadcast_code, 0, 16); 291ac95ea81SMatthias Ringwald } 292cd0bedb1SMatthias Ringwald if (sampling_frequency_hz == 44100){ 293cd0bedb1SMatthias Ringwald // same config as for 48k -> frame is longer by 48/44.1 294cd0bedb1SMatthias Ringwald big_params.sdu_interval_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8163 : 10884; 295cd0bedb1SMatthias Ringwald big_params.framing = 1; 296cd0bedb1SMatthias Ringwald } else { 297cd0bedb1SMatthias Ringwald big_params.sdu_interval_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 7500 : 10000; 298cd0bedb1SMatthias Ringwald big_params.framing = 0; 299cd0bedb1SMatthias Ringwald } 300cd0bedb1SMatthias Ringwald app_state = APP_W4_CREATE_BIG_COMPLETE; 301cd0bedb1SMatthias Ringwald gap_big_create(&big_storage, &big_params); 302cd0bedb1SMatthias Ringwald } 303cd0bedb1SMatthias Ringwald 30456c77a86SMatthias Ringwald 30556c77a86SMatthias Ringwald static void start_broadcast() {// use values from table 30656c77a86SMatthias Ringwald sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz; 30756c77a86SMatthias Ringwald octets_per_frame = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame; 30856c77a86SMatthias Ringwald frame_duration = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration; 30956c77a86SMatthias Ringwald 310bb81690eSMatthias Ringwald number_samples_per_frame = btstack_lc3_samples_per_frame(sampling_frequency_hz, frame_duration); 311bb81690eSMatthias Ringwald 312bb81690eSMatthias Ringwald printf("LC3 Encoder config: %u hz, frame duration %s ms, num samples %u, num octets %u\n", 313bb81690eSMatthias Ringwald sampling_frequency_hz, frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10", 314bb81690eSMatthias Ringwald number_samples_per_frame, octets_per_frame); 315bb81690eSMatthias Ringwald 316bb81690eSMatthias Ringwald le_audio_demo_util_source_configure(num_bis, 1, sampling_frequency_hz, frame_duration, octets_per_frame); 317bb81690eSMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(audio_source); 31856c77a86SMatthias Ringwald 3194a06e23fSMatthias Ringwald // setup base 3204a06e23fSMatthias Ringwald uint8_t codec_id[] = { 0x06, 0x00, 0x00, 0x00, 0x00 }; 3214a06e23fSMatthias Ringwald uint8_t subgroup_codec_specific_configuration[] = { 3224a06e23fSMatthias Ringwald 0x02, 0x01, 0x01, 3234a06e23fSMatthias Ringwald 0x02, 0x02, 0x01, 3244a06e23fSMatthias Ringwald 0x03, 0x04, 0x1E, 0x00, 3254a06e23fSMatthias Ringwald }; 3264a06e23fSMatthias Ringwald subgroup_codec_specific_configuration[2] = codec_configurations[menu_sampling_frequency].samplingrate_index; 3274a06e23fSMatthias Ringwald subgroup_codec_specific_configuration[5] = (frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US) ? 0 : 1;; 3284a06e23fSMatthias Ringwald uint8_t subgroup_metadata[] = { 3294a06e23fSMatthias Ringwald 0x03, 0x02, 0x04, 0x00, // Metadata[i] 3304a06e23fSMatthias Ringwald }; 3314a06e23fSMatthias Ringwald little_endian_store_16(subgroup_codec_specific_configuration, 8, octets_per_frame); 3324a06e23fSMatthias Ringwald uint8_t bis_codec_specific_configuration_1[] = { 3334a06e23fSMatthias Ringwald 0x05, 0x03, 0x01, 0x00, 0x00, 0x00 3344a06e23fSMatthias Ringwald }; 3354a06e23fSMatthias Ringwald uint8_t bis_codec_specific_configuration_2[] = { 3364a06e23fSMatthias Ringwald 0x05, 0x03, 0x02, 0x00, 0x00, 0x00 3374a06e23fSMatthias Ringwald }; 3380f7e8caeSMatthias Ringwald le_audio_base_builder_t builder; 339*0c30abb2SDirk Helbig le_audio_base_builder_init(&builder, period_adv_data, sizeof(period_adv_data), 20000); 3404a06e23fSMatthias Ringwald le_audio_base_builder_add_subgroup(&builder, codec_id, 3414a06e23fSMatthias Ringwald sizeof(subgroup_codec_specific_configuration), 3424a06e23fSMatthias Ringwald subgroup_codec_specific_configuration, 3434a06e23fSMatthias Ringwald sizeof(subgroup_metadata), subgroup_metadata); 3444a06e23fSMatthias Ringwald le_audio_base_builder_add_bis(&builder, 1, sizeof(bis_codec_specific_configuration_1), 3454a06e23fSMatthias Ringwald bis_codec_specific_configuration_1); 3464a06e23fSMatthias Ringwald if (num_bis == 2){ 3474a06e23fSMatthias Ringwald le_audio_base_builder_add_bis(&builder, 2, sizeof(bis_codec_specific_configuration_2), 3484a06e23fSMatthias Ringwald bis_codec_specific_configuration_2); 3494a06e23fSMatthias Ringwald } 3504a06e23fSMatthias Ringwald period_adv_data_len = le_audio_base_builder_get_ad_data_size(&builder); 35156c77a86SMatthias Ringwald 35256c77a86SMatthias Ringwald // setup extended and periodic advertising 35356c77a86SMatthias Ringwald setup_advertising(); 35456c77a86SMatthias Ringwald 35556c77a86SMatthias Ringwald // setup big 35656c77a86SMatthias Ringwald setup_big(); 35756c77a86SMatthias Ringwald } 35856c77a86SMatthias Ringwald 35910277393SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 36010277393SMatthias Ringwald UNUSED(channel); 36110277393SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 3620be46310SMatthias Ringwald uint8_t bis_index; 36310277393SMatthias Ringwald 36410277393SMatthias Ringwald switch (packet[0]) { 36510277393SMatthias Ringwald case BTSTACK_EVENT_STATE: 36610277393SMatthias Ringwald switch(btstack_event_state_get_state(packet)) { 36710277393SMatthias Ringwald case HCI_STATE_WORKING: 36856c77a86SMatthias Ringwald #ifdef ENABLE_DEMO_MODE 36956c77a86SMatthias Ringwald // start broadcast automatically, mod player, 48_5_1 37056c77a86SMatthias Ringwald num_bis = 1; 37156c77a86SMatthias Ringwald menu_sampling_frequency = 5; 37256c77a86SMatthias Ringwald menu_variant = 4; 37356c77a86SMatthias Ringwald start_broadcast(); 374*0c30abb2SDirk Helbig #elif defined( NRF5340_BROADCAST_MODE ) 375*0c30abb2SDirk Helbig num_bis = 1; 376*0c30abb2SDirk Helbig menu_sampling_frequency = 5; 377*0c30abb2SDirk Helbig menu_variant = 1; 37856c77a86SMatthias Ringwald #else 37910277393SMatthias Ringwald show_usage(); 38010277393SMatthias Ringwald printf("Please select sample frequency and variation, then start broadcast\n"); 38156c77a86SMatthias Ringwald #endif 38210277393SMatthias Ringwald break; 38310277393SMatthias Ringwald case HCI_STATE_OFF: 38410277393SMatthias Ringwald printf("Goodbye\n"); 38510277393SMatthias Ringwald exit(0); 38610277393SMatthias Ringwald break; 38710277393SMatthias Ringwald default: 38810277393SMatthias Ringwald break; 38910277393SMatthias Ringwald } 39010277393SMatthias Ringwald break; 391cd0bedb1SMatthias Ringwald case HCI_EVENT_META_GAP: 392cd0bedb1SMatthias Ringwald switch (hci_event_gap_meta_get_subevent_code(packet)){ 3930be46310SMatthias Ringwald case GAP_SUBEVENT_BIG_CREATED: 394cd0bedb1SMatthias Ringwald printf("BIG Created with BIS Connection handles: \n"); 3950be46310SMatthias Ringwald for (bis_index=0;bis_index<num_bis;bis_index++){ 3960be46310SMatthias Ringwald bis_con_handles[bis_index] = gap_subevent_big_created_get_bis_con_handles(packet, bis_index); 3970be46310SMatthias Ringwald printf("0x%04x ", bis_con_handles[bis_index]); 39810277393SMatthias Ringwald } 39944959aebSMatthias Ringwald 400cd0bedb1SMatthias Ringwald app_state = APP_STREAMING; 40110277393SMatthias Ringwald printf("Start streaming\n"); 4020be46310SMatthias Ringwald hci_request_bis_can_send_now_events(big_params.big_handle); 40310277393SMatthias Ringwald break; 40410277393SMatthias Ringwald default: 40510277393SMatthias Ringwald break; 40610277393SMatthias Ringwald } 40710277393SMatthias Ringwald break; 4080be46310SMatthias Ringwald case HCI_EVENT_BIS_CAN_SEND_NOW: 4090d718107SMatthias Ringwald bis_index = hci_event_bis_can_send_now_get_bis_index(packet); 410bb81690eSMatthias Ringwald le_audio_demo_util_source_send(bis_index, bis_con_handles[bis_index]); 4110be46310SMatthias Ringwald bis_index++; 4120be46310SMatthias Ringwald if (bis_index == num_bis){ 413bb81690eSMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(audio_source); 4140be46310SMatthias Ringwald hci_request_bis_can_send_now_events(big_params.big_handle); 41510277393SMatthias Ringwald } 41610277393SMatthias Ringwald break; 41710277393SMatthias Ringwald default: 41810277393SMatthias Ringwald break; 41910277393SMatthias Ringwald } 42010277393SMatthias Ringwald } 42110277393SMatthias Ringwald 42210277393SMatthias Ringwald static void show_usage(void){ 42310277393SMatthias Ringwald printf("\n--- LE Audio Broadcast Source Test Console ---\n"); 42410277393SMatthias Ringwald print_config(); 42510277393SMatthias Ringwald printf("---\n"); 42610277393SMatthias Ringwald printf("c - toggle channels\n"); 427ac95ea81SMatthias Ringwald printf("e - toggle encryption\n"); 42810277393SMatthias Ringwald printf("f - next sampling frequency\n"); 42910277393SMatthias Ringwald printf("v - next codec variant\n"); 43010277393SMatthias Ringwald printf("t - toggle sine / modplayer\n"); 43110277393SMatthias Ringwald printf("s - start broadcast\n"); 43210277393SMatthias Ringwald printf("---\n"); 43310277393SMatthias Ringwald } 43410277393SMatthias Ringwald static void stdin_process(char c){ 43510277393SMatthias Ringwald switch (c){ 43610277393SMatthias Ringwald case 'c': 43710277393SMatthias Ringwald if (app_state != APP_IDLE){ 43810277393SMatthias Ringwald printf("Codec configuration can only be changed in idle state\n"); 43910277393SMatthias Ringwald break; 44010277393SMatthias Ringwald } 44110277393SMatthias Ringwald num_bis = 3 - num_bis; 44210277393SMatthias Ringwald print_config(); 44310277393SMatthias Ringwald break; 444ac95ea81SMatthias Ringwald case 'e': 445ac95ea81SMatthias Ringwald if (app_state != APP_IDLE){ 446ac95ea81SMatthias Ringwald printf("Encryption can only be changed in idle state\n"); 447ac95ea81SMatthias Ringwald break; 448ac95ea81SMatthias Ringwald } 449ac95ea81SMatthias Ringwald encryption = 1 - encryption; 450ac95ea81SMatthias Ringwald print_config(); 451ac95ea81SMatthias Ringwald break; 45210277393SMatthias Ringwald case 'f': 45310277393SMatthias Ringwald if (app_state != APP_IDLE){ 45410277393SMatthias Ringwald printf("Codec configuration can only be changed in idle state\n"); 45510277393SMatthias Ringwald break; 45610277393SMatthias Ringwald } 45710277393SMatthias Ringwald menu_sampling_frequency++; 45810277393SMatthias Ringwald if (menu_sampling_frequency >= 6){ 45910277393SMatthias Ringwald menu_sampling_frequency = 0; 46010277393SMatthias Ringwald } 46110277393SMatthias Ringwald if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){ 46210277393SMatthias Ringwald menu_variant = 0; 46310277393SMatthias Ringwald } 46410277393SMatthias Ringwald print_config(); 46510277393SMatthias Ringwald break; 46610277393SMatthias Ringwald case 'v': 46710277393SMatthias Ringwald if (app_state != APP_IDLE){ 46810277393SMatthias Ringwald printf("Codec configuration can only be changed in idle state\n"); 46910277393SMatthias Ringwald break; 47010277393SMatthias Ringwald } 47110277393SMatthias Ringwald menu_variant++; 47210277393SMatthias Ringwald if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){ 47310277393SMatthias Ringwald menu_variant = 0; 47410277393SMatthias Ringwald } 47510277393SMatthias Ringwald print_config(); 47610277393SMatthias Ringwald break; 47710277393SMatthias Ringwald case 's': 47810277393SMatthias Ringwald if (app_state != APP_IDLE){ 47910277393SMatthias Ringwald printf("Cannot start broadcast - not in idle state\n"); 48010277393SMatthias Ringwald break; 48110277393SMatthias Ringwald } 48256c77a86SMatthias Ringwald start_broadcast(); 48310277393SMatthias Ringwald break; 48410277393SMatthias Ringwald case 't': 485d352c98fSMatthias Ringwald switch (audio_source){ 486d352c98fSMatthias Ringwald case AUDIO_SOURCE_MODPLAYER: 487d352c98fSMatthias Ringwald audio_source = AUDIO_SOURCE_SINE; 488d352c98fSMatthias Ringwald break; 489d352c98fSMatthias Ringwald case AUDIO_SOURCE_SINE: 490d352c98fSMatthias Ringwald audio_source = AUDIO_SOURCE_MODPLAYER; 491d352c98fSMatthias Ringwald break; 492d352c98fSMatthias Ringwald default: 493d352c98fSMatthias Ringwald btstack_unreachable(); 494d352c98fSMatthias Ringwald break; 495d352c98fSMatthias Ringwald } 49610277393SMatthias Ringwald print_config(); 49710277393SMatthias Ringwald break; 49810277393SMatthias Ringwald case '\n': 49910277393SMatthias Ringwald case '\r': 50010277393SMatthias Ringwald break; 50110277393SMatthias Ringwald default: 50210277393SMatthias Ringwald show_usage(); 50310277393SMatthias Ringwald break; 50410277393SMatthias Ringwald } 50510277393SMatthias Ringwald } 50610277393SMatthias Ringwald 50710277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]); 50810277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 50910277393SMatthias Ringwald (void) argv; 51010277393SMatthias Ringwald (void) argc; 51110277393SMatthias Ringwald 51210277393SMatthias Ringwald // register for HCI events 51310277393SMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 51410277393SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 51510277393SMatthias Ringwald 516bb81690eSMatthias Ringwald // setup audio processing 517bb81690eSMatthias Ringwald le_audio_demo_util_source_init(); 518bb81690eSMatthias Ringwald 51910277393SMatthias Ringwald // turn on! 52010277393SMatthias Ringwald hci_power_control(HCI_POWER_ON); 52110277393SMatthias Ringwald 52210277393SMatthias Ringwald btstack_stdin_setup(stdin_process); 52310277393SMatthias Ringwald return 0; 52410277393SMatthias Ringwald } 525