124b69d49SMatthias Ringwald /* 224b69d49SMatthias Ringwald * Copyright (C) {copyright_year} BlueKitchen GmbH 324b69d49SMatthias Ringwald * 424b69d49SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 524b69d49SMatthias Ringwald * modification, are permitted provided that the following conditions 624b69d49SMatthias Ringwald * are met: 724b69d49SMatthias Ringwald * 824b69d49SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 924b69d49SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 1024b69d49SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 1124b69d49SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 1224b69d49SMatthias Ringwald * documentation and/or other materials provided with the distribution. 1324b69d49SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 1424b69d49SMatthias Ringwald * contributors may be used to endorse or promote products derived 1524b69d49SMatthias Ringwald * from this software without specific prior written permission. 1624b69d49SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 1724b69d49SMatthias Ringwald * personal benefit and not for any commercial purpose or for 1824b69d49SMatthias Ringwald * monetary gain. 1924b69d49SMatthias Ringwald * 2024b69d49SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 2124b69d49SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2224b69d49SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2324b69d49SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 2424b69d49SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2524b69d49SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2624b69d49SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2724b69d49SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2824b69d49SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2924b69d49SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3024b69d49SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3124b69d49SMatthias Ringwald * SUCH DAMAGE. 3224b69d49SMatthias Ringwald * 3324b69d49SMatthias Ringwald * Please inquire about commercial licensing options at 3424b69d49SMatthias Ringwald * [email protected] 3524b69d49SMatthias Ringwald * 3624b69d49SMatthias Ringwald */ 3724b69d49SMatthias Ringwald 3824b69d49SMatthias Ringwald #define BTSTACK_FILE__ "le_audio_demo_util_source.c" 3924b69d49SMatthias Ringwald 4024b69d49SMatthias Ringwald #include "le_audio_demo_util_source.h" 4124b69d49SMatthias Ringwald 429d8b6c89SDirk Helbig #include <stdio.h> 43*65e76442SMatthias Ringwald #include <inttypes.h> 44*65e76442SMatthias Ringwald #include <math.h> 45*65e76442SMatthias Ringwald 46*65e76442SMatthias Ringwald #include "btstack_config.h" 47*65e76442SMatthias Ringwald #include "btstack_bool.h" 48*65e76442SMatthias Ringwald #include "btstack_debug.h" 49*65e76442SMatthias Ringwald #include "btstack_ring_buffer.h" 5024b69d49SMatthias Ringwald 5124b69d49SMatthias Ringwald #include "hci.h" 5224b69d49SMatthias Ringwald #include "btstack_audio.h" 5324b69d49SMatthias Ringwald #include "btstack_lc3_google.h" 5424b69d49SMatthias Ringwald #include "btstack_lc3plus_fraunhofer.h" 5524b69d49SMatthias Ringwald 5624b69d49SMatthias Ringwald #include "hxcmod.h" 5724b69d49SMatthias Ringwald #include "mods/mod.h" 5824b69d49SMatthias Ringwald 59*65e76442SMatthias Ringwald #define MAX_CHANNELS 5 60*65e76442SMatthias Ringwald #define MAX_SAMPLES_PER_10MS_FRAME 480 6124b69d49SMatthias Ringwald #define MAX_LC3_FRAME_BYTES 155 6224b69d49SMatthias Ringwald 63*65e76442SMatthias Ringwald // live recording 64*65e76442SMatthias Ringwald #define RECORDING_PREBUFFER__MS 20 65*65e76442SMatthias Ringwald #define RECORDING_BUFFER_MS 40 6624b69d49SMatthias Ringwald 6724b69d49SMatthias Ringwald // SOURCE 68*65e76442SMatthias Ringwald static float sine_frequencies[MAX_CHANNELS] = { 69*65e76442SMatthias Ringwald 261.63, // C-4 70*65e76442SMatthias Ringwald 311.13, // Es-4 71*65e76442SMatthias Ringwald 369.99, // G-4 72*65e76442SMatthias Ringwald 493.88, // B-4 73*65e76442SMatthias Ringwald 587.33, // D-5 7424b69d49SMatthias Ringwald }; 7524b69d49SMatthias Ringwald 76*65e76442SMatthias Ringwald // 48000 / 261.6 = 183.46 77*65e76442SMatthias Ringwald #define SINE_MAX_SAMPLES_AT_48KHZ 185 78*65e76442SMatthias Ringwald #define PI 3.14159265358979323846 79*65e76442SMatthias Ringwald 80*65e76442SMatthias Ringwald static int16_t sine_table[MAX_CHANNELS * SINE_MAX_SAMPLES_AT_48KHZ]; 81*65e76442SMatthias Ringwald 8224b69d49SMatthias Ringwald static uint16_t le_audio_demo_source_octets_per_frame; 8324b69d49SMatthias Ringwald static uint16_t le_audio_demo_source_packet_sequence_numbers[MAX_CHANNELS]; 8424b69d49SMatthias Ringwald static uint8_t le_audio_demo_source_iso_frame_counter; 8524b69d49SMatthias Ringwald static uint32_t le_audio_demo_source_sampling_frequency_hz; 8624b69d49SMatthias Ringwald static btstack_lc3_frame_duration_t le_audio_demo_source_frame_duration; 8724b69d49SMatthias Ringwald static uint8_t le_audio_demo_source_num_channels; 8824b69d49SMatthias Ringwald static uint8_t le_audio_demo_source_num_streams; 8924b69d49SMatthias Ringwald static uint8_t le_audio_demo_source_num_channels_per_stream; 9024b69d49SMatthias Ringwald static uint16_t le_audio_demo_source_num_samples_per_frame; 9124b69d49SMatthias Ringwald 9224b69d49SMatthias Ringwald 9324b69d49SMatthias Ringwald static uint8_t le_audio_demo_source_iso_payload[MAX_CHANNELS * MAX_LC3_FRAME_BYTES]; 9424b69d49SMatthias Ringwald 9524b69d49SMatthias Ringwald // lc3 encoder 9624b69d49SMatthias Ringwald static const btstack_lc3_encoder_t * le_audio_demo_source_lc3_encoder; 9724b69d49SMatthias Ringwald static btstack_lc3_encoder_google_t le_audio_demo_source_encoder_contexts[MAX_CHANNELS]; 98*65e76442SMatthias Ringwald static int16_t le_audio_demo_source_pcm[MAX_CHANNELS * MAX_SAMPLES_PER_10MS_FRAME]; 9924b69d49SMatthias Ringwald 10024b69d49SMatthias Ringwald // sine generator 101*65e76442SMatthias Ringwald static uint16_t le_audio_demo_source_sine_samples[MAX_CHANNELS]; 10224b69d49SMatthias Ringwald static uint16_t le_audio_demo_source_sine_phases[MAX_CHANNELS]; 10324b69d49SMatthias Ringwald 10424b69d49SMatthias Ringwald // mod player 10524b69d49SMatthias Ringwald static bool le_audio_demo_source_hxcmod_initialized; 10624b69d49SMatthias Ringwald static modcontext le_audio_demo_source_hxcmod_context; 10724b69d49SMatthias Ringwald static tracker_buffer_state le_audio_demo_source_hxcmod_trkbuf; 10824b69d49SMatthias Ringwald 109*65e76442SMatthias Ringwald // recording / portaudio 110*65e76442SMatthias Ringwald #define SAMPLES_PER_CHANNEL_RECORDING (MAX_SAMPLES_PER_10MS_FRAME * RECORDING_BUFFER_MS / 10) 111*65e76442SMatthias Ringwald static uint8_t recording_storage[MAX_CHANNELS * 2 * SAMPLES_PER_CHANNEL_RECORDING]; 112*65e76442SMatthias Ringwald static btstack_ring_buffer_t le_audio_demo_source_recording_buffer; 113*65e76442SMatthias Ringwald static uint16_t le_audio_demo_source_recording_stored_samples; 114*65e76442SMatthias Ringwald static uint16_t le_audio_demo_source_recording_prebuffer_samples; 115*65e76442SMatthias Ringwald static bool le_audio_demo_source_recording_streaming; 116*65e76442SMatthias Ringwald static btstack_audio_source_t const * le_audio_demo_audio_source; 117*65e76442SMatthias Ringwald 118*65e76442SMatthias Ringwald // generation method 119*65e76442SMatthias Ringwald static le_audio_demo_source_generator le_audio_demo_util_source_generator = AUDIO_SOURCE_SINE; 120*65e76442SMatthias Ringwald 121*65e76442SMatthias Ringwald // recording callback has channels interleaved, collect per channel 122*65e76442SMatthias Ringwald static void le_audio_util_source_recording_callback(const int16_t * buffer, uint16_t num_samples){ 123*65e76442SMatthias Ringwald log_info("store %u samples per channel", num_samples); 124*65e76442SMatthias Ringwald uint32_t bytes_to_store = le_audio_demo_source_num_channels * num_samples * 2; 125*65e76442SMatthias Ringwald if (bytes_to_store < btstack_ring_buffer_bytes_free(&le_audio_demo_source_recording_buffer)){ 126*65e76442SMatthias Ringwald btstack_ring_buffer_write(&le_audio_demo_source_recording_buffer, (uint8_t *)buffer, bytes_to_store); 127*65e76442SMatthias Ringwald le_audio_demo_source_recording_stored_samples += num_samples; 128*65e76442SMatthias Ringwald } 129*65e76442SMatthias Ringwald } 130*65e76442SMatthias Ringwald 13124b69d49SMatthias Ringwald void le_audio_demo_util_source_init(void) { 132*65e76442SMatthias Ringwald le_audio_demo_audio_source = btstack_audio_source_get_instance(); 133*65e76442SMatthias Ringwald } 134*65e76442SMatthias Ringwald 135*65e76442SMatthias Ringwald static bool le_audio_demo_util_source_recording_start(void){ 136*65e76442SMatthias Ringwald bool ok = false; 137*65e76442SMatthias Ringwald if (le_audio_demo_audio_source != NULL){ 138*65e76442SMatthias Ringwald int init_ok = le_audio_demo_audio_source->init(le_audio_demo_source_num_channels, le_audio_demo_source_sampling_frequency_hz, 139*65e76442SMatthias Ringwald &le_audio_util_source_recording_callback); 140*65e76442SMatthias Ringwald log_info("recording initialized, ok %u", init_ok); 141*65e76442SMatthias Ringwald if (init_ok){ 142*65e76442SMatthias Ringwald btstack_ring_buffer_init(&le_audio_demo_source_recording_buffer, recording_storage, sizeof(recording_storage)); 143*65e76442SMatthias Ringwald le_audio_demo_source_recording_prebuffer_samples = le_audio_demo_source_num_channels * le_audio_demo_source_sampling_frequency_hz * RECORDING_PREBUFFER__MS / 1000; 144*65e76442SMatthias Ringwald le_audio_demo_source_recording_streaming = false; 145*65e76442SMatthias Ringwald le_audio_demo_source_recording_stored_samples = 0; 146*65e76442SMatthias Ringwald le_audio_demo_audio_source->start_stream(); 147*65e76442SMatthias Ringwald log_info("recording start, %u prebuffer samples per channel", le_audio_demo_source_recording_prebuffer_samples / le_audio_demo_source_num_channels); 148*65e76442SMatthias Ringwald ok = true; 149*65e76442SMatthias Ringwald } 150*65e76442SMatthias Ringwald } 151*65e76442SMatthias Ringwald return ok; 152*65e76442SMatthias Ringwald } 153*65e76442SMatthias Ringwald 154*65e76442SMatthias Ringwald static void le_audio_demo_util_source_recording_stop(void) { 155*65e76442SMatthias Ringwald le_audio_demo_audio_source->stop_stream(); 15624b69d49SMatthias Ringwald } 15724b69d49SMatthias Ringwald 15824b69d49SMatthias Ringwald static void le_audio_demo_source_setup_lc3_encoder(void){ 15924b69d49SMatthias Ringwald uint8_t channel; 16024b69d49SMatthias Ringwald for (channel = 0 ; channel < le_audio_demo_source_num_channels ; channel++){ 16124b69d49SMatthias Ringwald btstack_lc3_encoder_google_t * context = &le_audio_demo_source_encoder_contexts[channel]; 16224b69d49SMatthias Ringwald le_audio_demo_source_lc3_encoder = btstack_lc3_encoder_google_init_instance(context); 16324b69d49SMatthias Ringwald le_audio_demo_source_lc3_encoder->configure(context, le_audio_demo_source_sampling_frequency_hz, le_audio_demo_source_frame_duration, le_audio_demo_source_octets_per_frame); 16424b69d49SMatthias Ringwald } 16524b69d49SMatthias Ringwald 166*65e76442SMatthias Ringwald printf("LC3 Encoder config: %" PRIu32 " hz, frame duration %s ms, num samples %u, num octets %u\n", 16724b69d49SMatthias Ringwald le_audio_demo_source_sampling_frequency_hz, le_audio_demo_source_frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10", 16824b69d49SMatthias Ringwald le_audio_demo_source_num_samples_per_frame, le_audio_demo_source_octets_per_frame); 16924b69d49SMatthias Ringwald } 17024b69d49SMatthias Ringwald 17124b69d49SMatthias Ringwald static void le_audio_demo_source_setup_mod_player(void){ 17224b69d49SMatthias Ringwald if (!le_audio_demo_source_hxcmod_initialized) { 17324b69d49SMatthias Ringwald le_audio_demo_source_hxcmod_initialized = hxcmod_init(&le_audio_demo_source_hxcmod_context); 17424b69d49SMatthias Ringwald btstack_assert(le_audio_demo_source_hxcmod_initialized != 0); 17524b69d49SMatthias Ringwald } 17624b69d49SMatthias Ringwald hxcmod_unload(&le_audio_demo_source_hxcmod_context); 17724b69d49SMatthias Ringwald hxcmod_setcfg(&le_audio_demo_source_hxcmod_context, le_audio_demo_source_sampling_frequency_hz, 16, 1, 1, 1); 17824b69d49SMatthias Ringwald hxcmod_load(&le_audio_demo_source_hxcmod_context, (void *) &mod_data, mod_len); 17924b69d49SMatthias Ringwald } 18024b69d49SMatthias Ringwald 181*65e76442SMatthias Ringwald static void le_audio_demo_source_setup_sine_generator(void){ 182*65e76442SMatthias Ringwald // pre-compute sine for all channels 183*65e76442SMatthias Ringwald uint8_t channel; 184*65e76442SMatthias Ringwald for (channel = 0; channel < MAX_CHANNELS ; channel++){ 185*65e76442SMatthias Ringwald float frequency_hz = (float) sine_frequencies[channel]; 186*65e76442SMatthias Ringwald float samplerate_hz = (float) le_audio_demo_source_sampling_frequency_hz; 187*65e76442SMatthias Ringwald float period_samples =samplerate_hz / frequency_hz; 188*65e76442SMatthias Ringwald le_audio_demo_source_sine_samples[channel] = (uint16_t) period_samples; 189*65e76442SMatthias Ringwald le_audio_demo_source_sine_phases[channel] = 0; 190*65e76442SMatthias Ringwald uint16_t i; 191*65e76442SMatthias Ringwald for (i=0;i<le_audio_demo_source_sine_samples[channel] ;i++){ 192*65e76442SMatthias Ringwald float sine_value = sin(2 * PI * i / period_samples); 193*65e76442SMatthias Ringwald sine_table[channel*SINE_MAX_SAMPLES_AT_48KHZ + i] = (int16_t)(sine_value * 32767); 194*65e76442SMatthias Ringwald } 195*65e76442SMatthias Ringwald } 196*65e76442SMatthias Ringwald } 197*65e76442SMatthias Ringwald 19824b69d49SMatthias Ringwald void le_audio_demo_util_source_configure(uint8_t num_streams, uint8_t num_channels_per_stream, uint32_t sampling_frequency_hz, 19924b69d49SMatthias Ringwald btstack_lc3_frame_duration_t frame_duration, uint16_t octets_per_frame) { 20024b69d49SMatthias Ringwald le_audio_demo_source_sampling_frequency_hz = sampling_frequency_hz; 20124b69d49SMatthias Ringwald le_audio_demo_source_frame_duration = frame_duration; 20224b69d49SMatthias Ringwald le_audio_demo_source_octets_per_frame = octets_per_frame; 20324b69d49SMatthias Ringwald le_audio_demo_source_num_streams = num_streams; 20424b69d49SMatthias Ringwald le_audio_demo_source_num_channels_per_stream = num_channels_per_stream; 20524b69d49SMatthias Ringwald 20624b69d49SMatthias Ringwald le_audio_demo_source_num_channels = num_streams * num_channels_per_stream; 207*65e76442SMatthias Ringwald btstack_assert((le_audio_demo_source_num_channels > 0) || (le_audio_demo_source_num_channels <= MAX_CHANNELS)); 20824b69d49SMatthias Ringwald 20924b69d49SMatthias Ringwald le_audio_demo_source_num_samples_per_frame = btstack_lc3_samples_per_frame(sampling_frequency_hz, frame_duration); 210*65e76442SMatthias Ringwald btstack_assert(le_audio_demo_source_num_samples_per_frame <= MAX_SAMPLES_PER_10MS_FRAME); 21124b69d49SMatthias Ringwald 21224b69d49SMatthias Ringwald // setup encoder 21324b69d49SMatthias Ringwald le_audio_demo_source_setup_lc3_encoder(); 21424b69d49SMatthias Ringwald 21524b69d49SMatthias Ringwald // setup sine generator 216*65e76442SMatthias Ringwald le_audio_demo_source_setup_sine_generator(); 21724b69d49SMatthias Ringwald 21824b69d49SMatthias Ringwald // setup mod player 21924b69d49SMatthias Ringwald le_audio_demo_source_setup_mod_player(); 220*65e76442SMatthias Ringwald } 22124b69d49SMatthias Ringwald 22224b69d49SMatthias Ringwald void le_audio_demo_util_source_generate_iso_frame(le_audio_demo_source_generator generator) { 22324b69d49SMatthias Ringwald btstack_assert(le_audio_demo_source_octets_per_frame != 0); 22424b69d49SMatthias Ringwald uint16_t sample; 22524b69d49SMatthias Ringwald bool encode_pcm = true; 226*65e76442SMatthias Ringwald 227*65e76442SMatthias Ringwald // lazy init of btstack_audio, fallback to sine 228*65e76442SMatthias Ringwald if ((generator == AUDIO_SOURCE_RECORDING) && (le_audio_demo_util_source_generator != AUDIO_SOURCE_RECORDING)){ 229*65e76442SMatthias Ringwald bool ok = le_audio_demo_util_source_recording_start(); 230*65e76442SMatthias Ringwald if (ok) { 231*65e76442SMatthias Ringwald le_audio_demo_util_source_generator = generator; 232*65e76442SMatthias Ringwald } else { 233*65e76442SMatthias Ringwald generator = AUDIO_SOURCE_SINE; 234*65e76442SMatthias Ringwald } 235*65e76442SMatthias Ringwald } 236*65e76442SMatthias Ringwald 237*65e76442SMatthias Ringwald // stop recording 238*65e76442SMatthias Ringwald if ((generator != AUDIO_SOURCE_RECORDING) && (le_audio_demo_util_source_generator == AUDIO_SOURCE_RECORDING)) { 239*65e76442SMatthias Ringwald le_audio_demo_util_source_recording_stop(); 240*65e76442SMatthias Ringwald } 241*65e76442SMatthias Ringwald 24224b69d49SMatthias Ringwald switch (generator){ 24324b69d49SMatthias Ringwald case AUDIO_SOURCE_COUNTER: 24424b69d49SMatthias Ringwald encode_pcm = false; 24524b69d49SMatthias Ringwald memset(le_audio_demo_source_iso_payload, le_audio_demo_source_iso_frame_counter++, sizeof(le_audio_demo_source_iso_payload)); 24624b69d49SMatthias Ringwald break; 24724b69d49SMatthias Ringwald case AUDIO_SOURCE_SINE: 248*65e76442SMatthias Ringwald // use pre-computed sine for all channels 24924b69d49SMatthias Ringwald for (sample = 0 ; sample < le_audio_demo_source_num_samples_per_frame ; sample++){ 25024b69d49SMatthias Ringwald uint8_t i; 25124b69d49SMatthias Ringwald for (i = 0; i < le_audio_demo_source_num_channels; i++) { 252*65e76442SMatthias Ringwald int16_t value = sine_table[i*SINE_MAX_SAMPLES_AT_48KHZ + le_audio_demo_source_sine_phases[i]]; 25324b69d49SMatthias Ringwald le_audio_demo_source_pcm[sample * le_audio_demo_source_num_channels + i] = value; 254*65e76442SMatthias Ringwald le_audio_demo_source_sine_phases[i] += 1; 255*65e76442SMatthias Ringwald if (le_audio_demo_source_sine_phases[i] >= le_audio_demo_source_sine_samples[i]) { 25624b69d49SMatthias Ringwald le_audio_demo_source_sine_phases[i] = 0; 25724b69d49SMatthias Ringwald } 25824b69d49SMatthias Ringwald } 25924b69d49SMatthias Ringwald } 26024b69d49SMatthias Ringwald break; 26124b69d49SMatthias Ringwald case AUDIO_SOURCE_MODPLAYER: 26224b69d49SMatthias Ringwald // mod player configured for stereo 26324b69d49SMatthias Ringwald hxcmod_fillbuffer(&le_audio_demo_source_hxcmod_context, (unsigned short *) le_audio_demo_source_pcm, le_audio_demo_source_num_samples_per_frame, &le_audio_demo_source_hxcmod_trkbuf); 26424b69d49SMatthias Ringwald // stereo -> mono 265*65e76442SMatthias Ringwald if (le_audio_demo_source_num_channels == 1) { 266b5232cd8SMatthias Ringwald uint16_t i; 26724b69d49SMatthias Ringwald for (i=0;i<le_audio_demo_source_num_samples_per_frame;i++){ 26824b69d49SMatthias Ringwald le_audio_demo_source_pcm[i] = (le_audio_demo_source_pcm[2*i] / 2) + (le_audio_demo_source_pcm[2*i+1] / 2); 26924b69d49SMatthias Ringwald } 27024b69d49SMatthias Ringwald } 271*65e76442SMatthias Ringwald // duplicate stereo channels 272*65e76442SMatthias Ringwald if (le_audio_demo_source_num_channels > 2) { 273*65e76442SMatthias Ringwald int16_t i; 274*65e76442SMatthias Ringwald for (i = le_audio_demo_source_num_samples_per_frame - 1; i >= 0; i--) { 275*65e76442SMatthias Ringwald uint16_t channel_dst; 276*65e76442SMatthias Ringwald for (channel_dst=0; channel_dst < le_audio_demo_source_num_channels; channel_dst++){ 277*65e76442SMatthias Ringwald uint16_t channel_src = channel_dst & 1; 278*65e76442SMatthias Ringwald le_audio_demo_source_pcm[i * le_audio_demo_source_num_channels + channel_dst] = 279*65e76442SMatthias Ringwald le_audio_demo_source_pcm[i * 2 + channel_src]; 280*65e76442SMatthias Ringwald } 281*65e76442SMatthias Ringwald } 282*65e76442SMatthias Ringwald } 283*65e76442SMatthias Ringwald break; 284*65e76442SMatthias Ringwald case AUDIO_SOURCE_RECORDING: 285*65e76442SMatthias Ringwald if (le_audio_demo_source_recording_streaming == false){ 286*65e76442SMatthias Ringwald if (le_audio_demo_source_recording_stored_samples >= le_audio_demo_source_recording_prebuffer_samples){ 287*65e76442SMatthias Ringwald // start streaming audio 288*65e76442SMatthias Ringwald le_audio_demo_source_recording_streaming = true; 289*65e76442SMatthias Ringwald log_info("Streaming started"); 290*65e76442SMatthias Ringwald 291*65e76442SMatthias Ringwald } 292*65e76442SMatthias Ringwald } 293*65e76442SMatthias Ringwald if (le_audio_demo_source_recording_streaming){ 294*65e76442SMatthias Ringwald uint32_t bytes_needed = le_audio_demo_source_num_channels * le_audio_demo_source_num_samples_per_frame * 2; 295*65e76442SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&le_audio_demo_source_recording_buffer) >= bytes_needed){ 296*65e76442SMatthias Ringwald uint32_t bytes_read; 297*65e76442SMatthias Ringwald btstack_ring_buffer_read(&le_audio_demo_source_recording_buffer, (uint8_t*) le_audio_demo_source_pcm, bytes_needed, &bytes_read); 298*65e76442SMatthias Ringwald btstack_assert(bytes_needed == bytes_needed); 299*65e76442SMatthias Ringwald log_info("Read %u samples per channel", le_audio_demo_source_num_samples_per_frame); 300*65e76442SMatthias Ringwald le_audio_demo_source_recording_stored_samples -= le_audio_demo_source_num_samples_per_frame; 301*65e76442SMatthias Ringwald } else { 302*65e76442SMatthias Ringwald le_audio_demo_source_recording_streaming = false; 303*65e76442SMatthias Ringwald log_info("Streaming underrun"); 304*65e76442SMatthias Ringwald } 305*65e76442SMatthias Ringwald } else { 306*65e76442SMatthias Ringwald memset(le_audio_demo_source_pcm, 0, sizeof(le_audio_demo_source_pcm)); 307*65e76442SMatthias Ringwald } 30824b69d49SMatthias Ringwald break; 30924b69d49SMatthias Ringwald default: 31024b69d49SMatthias Ringwald btstack_unreachable(); 31124b69d49SMatthias Ringwald break; 31224b69d49SMatthias Ringwald } 31324b69d49SMatthias Ringwald 31424b69d49SMatthias Ringwald if (encode_pcm){ 31524b69d49SMatthias Ringwald uint8_t i; 31624b69d49SMatthias Ringwald for (i=0;i<le_audio_demo_source_num_channels;i++){ 31724b69d49SMatthias Ringwald le_audio_demo_source_lc3_encoder->encode_signed_16(&le_audio_demo_source_encoder_contexts[i], &le_audio_demo_source_pcm[i], le_audio_demo_source_num_channels, &le_audio_demo_source_iso_payload[i * MAX_LC3_FRAME_BYTES]); 31824b69d49SMatthias Ringwald } 31924b69d49SMatthias Ringwald } 320*65e76442SMatthias Ringwald 321*65e76442SMatthias Ringwald le_audio_demo_util_source_generator = generator; 322*65e76442SMatthias Ringwald } 32324b69d49SMatthias Ringwald 32424b69d49SMatthias Ringwald void le_audio_demo_util_source_send(uint8_t stream_index, hci_con_handle_t con_handle){ 32524b69d49SMatthias Ringwald btstack_assert(le_audio_demo_source_octets_per_frame != 0); 32624b69d49SMatthias Ringwald 32783dfe5ceSMatthias Ringwald hci_reserve_packet_buffer(); 32824b69d49SMatthias Ringwald 32924b69d49SMatthias Ringwald uint8_t * buffer = hci_get_outgoing_packet_buffer(); 33024b69d49SMatthias Ringwald // complete SDU, no TimeStamp 33124b69d49SMatthias Ringwald little_endian_store_16(buffer, 0, ((uint16_t) con_handle) | (2 << 12)); 33224b69d49SMatthias Ringwald // len 33324b69d49SMatthias Ringwald little_endian_store_16(buffer, 2, 0 + 4 + le_audio_demo_source_num_channels_per_stream * le_audio_demo_source_octets_per_frame); 33424b69d49SMatthias Ringwald // TimeStamp if TS flag is set 33524b69d49SMatthias Ringwald // packet seq nr 33624b69d49SMatthias Ringwald little_endian_store_16(buffer, 4, le_audio_demo_source_packet_sequence_numbers[stream_index]); 33724b69d49SMatthias Ringwald // iso sdu len 33824b69d49SMatthias Ringwald little_endian_store_16(buffer, 6, le_audio_demo_source_num_channels_per_stream * le_audio_demo_source_octets_per_frame); 33924b69d49SMatthias Ringwald uint16_t offset = 8; 34024b69d49SMatthias Ringwald // copy encoded payload 34124b69d49SMatthias Ringwald uint8_t i; 34224b69d49SMatthias Ringwald for (i=0; i<le_audio_demo_source_num_channels_per_stream;i++) { 3430ab066e8SMatthias Ringwald uint8_t effective_channel = (stream_index * le_audio_demo_source_num_channels_per_stream) + i; 3440ab066e8SMatthias Ringwald memcpy(&buffer[offset], &le_audio_demo_source_iso_payload[effective_channel * MAX_LC3_FRAME_BYTES], le_audio_demo_source_octets_per_frame); 34524b69d49SMatthias Ringwald offset += le_audio_demo_source_octets_per_frame; 34624b69d49SMatthias Ringwald } 34724b69d49SMatthias Ringwald // send 34824b69d49SMatthias Ringwald hci_send_iso_packet_buffer(offset); 34924b69d49SMatthias Ringwald 35024b69d49SMatthias Ringwald le_audio_demo_source_packet_sequence_numbers[stream_index]++; 35124b69d49SMatthias Ringwald } 35224b69d49SMatthias Ringwald 35324b69d49SMatthias Ringwald void le_audio_demo_util_source_close(void){ 354*65e76442SMatthias Ringwald if (le_audio_demo_audio_source != NULL){ 355*65e76442SMatthias Ringwald le_audio_demo_audio_source->close(); 356*65e76442SMatthias Ringwald } 35724b69d49SMatthias Ringwald } 358