xref: /btstack/test/le_audio/lc3_test.c (revision 533ea81febb4126dd506c94e83cc8f96e8197e91)
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__ "lc3_test.c"
39 
40 /*
41  * Measure LC3 encoding load
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 
60 #include "hxcmod.h"
61 #include "mods/mod.h"
62 
63 
64 #ifdef HAVE_POSIX_FILE_IO
65 #include "wav_util.h"
66 #endif
67 
68 // max config
69 #define MAX_SAMPLES_PER_FRAME 480
70 #define MAX_NUM_BIS 2
71 
72 // lc3 codec config
73 static uint32_t sampling_frequency_hz;
74 static btstack_lc3_frame_duration_t frame_duration;
75 static uint16_t number_samples_per_frame;
76 static uint16_t octets_per_frame;
77 static uint8_t  num_bis = 1;
78 
79 // lc3 encoder
80 static const btstack_lc3_encoder_t * lc3_encoder;
81 static btstack_lc3_encoder_google_t encoder_contexts[MAX_NUM_BIS];
82 static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
83 
84 // lc3 decoder
85 static const btstack_lc3_decoder_t * lc3_decoder;
86 static btstack_lc3_decoder_google_t decoder_contexts[MAX_NUM_BIS];
87 static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
88 
89 // PLC
90 static uint16_t plc_frame_counter;
91 static uint16_t plc_dopped_frame_interval;
92 
93 // codec menu
94 static uint8_t menu_sampling_frequency;
95 static uint8_t menu_variant;
96 
97 // mod player
98 static int hxcmod_initialized;
99 static modcontext mod_context;
100 static tracker_buffer_state trkbuf;
101 
102 // sine generator
103 static uint8_t  sine_step;
104 static uint16_t sine_phases[MAX_NUM_BIS];
105 
106 // audio producer
107 static enum {
108     AUDIO_SOURCE_SINE,
109     AUDIO_SOURCE_MODPLAYER
110 } audio_source = AUDIO_SOURCE_MODPLAYER;
111 
112 // enumerate default codec configs
113 static struct {
114     uint32_t samplingrate_hz;
115     uint8_t  samplingrate_index;
116     uint8_t  num_variants;
117     struct {
118         const char * name;
119         btstack_lc3_frame_duration_t frame_duration;
120         uint16_t octets_per_frame;
121     } variants[6];
122 } codec_configurations[] = {
123     {
124         8000, 0x01, 2,
125         {
126             {  "8_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 26},
127             {  "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30}
128         }
129     },
130     {
131        16000, 0x03, 2,
132        {
133             {  "16_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 30},
134             {  "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40}
135        }
136     },
137     {
138         24000, 0x05, 2,
139         {
140             {  "24_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 45},
141             {  "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60}
142        }
143     },
144     {
145         32000, 0x06, 2,
146         {
147             {  "32_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 60},
148             {  "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80}
149         }
150     },
151     {
152         44100, 0x07, 2,
153         {
154             { "441_1",  BTSTACK_LC3_FRAME_DURATION_7500US,  97},
155             { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130}
156         }
157     },
158     {
159         48000, 0x08, 6,
160         {
161             {  "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75},
162             {  "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100},
163             {  "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90},
164             {  "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120},
165             {  "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117},
166             {  "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155}
167         }
168     },
169 };
170 
171 
172 // input signal: pre-computed int16 sine wave, 96000 Hz at 300 Hz
173 static const int16_t sine_int16[] = {
174         0,    643,   1286,   1929,   2571,   3212,   3851,   4489,   5126,   5760,
175         6393,   7022,   7649,   8273,   8894,   9512,  10126,  10735,  11341,  11943,
176         12539,  13131,  13718,  14300,  14876,  15446,  16011,  16569,  17121,  17666,
177         18204,  18736,  19260,  19777,  20286,  20787,  21280,  21766,  22242,  22710,
178         23170,  23620,  24062,  24494,  24916,  25329,  25732,  26126,  26509,  26882,
179         27245,  27597,  27938,  28269,  28589,  28898,  29196,  29482,  29757,  30021,
180         30273,  30513,  30742,  30958,  31163,  31356,  31537,  31705,  31862,  32006,
181         32137,  32257,  32364,  32458,  32540,  32609,  32666,  32710,  32742,  32761,
182         32767,  32761,  32742,  32710,  32666,  32609,  32540,  32458,  32364,  32257,
183         32137,  32006,  31862,  31705,  31537,  31356,  31163,  30958,  30742,  30513,
184         30273,  30021,  29757,  29482,  29196,  28898,  28589,  28269,  27938,  27597,
185         27245,  26882,  26509,  26126,  25732,  25329,  24916,  24494,  24062,  23620,
186         23170,  22710,  22242,  21766,  21280,  20787,  20286,  19777,  19260,  18736,
187         18204,  17666,  17121,  16569,  16011,  15446,  14876,  14300,  13718,  13131,
188         12539,  11943,  11341,  10735,  10126,   9512,   8894,   8273,   7649,   7022,
189         6393,   5760,   5126,   4489,   3851,   3212,   2571,   1929,   1286,    643,
190         0,   -643,  -1286,  -1929,  -2571,  -3212,  -3851,  -4489,  -5126,  -5760,
191         -6393,  -7022,  -7649,  -8273,  -8894,  -9512, -10126, -10735, -11341, -11943,
192         -12539, -13131, -13718, -14300, -14876, -15446, -16011, -16569, -17121, -17666,
193         -18204, -18736, -19260, -19777, -20286, -20787, -21280, -21766, -22242, -22710,
194         -23170, -23620, -24062, -24494, -24916, -25329, -25732, -26126, -26509, -26882,
195         -27245, -27597, -27938, -28269, -28589, -28898, -29196, -29482, -29757, -30021,
196         -30273, -30513, -30742, -30958, -31163, -31356, -31537, -31705, -31862, -32006,
197         -32137, -32257, -32364, -32458, -32540, -32609, -32666, -32710, -32742, -32761,
198         -32767, -32761, -32742, -32710, -32666, -32609, -32540, -32458, -32364, -32257,
199         -32137, -32006, -31862, -31705, -31537, -31356, -31163, -30958, -30742, -30513,
200         -30273, -30021, -29757, -29482, -29196, -28898, -28589, -28269, -27938, -27597,
201         -27245, -26882, -26509, -26126, -25732, -25329, -24916, -24494, -24062, -23620,
202         -23170, -22710, -22242, -21766, -21280, -20787, -20286, -19777, -19260, -18736,
203         -18204, -17666, -17121, -16569, -16011, -15446, -14876, -14300, -13718, -13131,
204         -12539, -11943, -11341, -10735, -10126,  -9512,  -8894,  -8273,  -7649,  -7022,
205         -6393,  -5760,  -5126,  -4489,  -3851,  -3212,  -2571,  -1929,  -1286,   -643,
206 };
207 
208 static void show_usage(void);
209 
210 static void print_config(void) {
211     printf("Config '%s_%u': %u, %s ms, %u octets - %s, drop frame interval %u\n",
212            codec_configurations[menu_sampling_frequency].variants[menu_variant].name,
213            num_bis,
214            codec_configurations[menu_sampling_frequency].samplingrate_hz,
215            codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
216            codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame,
217            audio_source == AUDIO_SOURCE_SINE ? "Sine" : "Modplayer",
218            plc_dopped_frame_interval);
219 }
220 
221 static void setup_lc3_encoder(void){
222     uint8_t channel;
223     for (channel = 0 ; channel < num_bis ; channel++){
224         btstack_lc3_encoder_google_t * context = &encoder_contexts[channel];
225         lc3_encoder = btstack_lc3_encoder_google_init_instance(context);
226         lc3_encoder->configure(context, sampling_frequency_hz, frame_duration);
227     }
228     number_samples_per_frame = lc3_encoder->get_number_samples_per_frame(&encoder_contexts[0]);
229     btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
230     printf("LC3 Encoder config: %u hz, frame duration %s ms, num samples %u, num octets %u\n",
231            sampling_frequency_hz, frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
232            number_samples_per_frame, octets_per_frame);
233 }
234 
235 static void setup_lc3_decoder(void){
236     uint8_t channel;
237     for (channel = 0 ; channel < num_bis ; channel++){
238         btstack_lc3_decoder_google_t * decoder_context = &decoder_contexts[channel];
239         lc3_decoder = btstack_lc3_decoder_google_init_instance(decoder_context);
240         lc3_decoder->configure(decoder_context, sampling_frequency_hz, frame_duration);
241     }
242     number_samples_per_frame = lc3_decoder->get_number_samples_per_frame(&decoder_contexts[0]);
243     btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
244 }
245 
246 static void setup_mod_player(void){
247     if (!hxcmod_initialized) {
248         hxcmod_initialized = hxcmod_init(&mod_context);
249         btstack_assert(hxcmod_initialized != 0);
250     }
251     hxcmod_unload(&mod_context);
252     hxcmod_setcfg(&mod_context, sampling_frequency_hz, 16, 1, 1, 1);
253     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
254 }
255 
256 static void generate_audio(void){
257     uint16_t sample;
258     switch (audio_source) {
259         case AUDIO_SOURCE_SINE:
260             // generate sine wave for all channels
261             for (sample = 0 ; sample < number_samples_per_frame ; sample++){
262                 uint8_t channel;
263                 for (channel = 0; channel < num_bis; channel++) {
264                     int16_t value = sine_int16[sine_phases[channel]] / 4;
265                     pcm[sample * num_bis + channel] = value;
266                     sine_phases[channel] += sine_step * (1+channel);    // second channel, double frequency
267                     if (sine_phases[channel] >= (sizeof(sine_int16) / sizeof(int16_t))) {
268                         sine_phases[channel] = 0;
269                     }
270                 }
271             }
272             break;
273         case AUDIO_SOURCE_MODPLAYER:
274             // mod player configured for stereo
275             hxcmod_fillbuffer(&mod_context, (unsigned short *) pcm, number_samples_per_frame, &trkbuf);
276             if (num_bis == 1) {
277                 // stereo -> mono
278                 uint16_t i;
279                 for (i=0;i<number_samples_per_frame;i++){
280                     pcm[i] = (pcm[2*i] / 2) + (pcm[2*i+1] / 2);
281                 }
282             }
283             break;
284         default:
285             btstack_unreachable();
286             break;
287     }
288 }
289 
290 static void test_encoder(){
291 #ifdef HAVE_POSIX_FILE_IO
292     wav_writer_open("lc3_test.wav", 1, sampling_frequency_hz);
293 #endif
294 
295     // encode 10 seconds of music
296     uint32_t audio_duration_in_seconds = 10;
297     uint32_t total_samples = sampling_frequency_hz * audio_duration_in_seconds;
298     uint32_t generated_samples = 0;
299     uint32_t player_ms = 0;
300     uint32_t encoder_ms = 0;
301     uint32_t decoder_ms = 0;
302     plc_frame_counter = 0;
303 
304     printf("Encoding and decoding %u seconds of audio...\n", audio_duration_in_seconds);
305     while (generated_samples < total_samples){
306 
307         // generate audio
308         uint32_t block_start_ms = btstack_run_loop_get_time_ms();
309         generate_audio();
310         uint32_t block_generated_ms  = btstack_run_loop_get_time_ms();
311 
312         // encode frame
313         uint8_t buffer[200];
314         lc3_encoder->encode_signed_16(&encoder_contexts[0], pcm, 1, buffer, octets_per_frame);
315         generated_samples += number_samples_per_frame;
316         uint32_t block_encoded_ms  = btstack_run_loop_get_time_ms();
317         plc_frame_counter++;
318 
319         uint8_t BFI = 0;
320         // simulate dropped packets
321         if ((plc_dopped_frame_interval != 0) && (plc_frame_counter == plc_dopped_frame_interval)){
322             plc_frame_counter = 0;
323             BFI = 1;
324         }
325 
326 #ifdef HAVE_POSIX_FILE_IO
327         if (BFI){
328             // insert silence before for analysis in audacity
329             memset(pcm, 0, sizeof(pcm));
330             wav_writer_write_int16(number_samples_per_frame, pcm);
331         }
332 #endif
333 
334         // decode codec frame
335         uint8_t tmp_BEC_detect;
336         (void) lc3_decoder->decode_signed_16(&decoder_contexts[0], buffer, octets_per_frame, BFI, pcm, 1, &tmp_BEC_detect);
337 
338         uint32_t block_decoded_ms  = btstack_run_loop_get_time_ms();
339 
340 #ifdef HAVE_POSIX_FILE_IO
341         wav_writer_write_int16(number_samples_per_frame, pcm);
342         if (BFI){
343             // insert silence after for analysis in audacity
344             memset(pcm, 0, sizeof(pcm));
345             wav_writer_write_int16(number_samples_per_frame, pcm);
346         }
347 #endif
348 
349         // summary
350         player_ms  += block_generated_ms - block_start_ms;
351         encoder_ms += block_encoded_ms   - block_generated_ms;
352         decoder_ms += block_decoded_ms   - block_encoded_ms;
353     }
354     printf("Player:  time %5u ms, duty cycle %3u %%\n", player_ms,  player_ms  / audio_duration_in_seconds / 10);
355     printf("Encoder: time %5u ms, duty cycle %3u %%\n", encoder_ms, encoder_ms / audio_duration_in_seconds / 10);
356     printf("Decoder: time %5u ms, duty cycle %3u %%\n", decoder_ms, decoder_ms / audio_duration_in_seconds / 10);
357 
358 #ifdef HAVE_POSIX_FILE_IO
359     wav_writer_close();
360 #endif
361 }
362 
363 static void show_usage(void){
364     printf("\n--- LC3 Encoder Test Console ---\n");
365     print_config();
366     printf("---\n");
367     printf("f - next sampling frequency\n");
368     printf("v - next codec variant\n");
369     printf("t - toggle sine / modplayer\n");
370     printf("p - simulated dropped frames\n");
371     printf("s - start test\n");
372     printf("---\n");
373 }
374 
375 static void stdin_process(char c){
376     switch (c){
377         case 'p':
378             plc_dopped_frame_interval = 16 - plc_dopped_frame_interval;
379             print_config();
380             break;
381         case 'f':
382             menu_sampling_frequency++;
383             if (menu_sampling_frequency >= 6){
384                 menu_sampling_frequency = 0;
385             }
386             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
387                 menu_variant = 0;
388             }
389             print_config();
390             break;
391         case 'v':
392             menu_variant++;
393             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
394                 menu_variant = 0;
395             }
396             print_config();
397             break;
398         case 's':
399             // use values from table
400             sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz;
401             octets_per_frame      = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame;
402             frame_duration        = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration;
403 
404             // get num samples per frame
405             setup_lc3_encoder();
406             setup_lc3_decoder();
407 
408             // setup mod player
409             setup_mod_player();
410 
411             // setup sine generator
412             if (sampling_frequency_hz == 44100){
413                 sine_step = 2;
414             } else {
415                 sine_step = 96000 / sampling_frequency_hz;
416             }
417             test_encoder();
418             break;
419         case 't':
420             audio_source = 1 - audio_source;
421             print_config();
422             break;
423         case '\n':
424         case '\r':
425             break;
426         default:
427             show_usage();
428             break;
429     }
430 }
431 
432 int btstack_main(int argc, const char * argv[]);
433 int btstack_main(int argc, const char * argv[]){
434     (void) argv;
435     (void) argc;
436     btstack_stdin_setup(stdin_process);
437     // default config
438     menu_sampling_frequency = 5;
439     menu_variant = 4;
440     audio_source = AUDIO_SOURCE_SINE;
441     show_usage();
442     return 0;
443 }
444