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