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 6510277393SMatthias Ringwald // PTS mode 6610277393SMatthias Ringwald // #define PTS_MODE 6710277393SMatthias Ringwald 6810277393SMatthias Ringwald // Count mode - send packet count as test data for manual analysis 6910277393SMatthias Ringwald // #define COUNT_MODE 7010277393SMatthias Ringwald 7110277393SMatthias Ringwald // max config 7210277393SMatthias Ringwald #define MAX_NUM_BIS 2 7310277393SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480 743f485d09SMatthias Ringwald #define MAX_LC3_FRAME_BYTES 155 7510277393SMatthias Ringwald 7610277393SMatthias Ringwald static const uint8_t adv_sid = 0; 7710277393SMatthias Ringwald 7810277393SMatthias Ringwald static le_advertising_set_t le_advertising_set; 7910277393SMatthias Ringwald 80dcd1707aSDirk Helbig static le_extended_advertising_parameters_t extended_params = { 8110277393SMatthias Ringwald .advertising_event_properties = 0, 8210277393SMatthias Ringwald .primary_advertising_interval_min = 0x4b0, // 750 ms 8310277393SMatthias Ringwald .primary_advertising_interval_max = 0x4b0, // 750 ms 8410277393SMatthias Ringwald .primary_advertising_channel_map = 7, 85dcd1707aSDirk Helbig .own_address_type = BD_ADDR_TYPE_LE_PUBLIC, 8610277393SMatthias Ringwald .peer_address_type = 0, 87c52eeb3dSMatthias Ringwald .peer_address = { 0 }, 8810277393SMatthias Ringwald .advertising_filter_policy = 0, 8910277393SMatthias Ringwald .advertising_tx_power = 10, // 10 dBm 9010277393SMatthias Ringwald .primary_advertising_phy = 1, // LE 1M PHY 9110277393SMatthias Ringwald .secondary_advertising_max_skip = 0, 9210277393SMatthias Ringwald .secondary_advertising_phy = 1, // LE 1M PHY 9310277393SMatthias Ringwald .advertising_sid = adv_sid, 9410277393SMatthias Ringwald .scan_request_notification_enable = 0, 9510277393SMatthias Ringwald }; 9610277393SMatthias Ringwald 9770718632SMatthias Ringwald // Random Broadcast ID, valid for lifetime of BIG 9870718632SMatthias Ringwald #define BROADCAST_ID (0x112233u) 9970718632SMatthias Ringwald 10010277393SMatthias Ringwald static const uint8_t extended_adv_data[] = { 10110277393SMatthias Ringwald // 16 bit service data, ORG_BLUETOOTH_SERVICE_BASIC_AUDIO_ANNOUNCEMENT_SERVICE, Broadcast ID 10270718632SMatthias Ringwald 6, BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID, 0x52, 0x18, 10370718632SMatthias Ringwald BROADCAST_ID >> 16, 10470718632SMatthias Ringwald (BROADCAST_ID >> 8) & 0xff, 10570718632SMatthias Ringwald BROADCAST_ID & 0xff, 10610277393SMatthias Ringwald // name 10710277393SMatthias Ringwald #ifdef PTS_MODE 10810277393SMatthias Ringwald 7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'P', 'T', 'S', '-', 'x', 'x' 10910277393SMatthias Ringwald #elif defined(COUNT_MODE) 11010277393SMatthias Ringwald 6, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'C', 'O', 'U', 'N', 'T' 11110277393SMatthias Ringwald #else 11210277393SMatthias Ringwald 7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'S', 'o', 'u', 'r', 'c', 'e' 11310277393SMatthias Ringwald #endif 11410277393SMatthias Ringwald }; 11510277393SMatthias Ringwald 11610277393SMatthias Ringwald static const le_periodic_advertising_parameters_t periodic_params = { 11710277393SMatthias Ringwald .periodic_advertising_interval_min = 0x258, // 375 ms 11810277393SMatthias Ringwald .periodic_advertising_interval_max = 0x258, // 375 ms 11910277393SMatthias Ringwald .periodic_advertising_properties = 0 12010277393SMatthias Ringwald }; 12110277393SMatthias Ringwald 12210277393SMatthias Ringwald static bd_addr_t remote; 12310277393SMatthias Ringwald static const char * remote_addr_string = "00:1B:DC:08:E2:72"; 12410277393SMatthias Ringwald 12510277393SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 1264a06e23fSMatthias Ringwald static uint8_t period_adv_data[255]; 1274a06e23fSMatthias Ringwald static uint16_t period_adv_data_len; 12810277393SMatthias Ringwald 12910277393SMatthias Ringwald static uint8_t adv_handle = 0; 13010277393SMatthias Ringwald static unsigned int next_bis_index; 13110277393SMatthias Ringwald static hci_con_handle_t bis_con_handles[MAX_NUM_BIS]; 13210277393SMatthias Ringwald static uint16_t packet_sequence_numbers[MAX_NUM_BIS]; 13310277393SMatthias Ringwald static uint8_t framed_pdus; 13410277393SMatthias Ringwald static bool bis_can_send[MAX_NUM_BIS]; 13510277393SMatthias Ringwald static bool bis_has_data[MAX_NUM_BIS]; 13610277393SMatthias Ringwald static uint8_t iso_frame_counter; 13710277393SMatthias Ringwald static uint16_t frame_duration_us; 13810277393SMatthias Ringwald 139cd0bedb1SMatthias Ringwald static le_audio_big_t big_storage; 140cd0bedb1SMatthias Ringwald static le_audio_big_params_t big_params; 141cd0bedb1SMatthias Ringwald 14210277393SMatthias Ringwald // time stamping 14310277393SMatthias Ringwald #ifdef COUNT_MODE 14410277393SMatthias Ringwald #define MAX_PACKET_INTERVAL_BINS_MS 50 14510277393SMatthias Ringwald static uint32_t send_time_bins[MAX_PACKET_INTERVAL_BINS_MS]; 14610277393SMatthias Ringwald static uint32_t send_last_ms; 14710277393SMatthias Ringwald #endif 14810277393SMatthias Ringwald 14910277393SMatthias Ringwald // lc3 codec config 150c52eeb3dSMatthias Ringwald static uint16_t sampling_frequency_hz; 1512fd68da2SMatthias Ringwald static btstack_lc3_frame_duration_t frame_duration; 15210277393SMatthias Ringwald static uint16_t number_samples_per_frame; 15310277393SMatthias Ringwald static uint16_t octets_per_frame; 15410277393SMatthias Ringwald static uint8_t num_bis = 1; 15510277393SMatthias Ringwald 15610277393SMatthias Ringwald // codec menu 15710277393SMatthias Ringwald static uint8_t menu_sampling_frequency; 15810277393SMatthias Ringwald static uint8_t menu_variant; 15910277393SMatthias Ringwald 160ac95ea81SMatthias Ringwald // encryption 161ac95ea81SMatthias Ringwald static uint8_t encryption = 0; 162166aee19SMatthias Ringwald static uint8_t broadcast_code [] = {0x01, 0x02, 0x68, 0x05, 0x53, 0xF1, 0x41, 0x5A, 0xA2, 0x65, 0xBB, 0xAF, 0xC6, 0xEA, 0x03, 0xB8, }; 163ac95ea81SMatthias Ringwald 16410277393SMatthias Ringwald // audio producer 165bb81690eSMatthias Ringwald static le_audio_demo_source_generator audio_source = AUDIO_SOURCE_MODPLAYER; 16610277393SMatthias Ringwald 16710277393SMatthias Ringwald static enum { 16810277393SMatthias Ringwald APP_IDLE, 16910277393SMatthias Ringwald APP_W4_CREATE_BIG_COMPLETE, 170b9b9e477SMatthias Ringwald APP_STREAMING, 17110277393SMatthias Ringwald } app_state = APP_IDLE; 17210277393SMatthias Ringwald 17310277393SMatthias Ringwald // enumerate default codec configs 17410277393SMatthias Ringwald static struct { 175c52eeb3dSMatthias Ringwald uint16_t samplingrate_hz; 17610277393SMatthias Ringwald uint8_t samplingrate_index; 17710277393SMatthias Ringwald uint8_t num_variants; 17810277393SMatthias Ringwald struct { 17910277393SMatthias Ringwald const char * name; 1802fd68da2SMatthias Ringwald btstack_lc3_frame_duration_t frame_duration; 18110277393SMatthias Ringwald uint16_t octets_per_frame; 18210277393SMatthias Ringwald } variants[6]; 18310277393SMatthias Ringwald } codec_configurations[] = { 18410277393SMatthias Ringwald { 18510277393SMatthias Ringwald 8000, 0x01, 2, 18610277393SMatthias Ringwald { 1872fd68da2SMatthias Ringwald { "8_1", BTSTACK_LC3_FRAME_DURATION_7500US, 26}, 1882fd68da2SMatthias Ringwald { "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30} 18910277393SMatthias Ringwald } 19010277393SMatthias Ringwald }, 19110277393SMatthias Ringwald { 19210277393SMatthias Ringwald 16000, 0x03, 2, 19310277393SMatthias Ringwald { 1942fd68da2SMatthias Ringwald { "16_1", BTSTACK_LC3_FRAME_DURATION_7500US, 30}, 1952fd68da2SMatthias Ringwald { "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40} 19610277393SMatthias Ringwald } 19710277393SMatthias Ringwald }, 19810277393SMatthias Ringwald { 19910277393SMatthias Ringwald 24000, 0x05, 2, 20010277393SMatthias Ringwald { 2012fd68da2SMatthias Ringwald { "24_1", BTSTACK_LC3_FRAME_DURATION_7500US, 45}, 2022fd68da2SMatthias Ringwald { "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60} 20310277393SMatthias Ringwald } 20410277393SMatthias Ringwald }, 20510277393SMatthias Ringwald { 20610277393SMatthias Ringwald 32000, 0x06, 2, 20710277393SMatthias Ringwald { 2082fd68da2SMatthias Ringwald { "32_1", BTSTACK_LC3_FRAME_DURATION_7500US, 60}, 2092fd68da2SMatthias Ringwald { "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80} 21010277393SMatthias Ringwald } 21110277393SMatthias Ringwald }, 21210277393SMatthias Ringwald { 21310277393SMatthias Ringwald 44100, 0x07, 2, 21410277393SMatthias Ringwald { 2152fd68da2SMatthias Ringwald { "441_1", BTSTACK_LC3_FRAME_DURATION_7500US, 97}, 2162fd68da2SMatthias Ringwald { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130} 21710277393SMatthias Ringwald } 21810277393SMatthias Ringwald }, 21910277393SMatthias Ringwald { 22010277393SMatthias Ringwald 48000, 0x08, 6, 22110277393SMatthias Ringwald { 2222fd68da2SMatthias Ringwald { "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75}, 2232fd68da2SMatthias Ringwald { "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100}, 2242fd68da2SMatthias Ringwald { "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90}, 2252fd68da2SMatthias Ringwald { "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120}, 2262fd68da2SMatthias Ringwald { "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117}, 2272fd68da2SMatthias Ringwald { "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155} 22810277393SMatthias Ringwald } 22910277393SMatthias Ringwald }, 23010277393SMatthias Ringwald }; 23110277393SMatthias Ringwald 23210277393SMatthias Ringwald static void show_usage(void); 23310277393SMatthias Ringwald 23410277393SMatthias Ringwald static void print_config(void) { 235ac95ea81SMatthias Ringwald printf("Config '%s_%u': %u, %s ms, %u octets - %s%s\n", 23610277393SMatthias Ringwald codec_configurations[menu_sampling_frequency].variants[menu_variant].name, 23710277393SMatthias Ringwald num_bis, 23810277393SMatthias Ringwald codec_configurations[menu_sampling_frequency].samplingrate_hz, 2392fd68da2SMatthias Ringwald codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10", 24010277393SMatthias Ringwald codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame, 241ac95ea81SMatthias Ringwald audio_source == AUDIO_SOURCE_SINE ? "Sine" : "Modplayer", encryption ? " (encrypted)" : ""); 24210277393SMatthias Ringwald } 24310277393SMatthias Ringwald 24444959aebSMatthias Ringwald static void setup_advertising() { 245dcd1707aSDirk Helbig bd_addr_t local_addr; 246dcd1707aSDirk Helbig gap_local_bd_addr(local_addr); 2476d708481SDirk Helbig bool local_address_invalid = btstack_is_null_bd_addr( local_addr ); 248dcd1707aSDirk Helbig if( local_address_invalid ) { 249dcd1707aSDirk Helbig extended_params.own_address_type = BD_ADDR_TYPE_LE_RANDOM; 250dcd1707aSDirk Helbig } 25144959aebSMatthias Ringwald gap_extended_advertising_setup(&le_advertising_set, &extended_params, &adv_handle); 252dcd1707aSDirk Helbig if( local_address_invalid ) { 253dcd1707aSDirk Helbig bd_addr_t random_address = { 0xC1, 0x01, 0x01, 0x01, 0x01, 0x01 }; 254dcd1707aSDirk Helbig gap_extended_advertising_set_random_address( adv_handle, random_address ); 255dcd1707aSDirk Helbig } 25644959aebSMatthias Ringwald gap_extended_advertising_set_adv_data(adv_handle, sizeof(extended_adv_data), extended_adv_data); 25744959aebSMatthias Ringwald gap_periodic_advertising_set_params(adv_handle, &periodic_params); 2584a06e23fSMatthias Ringwald gap_periodic_advertising_set_data(adv_handle, period_adv_data_len, period_adv_data); 25944959aebSMatthias Ringwald gap_periodic_advertising_start(adv_handle, 0); 26044959aebSMatthias Ringwald gap_extended_advertising_start(adv_handle, 0, 0); 26144959aebSMatthias Ringwald } 26244959aebSMatthias Ringwald 26344959aebSMatthias Ringwald static void setup_big(void){ 264cd0bedb1SMatthias Ringwald // Create BIG 265cd0bedb1SMatthias Ringwald big_params.big_handle = 0; 266cd0bedb1SMatthias Ringwald big_params.advertising_handle = adv_handle; 267cd0bedb1SMatthias Ringwald big_params.num_bis = num_bis; 268cd0bedb1SMatthias Ringwald big_params.max_sdu = octets_per_frame; 269cd0bedb1SMatthias Ringwald big_params.max_transport_latency_ms = 31; 270cd0bedb1SMatthias Ringwald big_params.rtn = 2; 271cd0bedb1SMatthias Ringwald big_params.phy = 2; 272cd0bedb1SMatthias Ringwald big_params.packing = 0; 273ac95ea81SMatthias Ringwald big_params.encryption = encryption; 274ac95ea81SMatthias Ringwald if (encryption) { 275ac95ea81SMatthias Ringwald memcpy(big_params.broadcast_code, &broadcast_code[0], 16); 276ac95ea81SMatthias Ringwald } else { 277cd0bedb1SMatthias Ringwald memset(big_params.broadcast_code, 0, 16); 278ac95ea81SMatthias Ringwald } 279cd0bedb1SMatthias Ringwald if (sampling_frequency_hz == 44100){ 280cd0bedb1SMatthias Ringwald // same config as for 48k -> frame is longer by 48/44.1 281cd0bedb1SMatthias Ringwald big_params.sdu_interval_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8163 : 10884; 282cd0bedb1SMatthias Ringwald big_params.framing = 1; 283cd0bedb1SMatthias Ringwald } else { 284cd0bedb1SMatthias Ringwald big_params.sdu_interval_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 7500 : 10000; 285cd0bedb1SMatthias Ringwald big_params.framing = 0; 286cd0bedb1SMatthias Ringwald } 287cd0bedb1SMatthias Ringwald app_state = APP_W4_CREATE_BIG_COMPLETE; 288cd0bedb1SMatthias Ringwald gap_big_create(&big_storage, &big_params); 289cd0bedb1SMatthias Ringwald } 290cd0bedb1SMatthias Ringwald 29156c77a86SMatthias Ringwald 29256c77a86SMatthias Ringwald static void start_broadcast() {// use values from table 29356c77a86SMatthias Ringwald sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz; 29456c77a86SMatthias Ringwald octets_per_frame = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame; 29556c77a86SMatthias Ringwald frame_duration = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration; 29656c77a86SMatthias Ringwald 297bb81690eSMatthias Ringwald number_samples_per_frame = btstack_lc3_samples_per_frame(sampling_frequency_hz, frame_duration); 298bb81690eSMatthias Ringwald 299bb81690eSMatthias Ringwald printf("LC3 Encoder config: %u hz, frame duration %s ms, num samples %u, num octets %u\n", 300bb81690eSMatthias Ringwald sampling_frequency_hz, frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10", 301bb81690eSMatthias Ringwald number_samples_per_frame, octets_per_frame); 302bb81690eSMatthias Ringwald 303bb81690eSMatthias Ringwald le_audio_demo_util_source_configure(num_bis, 1, sampling_frequency_hz, frame_duration, octets_per_frame); 304bb81690eSMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(audio_source); 30556c77a86SMatthias Ringwald 3064a06e23fSMatthias Ringwald // setup base 3074a06e23fSMatthias Ringwald uint8_t codec_id[] = { 0x06, 0x00, 0x00, 0x00, 0x00 }; 3084a06e23fSMatthias Ringwald uint8_t subgroup_codec_specific_configuration[] = { 3094a06e23fSMatthias Ringwald 0x02, 0x01, 0x01, 3104a06e23fSMatthias Ringwald 0x02, 0x02, 0x01, 3114a06e23fSMatthias Ringwald 0x03, 0x04, 0x1E, 0x00, 3124a06e23fSMatthias Ringwald }; 3134a06e23fSMatthias Ringwald subgroup_codec_specific_configuration[2] = codec_configurations[menu_sampling_frequency].samplingrate_index; 3144a06e23fSMatthias Ringwald subgroup_codec_specific_configuration[5] = (frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US) ? 0 : 1;; 3154a06e23fSMatthias Ringwald uint8_t subgroup_metadata[] = { 3164a06e23fSMatthias Ringwald 0x03, 0x02, 0x04, 0x00, // Metadata[i] 3174a06e23fSMatthias Ringwald }; 3184a06e23fSMatthias Ringwald little_endian_store_16(subgroup_codec_specific_configuration, 8, octets_per_frame); 3194a06e23fSMatthias Ringwald uint8_t bis_codec_specific_configuration_1[] = { 3204a06e23fSMatthias Ringwald 0x05, 0x03, 0x01, 0x00, 0x00, 0x00 3214a06e23fSMatthias Ringwald }; 3224a06e23fSMatthias Ringwald uint8_t bis_codec_specific_configuration_2[] = { 3234a06e23fSMatthias Ringwald 0x05, 0x03, 0x02, 0x00, 0x00, 0x00 3244a06e23fSMatthias Ringwald }; 3250f7e8caeSMatthias Ringwald le_audio_base_builder_t builder; 3264a06e23fSMatthias Ringwald le_audio_base_builder_init(&builder, period_adv_data, sizeof(period_adv_data), 40); 3274a06e23fSMatthias Ringwald le_audio_base_builder_add_subgroup(&builder, codec_id, 3284a06e23fSMatthias Ringwald sizeof(subgroup_codec_specific_configuration), 3294a06e23fSMatthias Ringwald subgroup_codec_specific_configuration, 3304a06e23fSMatthias Ringwald sizeof(subgroup_metadata), subgroup_metadata); 3314a06e23fSMatthias Ringwald le_audio_base_builder_add_bis(&builder, 1, sizeof(bis_codec_specific_configuration_1), 3324a06e23fSMatthias Ringwald bis_codec_specific_configuration_1); 3334a06e23fSMatthias Ringwald if (num_bis == 2){ 3344a06e23fSMatthias Ringwald le_audio_base_builder_add_bis(&builder, 2, sizeof(bis_codec_specific_configuration_2), 3354a06e23fSMatthias Ringwald bis_codec_specific_configuration_2); 3364a06e23fSMatthias Ringwald } 3374a06e23fSMatthias Ringwald period_adv_data_len = le_audio_base_builder_get_ad_data_size(&builder); 33856c77a86SMatthias Ringwald 33956c77a86SMatthias Ringwald // setup extended and periodic advertising 34056c77a86SMatthias Ringwald setup_advertising(); 34156c77a86SMatthias Ringwald 34256c77a86SMatthias Ringwald // setup big 34356c77a86SMatthias Ringwald setup_big(); 34456c77a86SMatthias Ringwald } 34556c77a86SMatthias Ringwald 34610277393SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 34710277393SMatthias Ringwald UNUSED(channel); 34810277393SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 3490be46310SMatthias Ringwald uint8_t bis_index; 35010277393SMatthias Ringwald 35110277393SMatthias Ringwald switch (packet[0]) { 35210277393SMatthias Ringwald case BTSTACK_EVENT_STATE: 35310277393SMatthias Ringwald switch(btstack_event_state_get_state(packet)) { 35410277393SMatthias Ringwald case HCI_STATE_WORKING: 35556c77a86SMatthias Ringwald #ifdef ENABLE_DEMO_MODE 35656c77a86SMatthias Ringwald // start broadcast automatically, mod player, 48_5_1 35756c77a86SMatthias Ringwald num_bis = 1; 35856c77a86SMatthias Ringwald menu_sampling_frequency = 5; 35956c77a86SMatthias Ringwald menu_variant = 4; 36056c77a86SMatthias Ringwald start_broadcast(); 36156c77a86SMatthias Ringwald #else 36210277393SMatthias Ringwald show_usage(); 36310277393SMatthias Ringwald printf("Please select sample frequency and variation, then start broadcast\n"); 36456c77a86SMatthias Ringwald #endif 36510277393SMatthias Ringwald break; 36610277393SMatthias Ringwald case HCI_STATE_OFF: 36710277393SMatthias Ringwald printf("Goodbye\n"); 36810277393SMatthias Ringwald exit(0); 36910277393SMatthias Ringwald break; 37010277393SMatthias Ringwald default: 37110277393SMatthias Ringwald break; 37210277393SMatthias Ringwald } 37310277393SMatthias Ringwald break; 374cd0bedb1SMatthias Ringwald case HCI_EVENT_META_GAP: 375cd0bedb1SMatthias Ringwald switch (hci_event_gap_meta_get_subevent_code(packet)){ 3760be46310SMatthias Ringwald case GAP_SUBEVENT_BIG_CREATED: 377cd0bedb1SMatthias Ringwald printf("BIG Created with BIS Connection handles: \n"); 3780be46310SMatthias Ringwald for (bis_index=0;bis_index<num_bis;bis_index++){ 3790be46310SMatthias Ringwald bis_con_handles[bis_index] = gap_subevent_big_created_get_bis_con_handles(packet, bis_index); 3800be46310SMatthias Ringwald printf("0x%04x ", bis_con_handles[bis_index]); 38110277393SMatthias Ringwald } 38244959aebSMatthias Ringwald 383cd0bedb1SMatthias Ringwald app_state = APP_STREAMING; 38410277393SMatthias Ringwald printf("Start streaming\n"); 3850be46310SMatthias Ringwald hci_request_bis_can_send_now_events(big_params.big_handle); 38610277393SMatthias Ringwald break; 38710277393SMatthias Ringwald default: 38810277393SMatthias Ringwald break; 38910277393SMatthias Ringwald } 39010277393SMatthias Ringwald break; 3910be46310SMatthias Ringwald case HCI_EVENT_BIS_CAN_SEND_NOW: 3920d718107SMatthias Ringwald bis_index = hci_event_bis_can_send_now_get_bis_index(packet); 393bb81690eSMatthias Ringwald le_audio_demo_util_source_send(bis_index, bis_con_handles[bis_index]); 3940be46310SMatthias Ringwald bis_index++; 3950be46310SMatthias Ringwald if (bis_index == num_bis){ 396bb81690eSMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(audio_source); 3970be46310SMatthias Ringwald hci_request_bis_can_send_now_events(big_params.big_handle); 39810277393SMatthias Ringwald } 39910277393SMatthias Ringwald break; 40010277393SMatthias Ringwald default: 40110277393SMatthias Ringwald break; 40210277393SMatthias Ringwald } 40310277393SMatthias Ringwald } 40410277393SMatthias Ringwald 40510277393SMatthias Ringwald static void show_usage(void){ 40610277393SMatthias Ringwald printf("\n--- LE Audio Broadcast Source Test Console ---\n"); 40710277393SMatthias Ringwald print_config(); 40810277393SMatthias Ringwald printf("---\n"); 40910277393SMatthias Ringwald printf("c - toggle channels\n"); 410ac95ea81SMatthias Ringwald printf("e - toggle encryption\n"); 41110277393SMatthias Ringwald printf("f - next sampling frequency\n"); 41210277393SMatthias Ringwald printf("v - next codec variant\n"); 41310277393SMatthias Ringwald printf("t - toggle sine / modplayer\n"); 41410277393SMatthias Ringwald printf("s - start broadcast\n"); 41510277393SMatthias Ringwald printf("---\n"); 41610277393SMatthias Ringwald } 41710277393SMatthias Ringwald static void stdin_process(char c){ 41810277393SMatthias Ringwald switch (c){ 41910277393SMatthias Ringwald case 'c': 42010277393SMatthias Ringwald if (app_state != APP_IDLE){ 42110277393SMatthias Ringwald printf("Codec configuration can only be changed in idle state\n"); 42210277393SMatthias Ringwald break; 42310277393SMatthias Ringwald } 42410277393SMatthias Ringwald num_bis = 3 - num_bis; 42510277393SMatthias Ringwald print_config(); 42610277393SMatthias Ringwald break; 427ac95ea81SMatthias Ringwald case 'e': 428ac95ea81SMatthias Ringwald if (app_state != APP_IDLE){ 429ac95ea81SMatthias Ringwald printf("Encryption can only be changed in idle state\n"); 430ac95ea81SMatthias Ringwald break; 431ac95ea81SMatthias Ringwald } 432ac95ea81SMatthias Ringwald encryption = 1 - encryption; 433ac95ea81SMatthias Ringwald print_config(); 434ac95ea81SMatthias Ringwald break; 43510277393SMatthias Ringwald case 'f': 43610277393SMatthias Ringwald if (app_state != APP_IDLE){ 43710277393SMatthias Ringwald printf("Codec configuration can only be changed in idle state\n"); 43810277393SMatthias Ringwald break; 43910277393SMatthias Ringwald } 44010277393SMatthias Ringwald menu_sampling_frequency++; 44110277393SMatthias Ringwald if (menu_sampling_frequency >= 6){ 44210277393SMatthias Ringwald menu_sampling_frequency = 0; 44310277393SMatthias Ringwald } 44410277393SMatthias Ringwald if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){ 44510277393SMatthias Ringwald menu_variant = 0; 44610277393SMatthias Ringwald } 44710277393SMatthias Ringwald print_config(); 44810277393SMatthias Ringwald break; 44910277393SMatthias Ringwald case 'v': 45010277393SMatthias Ringwald if (app_state != APP_IDLE){ 45110277393SMatthias Ringwald printf("Codec configuration can only be changed in idle state\n"); 45210277393SMatthias Ringwald break; 45310277393SMatthias Ringwald } 45410277393SMatthias Ringwald menu_variant++; 45510277393SMatthias Ringwald if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){ 45610277393SMatthias Ringwald menu_variant = 0; 45710277393SMatthias Ringwald } 45810277393SMatthias Ringwald print_config(); 45910277393SMatthias Ringwald break; 46010277393SMatthias Ringwald case 's': 46110277393SMatthias Ringwald if (app_state != APP_IDLE){ 46210277393SMatthias Ringwald printf("Cannot start broadcast - not in idle state\n"); 46310277393SMatthias Ringwald break; 46410277393SMatthias Ringwald } 46556c77a86SMatthias Ringwald start_broadcast(); 46610277393SMatthias Ringwald break; 46710277393SMatthias Ringwald case 't': 468*d352c98fSMatthias Ringwald switch (audio_source){ 469*d352c98fSMatthias Ringwald case AUDIO_SOURCE_MODPLAYER: 470*d352c98fSMatthias Ringwald audio_source = AUDIO_SOURCE_SINE; 471*d352c98fSMatthias Ringwald break; 472*d352c98fSMatthias Ringwald case AUDIO_SOURCE_SINE: 473*d352c98fSMatthias Ringwald audio_source = AUDIO_SOURCE_MODPLAYER; 474*d352c98fSMatthias Ringwald break; 475*d352c98fSMatthias Ringwald default: 476*d352c98fSMatthias Ringwald btstack_unreachable(); 477*d352c98fSMatthias Ringwald break; 478*d352c98fSMatthias Ringwald } 47910277393SMatthias Ringwald print_config(); 48010277393SMatthias Ringwald break; 48110277393SMatthias Ringwald case '\n': 48210277393SMatthias Ringwald case '\r': 48310277393SMatthias Ringwald break; 48410277393SMatthias Ringwald default: 48510277393SMatthias Ringwald show_usage(); 48610277393SMatthias Ringwald break; 48710277393SMatthias Ringwald } 48810277393SMatthias Ringwald } 48910277393SMatthias Ringwald 49010277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]); 49110277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 49210277393SMatthias Ringwald (void) argv; 49310277393SMatthias Ringwald (void) argc; 49410277393SMatthias Ringwald 49510277393SMatthias Ringwald // register for HCI events 49610277393SMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 49710277393SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 49810277393SMatthias Ringwald 499bb81690eSMatthias Ringwald // setup audio processing 500bb81690eSMatthias Ringwald le_audio_demo_util_source_init(); 501bb81690eSMatthias Ringwald 50210277393SMatthias Ringwald // turn on! 50310277393SMatthias Ringwald hci_power_control(HCI_POWER_ON); 50410277393SMatthias Ringwald 50510277393SMatthias Ringwald btstack_stdin_setup(stdin_process); 50610277393SMatthias Ringwald return 0; 50710277393SMatthias Ringwald } 508