1d60a1028SMatthias Ringwald /* 2d60a1028SMatthias Ringwald * Copyright (C) 2022 BlueKitchen GmbH 3d60a1028SMatthias Ringwald * 4d60a1028SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5d60a1028SMatthias Ringwald * modification, are permitted provided that the following conditions 6d60a1028SMatthias Ringwald * are met: 7d60a1028SMatthias Ringwald * 8d60a1028SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9d60a1028SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10d60a1028SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11d60a1028SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12d60a1028SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13d60a1028SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14d60a1028SMatthias Ringwald * contributors may be used to endorse or promote products derived 15d60a1028SMatthias Ringwald * from this software without specific prior written permission. 16d60a1028SMatthias Ringwald * 17d60a1028SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 18d60a1028SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19d60a1028SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20d60a1028SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 21d60a1028SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22d60a1028SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23d60a1028SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 24d60a1028SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25d60a1028SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26d60a1028SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27d60a1028SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28d60a1028SMatthias Ringwald * SUCH DAMAGE. 29d60a1028SMatthias Ringwald * 30d60a1028SMatthias Ringwald */ 31d60a1028SMatthias Ringwald 32d60a1028SMatthias Ringwald #define BTSTACK_FILE__ "btstack_lc3_plus_fraunhofer.c" 33d60a1028SMatthias Ringwald 34d60a1028SMatthias Ringwald /** 35d60a1028SMatthias Ringwald * @title LC3 Plus Fraunhofer Adapter 36d60a1028SMatthias Ringwald */ 37d60a1028SMatthias Ringwald 38d60a1028SMatthias Ringwald #include "btstack_config.h" 39d60a1028SMatthias Ringwald #include "bluetooth.h" 40d60a1028SMatthias Ringwald 41d60a1028SMatthias Ringwald #include "btstack_lc3plus_fraunhofer.h" 42d60a1028SMatthias Ringwald #include "btstack_debug.h" 43d60a1028SMatthias Ringwald #include <string.h> 44d60a1028SMatthias Ringwald 45d60a1028SMatthias Ringwald #ifdef HAVE_LC3PLUS 46d60a1028SMatthias Ringwald 47d60a1028SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480 48d60a1028SMatthias Ringwald 49d60a1028SMatthias Ringwald static uint8_t lc3plus_farunhofer_scratch[LC3PLUS_DEC_MAX_SCRATCH_SIZE]; 50d60a1028SMatthias Ringwald 51d60a1028SMatthias Ringwald static uint16_t lc3_frame_duration_in_us(btstack_lc3_frame_duration_t frame_duration){ 52d60a1028SMatthias Ringwald switch (frame_duration) { 53d60a1028SMatthias Ringwald case BTSTACK_LC3_FRAME_DURATION_7500US: 54d60a1028SMatthias Ringwald return 7500; 55d60a1028SMatthias Ringwald case BTSTACK_LC3_FRAME_DURATION_10000US: 56d60a1028SMatthias Ringwald return 10000; 57d60a1028SMatthias Ringwald default: 58d60a1028SMatthias Ringwald return 0; 59d60a1028SMatthias Ringwald } 60d60a1028SMatthias Ringwald } 61d60a1028SMatthias Ringwald 62d60a1028SMatthias Ringwald /* Decoder implementation */ 63d60a1028SMatthias Ringwald 64d60a1028SMatthias Ringwald static uint8_t lc3plus_fraunhofer_decoder_configure(void * context, uint32_t sample_rate, btstack_lc3_frame_duration_t frame_duration, uint16_t octets_per_frame){ 65d60a1028SMatthias Ringwald btstack_lc3plus_fraunhofer_decoder_t * instance = (btstack_lc3plus_fraunhofer_decoder_t *) context; 66d60a1028SMatthias Ringwald LC3PLUS_Dec * decoder = (LC3PLUS_Dec*) instance->decoder; 67d60a1028SMatthias Ringwald 68d60a1028SMatthias Ringwald // map frame duration 69d60a1028SMatthias Ringwald uint16_t duration_us = lc3_frame_duration_in_us(frame_duration); 70d60a1028SMatthias Ringwald if (duration_us == 0){ 71d60a1028SMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 72d60a1028SMatthias Ringwald } 73d60a1028SMatthias Ringwald 74d60a1028SMatthias Ringwald // store config 75d60a1028SMatthias Ringwald instance->sample_rate = sample_rate; 76d60a1028SMatthias Ringwald instance->frame_duration = frame_duration; 77d60a1028SMatthias Ringwald instance->octets_per_frame = octets_per_frame; 78d60a1028SMatthias Ringwald instance->samples_per_frame = btstack_lc3_samples_per_frame(sample_rate, frame_duration); 79d60a1028SMatthias Ringwald 80d60a1028SMatthias Ringwald LC3PLUS_Error error; 81d60a1028SMatthias Ringwald error = lc3plus_dec_init(decoder, sample_rate, 1, LC3PLUS_PLC_ADVANCED, 0); 82d60a1028SMatthias Ringwald btstack_assert(error == LC3PLUS_OK); 83d60a1028SMatthias Ringwald 84d60a1028SMatthias Ringwald error = lc3plus_dec_set_frame_dms(decoder, duration_us / 100); 85d60a1028SMatthias Ringwald btstack_assert(error == LC3PLUS_OK); 86d60a1028SMatthias Ringwald 87d60a1028SMatthias Ringwald return ERROR_CODE_SUCCESS; 88d60a1028SMatthias Ringwald } 89d60a1028SMatthias Ringwald 90d60a1028SMatthias Ringwald static uint8_t lc3plus_fraunhofer_decoder_decode_signed_16(void * context, const uint8_t *bytes, uint8_t BFI, int16_t* pcm_out, uint16_t stride, uint8_t * BEC_detect) { 91d60a1028SMatthias Ringwald btstack_lc3plus_fraunhofer_decoder_t *instance = (btstack_lc3plus_fraunhofer_decoder_t *) context; 92d60a1028SMatthias Ringwald LC3PLUS_Dec *decoder = (LC3PLUS_Dec *) instance->decoder; 93d60a1028SMatthias Ringwald 94d60a1028SMatthias Ringwald // temporary output buffer to interleave samples for caller 95d60a1028SMatthias Ringwald int16_t temp_out[MAX_SAMPLES_PER_FRAME]; 96d60a1028SMatthias Ringwald 97d60a1028SMatthias Ringwald // output_samples: array of channel buffers. use temp_out if stride is used 98d60a1028SMatthias Ringwald int16_t *output_samples[1]; 99d60a1028SMatthias Ringwald if (stride > 1) { 100d60a1028SMatthias Ringwald output_samples[0] = temp_out; 101d60a1028SMatthias Ringwald } else { 102d60a1028SMatthias Ringwald output_samples[0] = pcm_out; 103d60a1028SMatthias Ringwald } 104d60a1028SMatthias Ringwald 105d60a1028SMatthias Ringwald // trigger plc if BFI by passing 0 valid input bytes 106d60a1028SMatthias Ringwald uint16_t byte_count = instance->octets_per_frame; 107d60a1028SMatthias Ringwald if (BFI != 0){ 108d60a1028SMatthias Ringwald byte_count = 0; 109d60a1028SMatthias Ringwald } 110d60a1028SMatthias Ringwald 111d60a1028SMatthias Ringwald LC3PLUS_Error error = lc3plus_dec16(decoder, (void*) bytes, byte_count, output_samples, lc3plus_farunhofer_scratch, BFI); 112d60a1028SMatthias Ringwald 113d60a1028SMatthias Ringwald // store samples 114d60a1028SMatthias Ringwald if (stride > 1){ 115d60a1028SMatthias Ringwald uint16_t i; 116d60a1028SMatthias Ringwald for (i = 0; i < instance->samples_per_frame; i++){ 117*80ad9928SMatthias Ringwald // cppcheck-suppress uninitvar ; for stride > 1, output_samples[0] = temp_out, which is initialized by lc3plus_dec16 118d60a1028SMatthias Ringwald pcm_out [i * stride] = temp_out[i]; 119d60a1028SMatthias Ringwald } 120d60a1028SMatthias Ringwald } 121d60a1028SMatthias Ringwald 122d60a1028SMatthias Ringwald // map error 123d60a1028SMatthias Ringwald switch (error){ 124d60a1028SMatthias Ringwald case LC3PLUS_OK: 125d60a1028SMatthias Ringwald // success 126d60a1028SMatthias Ringwald return ERROR_CODE_SUCCESS; 127d60a1028SMatthias Ringwald case LC3PLUS_DECODE_ERROR: 128d60a1028SMatthias Ringwald // PLC enagaged 129d60a1028SMatthias Ringwald *BEC_detect = 1; 130d60a1028SMatthias Ringwald return ERROR_CODE_SUCCESS; 131d60a1028SMatthias Ringwald default: 132d60a1028SMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 133d60a1028SMatthias Ringwald } 134d60a1028SMatthias Ringwald } 135d60a1028SMatthias Ringwald 136d60a1028SMatthias Ringwald static uint8_t lc3plus_fraunhofer_decoder_decode_signed_24(void * context, const uint8_t *bytes, uint8_t BFI, int32_t* pcm_out, uint16_t stride, uint8_t * BEC_detect) { 137d60a1028SMatthias Ringwald btstack_lc3plus_fraunhofer_decoder_t * instance = (btstack_lc3plus_fraunhofer_decoder_t *) context; 138d60a1028SMatthias Ringwald LC3PLUS_Dec * decoder = (LC3PLUS_Dec*) instance->decoder; 139d60a1028SMatthias Ringwald 140d60a1028SMatthias Ringwald // output_samples: array of channel buffers. 141d60a1028SMatthias Ringwald int32_t * output_samples[1]; 142d60a1028SMatthias Ringwald output_samples[0] = pcm_out; 143d60a1028SMatthias Ringwald 144d60a1028SMatthias Ringwald // trigger plc if BFI by passing 0 valid input bytes 145d60a1028SMatthias Ringwald uint16_t byte_count = instance->octets_per_frame; 146d60a1028SMatthias Ringwald if (BFI != 0){ 147d60a1028SMatthias Ringwald byte_count = 0; 148d60a1028SMatthias Ringwald } 149d60a1028SMatthias Ringwald 150d60a1028SMatthias Ringwald LC3PLUS_Error error = lc3plus_dec24(decoder, (void *) bytes, byte_count, output_samples, lc3plus_farunhofer_scratch, BFI); 151d60a1028SMatthias Ringwald 152d60a1028SMatthias Ringwald // map error 153d60a1028SMatthias Ringwald switch (error){ 154d60a1028SMatthias Ringwald case LC3PLUS_OK: 155d60a1028SMatthias Ringwald // success 156d60a1028SMatthias Ringwald return ERROR_CODE_SUCCESS; 157d60a1028SMatthias Ringwald case LC3PLUS_DECODE_ERROR: 158d60a1028SMatthias Ringwald // PLC enagaged 159d60a1028SMatthias Ringwald *BEC_detect = 1; 160d60a1028SMatthias Ringwald return ERROR_CODE_SUCCESS; 161d60a1028SMatthias Ringwald default: 162d60a1028SMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 163d60a1028SMatthias Ringwald } 164d60a1028SMatthias Ringwald } 165d60a1028SMatthias Ringwald 166d60a1028SMatthias Ringwald static const btstack_lc3_decoder_t btstack_l3cplus_fraunhofer_decoder_instance = { 167d60a1028SMatthias Ringwald lc3plus_fraunhofer_decoder_configure, 168d60a1028SMatthias Ringwald lc3plus_fraunhofer_decoder_decode_signed_16, 169d60a1028SMatthias Ringwald lc3plus_fraunhofer_decoder_decode_signed_24 170d60a1028SMatthias Ringwald }; 171d60a1028SMatthias Ringwald 172d60a1028SMatthias Ringwald const btstack_lc3_decoder_t * btstack_lc3plus_fraunhofer_decoder_init_instance(btstack_lc3plus_fraunhofer_decoder_t * context){ 173d60a1028SMatthias Ringwald memset(context, 0, sizeof(btstack_lc3plus_fraunhofer_decoder_t)); 174d60a1028SMatthias Ringwald return &btstack_l3cplus_fraunhofer_decoder_instance; 175d60a1028SMatthias Ringwald } 176d60a1028SMatthias Ringwald 177d60a1028SMatthias Ringwald /* Encoder implementation */ 178d60a1028SMatthias Ringwald 179d60a1028SMatthias Ringwald static uint8_t lc3plus_fraunhofer_encoder_configure(void * context, uint32_t sample_rate, btstack_lc3_frame_duration_t frame_duration, uint16_t octets_per_frame){ 180d60a1028SMatthias Ringwald btstack_lc3plus_fraunhofer_encoder_t * instance = (btstack_lc3plus_fraunhofer_encoder_t *) context; 181d60a1028SMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 182d60a1028SMatthias Ringwald } 183d60a1028SMatthias Ringwald 184d60a1028SMatthias Ringwald static uint8_t lc3plus_fraunhofer_encoder_encode_signed_16(void * context, const int16_t* pcm_in, uint16_t stride, uint8_t *bytes){ 185d60a1028SMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 186d60a1028SMatthias Ringwald } 187d60a1028SMatthias Ringwald 188d60a1028SMatthias Ringwald static uint8_t lc3plus_fraunhofer_encoder_encode_signed_24(void * context, const int32_t* pcm_in, uint16_t stride, uint8_t *bytes) { 189d60a1028SMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 190d60a1028SMatthias Ringwald } 191d60a1028SMatthias Ringwald 192d60a1028SMatthias Ringwald static const btstack_lc3_encoder_t btstack_l3cplus_fraunhofer_encoder_instance = { 193d60a1028SMatthias Ringwald lc3plus_fraunhofer_encoder_configure, 194d60a1028SMatthias Ringwald lc3plus_fraunhofer_encoder_encode_signed_16, 195d60a1028SMatthias Ringwald lc3plus_fraunhofer_encoder_encode_signed_24 196d60a1028SMatthias Ringwald }; 197d60a1028SMatthias Ringwald 198d60a1028SMatthias Ringwald const btstack_lc3_encoder_t * btstack_lc3plus_fraunhofer_encoder_init_instance(btstack_lc3plus_fraunhofer_encoder_t * context){ 199d60a1028SMatthias Ringwald memset(context, 0, sizeof(btstack_lc3plus_fraunhofer_encoder_t)); 200d60a1028SMatthias Ringwald return &btstack_l3cplus_fraunhofer_encoder_instance; 201d60a1028SMatthias Ringwald } 202d60a1028SMatthias Ringwald 203d60a1028SMatthias Ringwald #endif /* HAVE_LC3PLUS */ 204