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