xref: /btstack/src/btstack_lc3plus_fraunhofer.c (revision 75b056dc9ae778c6f50a725bfc787b9c4ebd98f2)
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 
lc3_frame_duration_in_us(btstack_lc3_frame_duration_t frame_duration)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 
lc3plus_fraunhofer_decoder_configure(void * context,uint32_t sample_rate,btstack_lc3_frame_duration_t frame_duration,uint16_t octets_per_frame)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;
81*75b056dcSMatthias Ringwald #ifdef ENABLE_HR_MODE
82d60a1028SMatthias Ringwald     error = lc3plus_dec_init(decoder, sample_rate, 1, LC3PLUS_PLC_ADVANCED, 0);
83*75b056dcSMatthias Ringwald #else
84*75b056dcSMatthias Ringwald     error = lc3plus_dec_init(decoder, sample_rate, 1, LC3PLUS_PLC_ADVANCED);
85*75b056dcSMatthias Ringwald #endif
86d60a1028SMatthias Ringwald     btstack_assert(error == LC3PLUS_OK);
87d60a1028SMatthias Ringwald 
88d60a1028SMatthias Ringwald     error = lc3plus_dec_set_frame_dms(decoder, duration_us / 100);
89d60a1028SMatthias Ringwald     btstack_assert(error == LC3PLUS_OK);
90d60a1028SMatthias Ringwald 
91d60a1028SMatthias Ringwald     return ERROR_CODE_SUCCESS;
92d60a1028SMatthias Ringwald }
93d60a1028SMatthias Ringwald 
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)94d60a1028SMatthias 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) {
95d60a1028SMatthias Ringwald     btstack_lc3plus_fraunhofer_decoder_t *instance = (btstack_lc3plus_fraunhofer_decoder_t *) context;
96d60a1028SMatthias Ringwald     LC3PLUS_Dec *decoder = (LC3PLUS_Dec *) instance->decoder;
97d60a1028SMatthias Ringwald 
98d60a1028SMatthias Ringwald     // temporary output buffer to interleave samples for caller
99d60a1028SMatthias Ringwald     int16_t temp_out[MAX_SAMPLES_PER_FRAME];
100d60a1028SMatthias Ringwald 
101d60a1028SMatthias Ringwald     // output_samples: array of channel buffers. use temp_out if stride is used
102d60a1028SMatthias Ringwald     int16_t *output_samples[1];
103d60a1028SMatthias Ringwald     if (stride > 1) {
104d60a1028SMatthias Ringwald         output_samples[0] = temp_out;
105d60a1028SMatthias Ringwald     } else {
106d60a1028SMatthias Ringwald         output_samples[0] = pcm_out;
107d60a1028SMatthias Ringwald     }
108d60a1028SMatthias Ringwald 
109d60a1028SMatthias Ringwald     // trigger plc if BFI by passing 0 valid input bytes
110d60a1028SMatthias Ringwald     uint16_t byte_count = instance->octets_per_frame;
111d60a1028SMatthias Ringwald     if (BFI != 0){
112d60a1028SMatthias Ringwald         byte_count = 0;
113d60a1028SMatthias Ringwald     }
114d60a1028SMatthias Ringwald 
115d60a1028SMatthias Ringwald     LC3PLUS_Error error = lc3plus_dec16(decoder, (void*) bytes, byte_count, output_samples, lc3plus_farunhofer_scratch, BFI);
116d60a1028SMatthias Ringwald 
117d60a1028SMatthias Ringwald     // store samples
118d60a1028SMatthias Ringwald     if (stride > 1){
119d60a1028SMatthias Ringwald         uint16_t i;
120d60a1028SMatthias Ringwald         for (i = 0; i < instance->samples_per_frame; i++){
12180ad9928SMatthias Ringwald             // cppcheck-suppress uninitvar ; for stride > 1, output_samples[0] = temp_out, which is initialized by lc3plus_dec16
122d60a1028SMatthias Ringwald             pcm_out [i * stride] = temp_out[i];
123d60a1028SMatthias Ringwald         }
124d60a1028SMatthias Ringwald     }
125d60a1028SMatthias Ringwald 
126d60a1028SMatthias Ringwald     // map error
127d60a1028SMatthias Ringwald     switch (error){
128d60a1028SMatthias Ringwald         case LC3PLUS_OK:
129d60a1028SMatthias Ringwald             // success
130d60a1028SMatthias Ringwald             return ERROR_CODE_SUCCESS;
131d60a1028SMatthias Ringwald         case LC3PLUS_DECODE_ERROR:
132d60a1028SMatthias Ringwald             // PLC enagaged
133d60a1028SMatthias Ringwald             *BEC_detect = 1;
134d60a1028SMatthias Ringwald             return ERROR_CODE_SUCCESS;
135d60a1028SMatthias Ringwald         default:
136d60a1028SMatthias Ringwald             return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
137d60a1028SMatthias Ringwald     }
138d60a1028SMatthias Ringwald }
139d60a1028SMatthias Ringwald 
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)140d60a1028SMatthias 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) {
141d60a1028SMatthias Ringwald     btstack_lc3plus_fraunhofer_decoder_t * instance = (btstack_lc3plus_fraunhofer_decoder_t *) context;
142d60a1028SMatthias Ringwald     LC3PLUS_Dec * decoder = (LC3PLUS_Dec*) instance->decoder;
143d60a1028SMatthias Ringwald 
144d60a1028SMatthias Ringwald     // output_samples: array of channel buffers.
145d60a1028SMatthias Ringwald     int32_t * output_samples[1];
146d60a1028SMatthias Ringwald     output_samples[0] = pcm_out;
147d60a1028SMatthias Ringwald 
148d60a1028SMatthias Ringwald     // trigger plc if BFI by passing 0 valid input bytes
149d60a1028SMatthias Ringwald     uint16_t byte_count = instance->octets_per_frame;
150d60a1028SMatthias Ringwald     if (BFI != 0){
151d60a1028SMatthias Ringwald         byte_count = 0;
152d60a1028SMatthias Ringwald     }
153d60a1028SMatthias Ringwald 
154d60a1028SMatthias Ringwald     LC3PLUS_Error error = lc3plus_dec24(decoder, (void *) bytes, byte_count, output_samples, lc3plus_farunhofer_scratch, BFI);
155d60a1028SMatthias Ringwald 
156d60a1028SMatthias Ringwald     // map error
157d60a1028SMatthias Ringwald     switch (error){
158d60a1028SMatthias Ringwald         case LC3PLUS_OK:
159d60a1028SMatthias Ringwald             // success
160d60a1028SMatthias Ringwald             return ERROR_CODE_SUCCESS;
161d60a1028SMatthias Ringwald         case LC3PLUS_DECODE_ERROR:
162d60a1028SMatthias Ringwald             // PLC enagaged
163d60a1028SMatthias Ringwald             *BEC_detect = 1;
164d60a1028SMatthias Ringwald             return ERROR_CODE_SUCCESS;
165d60a1028SMatthias Ringwald         default:
166d60a1028SMatthias Ringwald             return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
167d60a1028SMatthias Ringwald     }
168d60a1028SMatthias Ringwald }
169d60a1028SMatthias Ringwald 
170d60a1028SMatthias Ringwald static const btstack_lc3_decoder_t btstack_l3cplus_fraunhofer_decoder_instance = {
171d60a1028SMatthias Ringwald         lc3plus_fraunhofer_decoder_configure,
172d60a1028SMatthias Ringwald         lc3plus_fraunhofer_decoder_decode_signed_16,
173d60a1028SMatthias Ringwald         lc3plus_fraunhofer_decoder_decode_signed_24
174d60a1028SMatthias Ringwald };
175d60a1028SMatthias Ringwald 
btstack_lc3plus_fraunhofer_decoder_init_instance(btstack_lc3plus_fraunhofer_decoder_t * context)176d60a1028SMatthias Ringwald const btstack_lc3_decoder_t * btstack_lc3plus_fraunhofer_decoder_init_instance(btstack_lc3plus_fraunhofer_decoder_t * context){
177d60a1028SMatthias Ringwald     memset(context, 0, sizeof(btstack_lc3plus_fraunhofer_decoder_t));
178d60a1028SMatthias Ringwald     return &btstack_l3cplus_fraunhofer_decoder_instance;
179d60a1028SMatthias Ringwald }
180d60a1028SMatthias Ringwald 
181d60a1028SMatthias Ringwald /* Encoder implementation */
182d60a1028SMatthias Ringwald 
lc3plus_fraunhofer_encoder_configure(void * context,uint32_t sample_rate,btstack_lc3_frame_duration_t frame_duration,uint16_t octets_per_frame)183d60a1028SMatthias 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){
184d60a1028SMatthias Ringwald     btstack_lc3plus_fraunhofer_encoder_t * instance = (btstack_lc3plus_fraunhofer_encoder_t *) context;
185d60a1028SMatthias Ringwald     return ERROR_CODE_COMMAND_DISALLOWED;
186d60a1028SMatthias Ringwald }
187d60a1028SMatthias Ringwald 
lc3plus_fraunhofer_encoder_encode_signed_16(void * context,const int16_t * pcm_in,uint16_t stride,uint8_t * bytes)188d60a1028SMatthias Ringwald static uint8_t lc3plus_fraunhofer_encoder_encode_signed_16(void * context, const int16_t* pcm_in, uint16_t stride, uint8_t *bytes){
189d60a1028SMatthias Ringwald     return ERROR_CODE_COMMAND_DISALLOWED;
190d60a1028SMatthias Ringwald }
191d60a1028SMatthias Ringwald 
lc3plus_fraunhofer_encoder_encode_signed_24(void * context,const int32_t * pcm_in,uint16_t stride,uint8_t * bytes)192d60a1028SMatthias Ringwald static uint8_t lc3plus_fraunhofer_encoder_encode_signed_24(void * context, const int32_t* pcm_in, uint16_t stride, uint8_t *bytes) {
193d60a1028SMatthias Ringwald     return ERROR_CODE_COMMAND_DISALLOWED;
194d60a1028SMatthias Ringwald }
195d60a1028SMatthias Ringwald 
196d60a1028SMatthias Ringwald static const btstack_lc3_encoder_t btstack_l3cplus_fraunhofer_encoder_instance = {
197d60a1028SMatthias Ringwald         lc3plus_fraunhofer_encoder_configure,
198d60a1028SMatthias Ringwald         lc3plus_fraunhofer_encoder_encode_signed_16,
199d60a1028SMatthias Ringwald         lc3plus_fraunhofer_encoder_encode_signed_24
200d60a1028SMatthias Ringwald };
201d60a1028SMatthias Ringwald 
btstack_lc3plus_fraunhofer_encoder_init_instance(btstack_lc3plus_fraunhofer_encoder_t * context)202d60a1028SMatthias Ringwald const btstack_lc3_encoder_t * btstack_lc3plus_fraunhofer_encoder_init_instance(btstack_lc3plus_fraunhofer_encoder_t * context){
203d60a1028SMatthias Ringwald     memset(context, 0, sizeof(btstack_lc3plus_fraunhofer_encoder_t));
204d60a1028SMatthias Ringwald     return &btstack_l3cplus_fraunhofer_encoder_instance;
205d60a1028SMatthias Ringwald }
206d60a1028SMatthias Ringwald 
207d60a1028SMatthias Ringwald #endif /* HAVE_LC3PLUS */
208