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_source.c"
39
40 /*
41 * LE Audio Unicast Source
42 * Until GATT Services are available, we encode LC3 config in advertising
43 */
44
45 #include <stdint.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <btstack_debug.h>
49
50 #include "bluetooth_data_types.h"
51 #include "bluetooth_company_id.h"
52 #include "btstack_stdin.h"
53 #include "btstack_event.h"
54 #include "gap.h"
55 #include "hci.h"
56 #include "btstack_lc3.h"
57 #include "btstack_lc3_google.h"
58 #include "le_audio_demo_util_source.h"
59 #include "le_audio_demo_util_sink.h"
60
61 // max config
62 #define MAX_CHANNELS 2
63 #define MAX_NUM_CIS 1
64
65
66 static uint8_t adv_data[] = {
67 // Manufacturer Specific Data to indicate codec
68 9,
69 BLUETOOTH_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA,
70 BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH & 0xff,
71 BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH >> 8,
72 0, // subtype: LE Audio Connection Source
73 0, // flags
74 1, // num bis
75 8, // sampling frequency in khz
76 0, // frame duration
77 26, // octets per frame
78 // name
79 7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'S', 'o', 'u', 'r', 'c', 'e'
80 };
81
82 static bd_addr_t remote;
83
84 static btstack_packet_callback_registration_t hci_event_callback_registration;
85
86 static unsigned int next_cis_index;
87 static hci_con_handle_t cis_con_handles[MAX_NUM_CIS];
88 static bool cis_established[MAX_NUM_CIS];
89 static uint8_t iso_frame_counter;
90 static uint8_t num_cis;
91
92 // time stamping
93 #ifdef COUNT_MODE
94 #define MAX_PACKET_INTERVAL_BINS_MS 50
95 static uint32_t send_time_bins[MAX_PACKET_INTERVAL_BINS_MS];
96 static uint32_t send_last_ms;
97 #endif
98
99 // lc3 codec config
100 static uint32_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 = 1;
105
106 // codec menu
107 static uint8_t menu_sampling_frequency;
108 static uint8_t menu_variant;
109
110 // audio producer
111 static le_audio_demo_source_generator audio_source = AUDIO_SOURCE_MODPLAYER;
112
113 static enum {
114 APP_W4_WORKING,
115 APP_IDLE,
116 APP_W4_CIS_COMPLETE,
117 APP_STREAMING,
118 } app_state = APP_W4_WORKING;
119
120 // enumerate default codec configs
121 static struct {
122 uint16_t samplingrate_hz;
123 uint8_t samplingrate_index;
124 uint8_t num_variants;
125 struct {
126 const char * name;
127 btstack_lc3_frame_duration_t frame_duration;
128 uint16_t octets_per_frame;
129 } variants[6];
130 } codec_configurations[] = {
131 {
132 8000, 0x01, 2,
133 {
134 { "8_1", BTSTACK_LC3_FRAME_DURATION_7500US, 26},
135 { "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30}
136 }
137 },
138 {
139 16000, 0x03, 2,
140 {
141 { "16_1", BTSTACK_LC3_FRAME_DURATION_7500US, 30},
142 { "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40}
143 }
144 },
145 {
146 24000, 0x05, 2,
147 {
148 { "24_1", BTSTACK_LC3_FRAME_DURATION_7500US, 45},
149 { "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60}
150 }
151 },
152 {
153 32000, 0x06, 2,
154 {
155 { "32_1", BTSTACK_LC3_FRAME_DURATION_7500US, 60},
156 { "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80}
157 }
158 },
159 {
160 44100, 0x07, 2,
161 {
162 { "441_1", BTSTACK_LC3_FRAME_DURATION_7500US, 97},
163 { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130}
164 }
165 },
166 {
167 48000, 0x08, 6,
168 {
169 { "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75},
170 { "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100},
171 { "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90},
172 { "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120},
173 { "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117},
174 { "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155}
175 }
176 },
177 };
178
179 static void show_usage(void);
180
print_config(void)181 static void print_config(void) {
182 printf("Config '%s_%u': %u, %s ms, %u octets - %s\n",
183 codec_configurations[menu_sampling_frequency].variants[menu_variant].name,
184 num_channels,
185 codec_configurations[menu_sampling_frequency].samplingrate_hz,
186 codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
187 codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame,
188 audio_source == AUDIO_SOURCE_SINE ? "Sine" : "Modplayer");
189 }
190
start_unicast()191 static void start_unicast() {
192 // use values from table
193 sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz;
194 octets_per_frame = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame;
195 frame_duration = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration;
196
197 le_audio_demo_util_source_configure(1, num_channels, sampling_frequency_hz, frame_duration, octets_per_frame);
198 le_audio_demo_util_source_generate_iso_frame(audio_source);
199
200 // update adv / BASE
201 adv_data[4] = 0; // subtype
202 adv_data[5] = 0; // flags
203 adv_data[6] = num_channels;
204 adv_data[7] = sampling_frequency_hz / 1000;
205 adv_data[8] = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 0 : 1;
206 adv_data[9] = octets_per_frame;
207
208 // setup advertisements
209 uint16_t adv_int_min = 0x0030;
210 uint16_t adv_int_max = 0x0030;
211 uint8_t adv_type = 0;
212 bd_addr_t null_addr;
213 memset(null_addr, 0, 6);
214 gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
215 gap_advertisements_set_data(sizeof(adv_data), adv_data);
216 gap_advertisements_enable(1);
217 num_cis = 1;
218 app_state = APP_W4_CIS_COMPLETE;
219 }
220
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)221 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
222 UNUSED(channel);
223 if (packet_type != HCI_EVENT_PACKET) return;
224
225 hci_con_handle_t cis_con_handle;
226 uint8_t i;
227
228 switch (packet[0]) {
229 case BTSTACK_EVENT_STATE:
230 switch(btstack_event_state_get_state(packet)) {
231 case HCI_STATE_WORKING:
232 app_state = APP_IDLE;
233 #ifdef ENABLE_DEMO_MODE
234 // start unicast automatically, mod player, 48_5_2
235 num_channels = 2;
236 menu_sampling_frequency = 5;
237 menu_variant = 4;
238 start_unicast();
239 #else
240 show_usage();
241 printf("Please select sample frequency and variation, then start advertising\n");
242 #endif
243 break;
244 case HCI_STATE_OFF:
245 printf("Goodbye\n");
246 exit(0);
247 break;
248 default:
249 break;
250 }
251 break;
252 case HCI_EVENT_DISCONNECTION_COMPLETE:
253 cis_con_handle = hci_event_disconnection_complete_get_connection_handle(packet);
254 for (i=0; i < num_cis; i++){
255 if (cis_con_handle == cis_con_handles[i]){
256 le_audio_demo_util_sink_close();
257 }
258 }
259 break;
260 case HCI_EVENT_LE_META:
261 switch(hci_event_le_meta_get_subevent_code(packet)){
262 case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
263 next_cis_index = 0;
264 break;
265 case HCI_SUBEVENT_LE_CIS_REQUEST:
266 cis_con_handles[next_cis_index] = hci_subevent_le_cis_request_get_cis_connection_handle(packet);
267 gap_cis_accept(cis_con_handles[next_cis_index]);
268 next_cis_index++;
269 break;
270 default:
271 break;
272 }
273 break;
274 case HCI_EVENT_META_GAP:
275 switch (hci_event_gap_meta_get_subevent_code(packet)) {
276 case GAP_SUBEVENT_CIS_CREATED: {
277 cis_con_handle = gap_subevent_cis_created_get_cis_con_handle(packet);
278 for (i=0; i < num_cis; i++){
279 if (cis_con_handle == cis_con_handles[i]){
280 cis_established[i] = true;
281 }
282 }
283 // check for complete
284 bool complete = true;
285 for (i=0; i < num_cis; i++) {
286 complete &= cis_established[i];
287 }
288 // ready to send
289 if (complete) {
290 printf("All CIS Established and ISO Path setup\n");
291
292 // init sink
293 uint16_t iso_interval_1250us = gap_subevent_cis_created_get_iso_interval_1250us(packet);
294 uint8_t flush_timeout = gap_subevent_cis_created_get_flush_timeout_c_to_p(packet);
295 le_audio_demo_util_sink_configure_unicast(1, 1, sampling_frequency_hz, frame_duration,
296 octets_per_frame,
297 iso_interval_1250us, flush_timeout);
298
299 next_cis_index = 0;
300 app_state = APP_STREAMING;
301
302 hci_request_cis_can_send_now_events(cis_con_handles[0]);
303 }
304 break;
305 }
306 }
307 break;
308 case HCI_EVENT_CIS_CAN_SEND_NOW:
309 cis_con_handle = hci_event_cis_can_send_now_get_cis_con_handle(packet);
310 for (i=0;i<num_cis;i++){
311 if (cis_con_handle == cis_con_handles[i]){
312 // allow to send
313 le_audio_demo_util_source_send(i, cis_con_handle);
314 le_audio_demo_util_source_generate_iso_frame(audio_source);
315 hci_request_cis_can_send_now_events(cis_con_handle);
316 }
317 }
318 break;
319
320 default:
321 break;
322 }
323 }
324
iso_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)325 static void iso_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
326 le_audio_demo_util_sink_receive(0, packet, size);
327 }
328
show_usage(void)329 static void show_usage(void){
330 printf("\n--- LE Audio Unicast Source Test Console ---\n");
331 print_config();
332 printf("---\n");
333 printf("c - toggle channels\n");
334 printf("f - next sampling frequency\n");
335 printf("v - next codec variant\n");
336 printf("t - toggle sine / modplayer\n");
337 printf("s - start advertising\n");
338 printf("x - shutdown\n");
339 printf("---\n");
340 }
341
stdin_process(char c)342 static void stdin_process(char c){
343 switch (c){
344 case 'c':
345 if (app_state != APP_IDLE){
346 printf("Codec configuration can only be changed in idle state\n");
347 break;
348 }
349 num_channels = 3 - num_channels;
350 print_config();
351 break;
352 case 'f':
353 if (app_state != APP_IDLE){
354 printf("Codec configuration can only be changed in idle state\n");
355 break;
356 }
357 menu_sampling_frequency++;
358 if (menu_sampling_frequency >= 6){
359 menu_sampling_frequency = 0;
360 }
361 if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
362 menu_variant = 0;
363 }
364 print_config();
365 break;
366 case 'v':
367 if (app_state != APP_IDLE){
368 printf("Codec configuration can only be changed in idle state\n");
369 break;
370 }
371 menu_variant++;
372 if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
373 menu_variant = 0;
374 }
375 print_config();
376 break;
377 case 's':
378 if (app_state != APP_IDLE){
379 printf("Cannot start advertising - not in idle state\n");
380 break;
381 }
382 start_unicast();
383
384 break;
385 case 't':
386 switch (audio_source){
387 case AUDIO_SOURCE_MODPLAYER:
388 audio_source = AUDIO_SOURCE_SINE;
389 break;
390 case AUDIO_SOURCE_SINE:
391 audio_source = AUDIO_SOURCE_MODPLAYER;
392 break;
393 default:
394 btstack_unreachable();
395 break;
396 }
397 print_config();
398 break;
399 case '\n':
400 case '\r':
401 break;
402 default:
403 show_usage();
404 break;
405 }
406 }
407
408 int btstack_main(int argc, const char * argv[]);
btstack_main(int argc,const char * argv[])409 int btstack_main(int argc, const char * argv[]){
410 (void) argv;
411 (void) argc;
412
413 // register for HCI events
414 hci_event_callback_registration.callback = &packet_handler;
415 hci_add_event_handler(&hci_event_callback_registration);
416
417 // register for ISO Packet
418 hci_register_iso_packet_handler(&iso_packet_handler);
419
420 // setup audio processing
421 le_audio_demo_util_sink_init("le_audio_unicast_source.wav");
422 le_audio_demo_util_source_init();
423
424 // turn on!
425 hci_power_control(HCI_POWER_ON);
426
427 btstack_stdin_setup(stdin_process);
428 return 0;
429 }
430