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 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__ "le_audio_broadcast_source.c"
39
40 /*
41 * LE Audio Broadcast Source
42 */
43
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <btstack_debug.h>
48
49 #include "bluetooth_data_types.h"
50 #include "btstack_stdin.h"
51 #include "btstack_event.h"
52 #include "btstack_run_loop.h"
53 #include "gap.h"
54 #include "hci.h"
55 #include "hci_cmd.h"
56 #include "hci_dump.h"
57 #include "btstack_lc3.h"
58 #include "btstack_lc3_google.h"
59 #include "le-audio/le_audio_base_builder.h"
60
61 #include "hxcmod.h"
62 #include "mods/mod.h"
63 #include "le_audio_demo_util_source.h"
64
65 // Interoperability with Nordic LE Audio demo
66 //#define NRF5340_BROADCAST_MODE
67
68 // max config
69 #define MAX_NUM_BIS 2
70 #define MAX_SAMPLES_PER_FRAME 480
71 #define MAX_LC3_FRAME_BYTES 155
72
73 static const uint8_t adv_sid = 0;
74
75 static le_advertising_set_t le_advertising_set;
76
77 static le_extended_advertising_parameters_t extended_params = {
78 .advertising_event_properties = 0,
79 .primary_advertising_interval_min = 0x4b0, // 750 ms
80 .primary_advertising_interval_max = 0x4b0, // 750 ms
81 .primary_advertising_channel_map = 7,
82 .own_address_type = BD_ADDR_TYPE_LE_PUBLIC,
83 .peer_address_type = 0,
84 .peer_address = { 0 },
85 .advertising_filter_policy = 0,
86 .advertising_tx_power = 10, // 10 dBm
87 .primary_advertising_phy = 1, // LE 1M PHY
88 .secondary_advertising_max_skip = 0,
89 .secondary_advertising_phy = 1, // LE 1M PHY
90 .advertising_sid = adv_sid,
91 .scan_request_notification_enable = 0,
92 };
93
94 // Random Broadcast ID, valid for lifetime of BIG
95 #define BROADCAST_ID (0x112233u)
96
97 static const uint8_t extended_adv_data[] = {
98 // 16 bit service data, ORG_BLUETOOTH_SERVICE_BASIC_AUDIO_ANNOUNCEMENT_SERVICE, Broadcast ID
99 6, BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID, 0x52, 0x18,
100 BROADCAST_ID >> 16,
101 (BROADCAST_ID >> 8) & 0xff,
102 BROADCAST_ID & 0xff,
103 // name
104 #if defined(NRF5340_BROADCAST_MODE)
105 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',
106 20, BLUETOOTH_DATA_TYPE_BROADCAST_NAME, 'N','R','F','5','3','4','0','_','B','R','O','A','D','C','A','S','T','E','R',
107 #else
108 7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'S', 'o', 'u', 'r', 'c', 'e',
109 7, BLUETOOTH_DATA_TYPE_BROADCAST_NAME, 'S', 'o', 'u', 'r', 'c', 'e',
110 #endif
111 };
112
113 static const le_periodic_advertising_parameters_t periodic_params = {
114 .periodic_advertising_interval_min = 0x258, // 375 ms
115 .periodic_advertising_interval_max = 0x258, // 375 ms
116 .periodic_advertising_properties = 0
117 };
118
119 static btstack_packet_callback_registration_t hci_event_callback_registration;
120 static uint8_t period_adv_data[255];
121 static uint16_t period_adv_data_len;
122
123 static uint8_t adv_handle = 0;
124 static hci_con_handle_t bis_con_handles[MAX_NUM_BIS];
125
126 static le_audio_big_t big_storage;
127 static le_audio_big_params_t big_params;
128
129 // time stamping
130 #ifdef COUNT_MODE
131 #define MAX_PACKET_INTERVAL_BINS_MS 50
132 static uint32_t send_time_bins[MAX_PACKET_INTERVAL_BINS_MS];
133 static uint32_t send_last_ms;
134 #endif
135
136 // lc3 codec config
137 static uint16_t sampling_frequency_hz;
138 static btstack_lc3_frame_duration_t frame_duration;
139 static uint16_t number_samples_per_frame;
140 static uint16_t octets_per_frame;
141 static uint8_t num_bis = 1;
142
143 // codec menu
144 static uint8_t menu_sampling_frequency;
145 static uint8_t menu_variant;
146
147 // encryption
148 static uint8_t encryption = 0;
149 static uint8_t broadcast_code [] = {0x01, 0x02, 0x68, 0x05, 0x53, 0xF1, 0x41, 0x5A, 0xA2, 0x65, 0xBB, 0xAF, 0xC6, 0xEA, 0x03, 0xB8, };
150
151 // audio producer
152 #ifdef COUNT_MODE
153 static le_audio_demo_source_generator audio_source = AUDIO_SOURCE_COUNTER;
154 #else
155 static le_audio_demo_source_generator audio_source = AUDIO_SOURCE_MODPLAYER;
156 #endif
157
158 static enum {
159 APP_IDLE,
160 APP_W4_CREATE_BIG_COMPLETE,
161 APP_STREAMING,
162 } app_state = APP_IDLE;
163
164 // enumerate default codec configs
165 static struct {
166 uint16_t samplingrate_hz;
167 uint8_t samplingrate_index;
168 uint8_t num_variants;
169 struct {
170 const char * name;
171 btstack_lc3_frame_duration_t frame_duration;
172 uint16_t octets_per_frame;
173 } variants[6];
174 } codec_configurations[] = {
175 {
176 8000, 0x01, 2,
177 {
178 { "8_1", BTSTACK_LC3_FRAME_DURATION_7500US, 26},
179 { "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30}
180 }
181 },
182 {
183 16000, 0x03, 2,
184 {
185 { "16_1", BTSTACK_LC3_FRAME_DURATION_7500US, 30},
186 { "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40}
187 }
188 },
189 {
190 24000, 0x05, 2,
191 {
192 { "24_1", BTSTACK_LC3_FRAME_DURATION_7500US, 45},
193 { "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60}
194 }
195 },
196 {
197 32000, 0x06, 2,
198 {
199 { "32_1", BTSTACK_LC3_FRAME_DURATION_7500US, 60},
200 { "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80}
201 }
202 },
203 {
204 44100, 0x07, 2,
205 {
206 { "441_1", BTSTACK_LC3_FRAME_DURATION_7500US, 97},
207 { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130}
208 }
209 },
210 {
211 48000, 0x08, 6,
212 {
213 { "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75},
214 { "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100},
215 { "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90},
216 { "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120},
217 { "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117},
218 { "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155}
219 }
220 },
221 };
222
223 static void show_usage(void);
224
print_config(void)225 static void print_config(void) {
226 static const char * generator[] = { "Sine", "Modplayer", "Recording"};
227 printf("Config '%s_%u': %u, %s ms, %u octets - %s%s\n",
228 codec_configurations[menu_sampling_frequency].variants[menu_variant].name,
229 num_bis,
230 codec_configurations[menu_sampling_frequency].samplingrate_hz,
231 codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
232 codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame,
233 generator[audio_source - AUDIO_SOURCE_SINE],
234 encryption ? " (encrypted)" : "");
235 }
236
setup_advertising()237 static void setup_advertising() {
238 bd_addr_t local_addr;
239 gap_local_bd_addr(local_addr);
240 bool local_address_invalid = btstack_is_null_bd_addr( local_addr );
241 if( local_address_invalid ) {
242 extended_params.own_address_type = BD_ADDR_TYPE_LE_RANDOM;
243 }
244 gap_extended_advertising_setup(&le_advertising_set, &extended_params, &adv_handle);
245 if( local_address_invalid ) {
246 bd_addr_t random_address = { 0xC1, 0x01, 0x01, 0x01, 0x01, 0x01 };
247 gap_extended_advertising_set_random_address( adv_handle, random_address );
248 }
249 gap_extended_advertising_set_adv_data(adv_handle, sizeof(extended_adv_data), extended_adv_data);
250 gap_periodic_advertising_set_params(adv_handle, &periodic_params);
251 gap_periodic_advertising_set_data(adv_handle, period_adv_data_len, period_adv_data);
252 gap_periodic_advertising_start(adv_handle, 0);
253 gap_extended_advertising_start(adv_handle, 0, 0);
254 }
255
setup_big(void)256 static void setup_big(void){
257 // Create BIG
258 big_params.big_handle = 0;
259 big_params.advertising_handle = adv_handle;
260 big_params.num_bis = num_bis;
261 big_params.max_sdu = octets_per_frame;
262 big_params.max_transport_latency_ms = 31;
263 big_params.rtn = 2;
264 big_params.phy = 2;
265 big_params.packing = 0;
266 big_params.encryption = encryption;
267 if (encryption) {
268 memcpy(big_params.broadcast_code, &broadcast_code[0], 16);
269 } else {
270 memset(big_params.broadcast_code, 0, 16);
271 }
272 if (sampling_frequency_hz == 44100){
273 // same config as for 48k -> frame is longer by 48/44.1
274 big_params.sdu_interval_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8163 : 10884;
275 big_params.framing = 1;
276 } else {
277 big_params.sdu_interval_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 7500 : 10000;
278 big_params.framing = 0;
279 }
280 app_state = APP_W4_CREATE_BIG_COMPLETE;
281 gap_big_create(&big_storage, &big_params);
282 }
283
284
start_broadcast()285 static void start_broadcast() {// use values from table
286 sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz;
287 octets_per_frame = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame;
288 frame_duration = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration;
289
290 number_samples_per_frame = btstack_lc3_samples_per_frame(sampling_frequency_hz, frame_duration);
291
292 le_audio_demo_util_source_configure(num_bis, 1, sampling_frequency_hz, frame_duration, octets_per_frame);
293 le_audio_demo_util_source_generate_iso_frame(audio_source);
294
295 // setup base
296 uint8_t codec_id[] = { 0x06, 0x00, 0x00, 0x00, 0x00 };
297 uint8_t subgroup_codec_specific_configuration[] = {
298 0x02, 0x01, 0x01,
299 0x02, 0x02, 0x01,
300 0x03, 0x04, 0x1E, 0x00,
301 };
302 subgroup_codec_specific_configuration[2] = codec_configurations[menu_sampling_frequency].samplingrate_index;
303 subgroup_codec_specific_configuration[5] = (frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US) ? 0 : 1;;
304 uint8_t subgroup_metadata[] = {
305 0x03, 0x02, 0x04, 0x00, // Metadata[i]
306 };
307 little_endian_store_16(subgroup_codec_specific_configuration, 8, octets_per_frame);
308 uint8_t bis_codec_specific_configuration_1[] = {
309 0x05, 0x03, 0x01, 0x00, 0x00, 0x00
310 };
311 uint8_t bis_codec_specific_configuration_2[] = {
312 0x05, 0x03, 0x02, 0x00, 0x00, 0x00
313 };
314 le_audio_base_builder_t builder;
315 le_audio_base_builder_init(&builder, period_adv_data, sizeof(period_adv_data), 20000);
316 le_audio_base_builder_add_subgroup(&builder, codec_id,
317 sizeof(subgroup_codec_specific_configuration),
318 subgroup_codec_specific_configuration,
319 sizeof(subgroup_metadata), subgroup_metadata);
320 le_audio_base_builder_add_bis(&builder, 1, sizeof(bis_codec_specific_configuration_1),
321 bis_codec_specific_configuration_1);
322 if (num_bis == 2){
323 le_audio_base_builder_add_bis(&builder, 2, sizeof(bis_codec_specific_configuration_2),
324 bis_codec_specific_configuration_2);
325 }
326 period_adv_data_len = le_audio_base_builder_get_ad_data_size(&builder);
327
328 // setup extended and periodic advertising
329 setup_advertising();
330
331 // setup big
332 setup_big();
333 }
334
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)335 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
336 UNUSED(channel);
337 if (packet_type != HCI_EVENT_PACKET) return;
338 uint8_t bis_index;
339
340 switch (packet[0]) {
341 case BTSTACK_EVENT_STATE:
342 switch(btstack_event_state_get_state(packet)) {
343 case HCI_STATE_WORKING:
344 #ifdef ENABLE_DEMO_MODE
345 // start broadcast automatically, mod player, 48_5_1
346 num_bis = 1;
347 menu_sampling_frequency = 5;
348 menu_variant = 4;
349 start_broadcast();
350 #elif defined( NRF5340_BROADCAST_MODE )
351 num_bis = 1;
352 menu_sampling_frequency = 5;
353 menu_variant = 1;
354 #else
355 show_usage();
356 printf("Please select sample frequency and variation, then start broadcast\n");
357 #endif
358 break;
359 case HCI_STATE_OFF:
360 printf("Goodbye\n");
361 exit(0);
362 break;
363 default:
364 break;
365 }
366 break;
367 case HCI_EVENT_META_GAP:
368 switch (hci_event_gap_meta_get_subevent_code(packet)){
369 case GAP_SUBEVENT_BIG_CREATED:
370 printf("BIG Created with BIS Connection handles: \n");
371 for (bis_index=0;bis_index<num_bis;bis_index++){
372 bis_con_handles[bis_index] = gap_subevent_big_created_get_bis_con_handles(packet, bis_index);
373 printf("0x%04x ", bis_con_handles[bis_index]);
374 }
375
376 app_state = APP_STREAMING;
377 printf("Start streaming\n");
378 hci_request_bis_can_send_now_events(big_params.big_handle);
379 break;
380 default:
381 break;
382 }
383 break;
384 case HCI_EVENT_BIS_CAN_SEND_NOW:
385 bis_index = hci_event_bis_can_send_now_get_bis_index(packet);
386 le_audio_demo_util_source_send(bis_index, bis_con_handles[bis_index]);
387 bis_index++;
388 if (bis_index == num_bis){
389 le_audio_demo_util_source_generate_iso_frame(audio_source);
390 hci_request_bis_can_send_now_events(big_params.big_handle);
391 }
392 break;
393 default:
394 break;
395 }
396 }
397
show_usage(void)398 static void show_usage(void){
399 printf("\n--- LE Audio Broadcast Source Test Console ---\n");
400 print_config();
401 printf("---\n");
402 printf("c - toggle channels\n");
403 printf("e - toggle encryption\n");
404 printf("f - next sampling frequency\n");
405 printf("v - next codec variant\n");
406 printf("x - toggle sine / modplayer / recording\n");
407 printf("s - start broadcast\n");
408 printf("---\n");
409 }
stdin_process(char c)410 static void stdin_process(char c){
411 switch (c){
412 case 'c':
413 if (app_state != APP_IDLE){
414 printf("Codec configuration can only be changed in idle state\n");
415 break;
416 }
417 num_bis = 3 - num_bis;
418 print_config();
419 break;
420 case 'e':
421 if (app_state != APP_IDLE){
422 printf("Encryption can only be changed in idle state\n");
423 break;
424 }
425 encryption = 1 - encryption;
426 print_config();
427 break;
428 case 'f':
429 if (app_state != APP_IDLE){
430 printf("Codec configuration can only be changed in idle state\n");
431 break;
432 }
433 menu_sampling_frequency++;
434 if (menu_sampling_frequency >= 6){
435 menu_sampling_frequency = 0;
436 }
437 if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
438 menu_variant = 0;
439 }
440 print_config();
441 break;
442 case 'v':
443 if (app_state != APP_IDLE){
444 printf("Codec configuration can only be changed in idle state\n");
445 break;
446 }
447 menu_variant++;
448 if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
449 menu_variant = 0;
450 }
451 print_config();
452 break;
453 case 's':
454 if (app_state != APP_IDLE){
455 printf("Cannot start broadcast - not in idle state\n");
456 break;
457 }
458 start_broadcast();
459 break;
460 case 'x':
461 switch (audio_source){
462 case AUDIO_SOURCE_MODPLAYER:
463 audio_source = AUDIO_SOURCE_SINE;
464 break;
465 case AUDIO_SOURCE_SINE:
466 audio_source = AUDIO_SOURCE_RECORDING;
467 break;
468 case AUDIO_SOURCE_RECORDING:
469 audio_source = AUDIO_SOURCE_MODPLAYER;
470 break;
471 default:
472 btstack_unreachable();
473 break;
474 }
475 print_config();
476 break;
477 case '\n':
478 case '\r':
479 break;
480 default:
481 show_usage();
482 break;
483 }
484 }
485
486 int btstack_main(int argc, const char * argv[]);
btstack_main(int argc,const char * argv[])487 int btstack_main(int argc, const char * argv[]){
488 (void) argv;
489 (void) argc;
490
491 // register for HCI events
492 hci_event_callback_registration.callback = &packet_handler;
493 hci_add_event_handler(&hci_event_callback_registration);
494
495 // setup audio processing
496 le_audio_demo_util_source_init();
497
498 // turn on!
499 hci_power_control(HCI_POWER_ON);
500
501 btstack_stdin_setup(stdin_process);
502 return 0;
503 }
504