arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
CodecLC3.h
Go to the documentation of this file.
1
11#pragma once
12
13#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
14#include "lc3.h"
15
16namespace audio_tools {
17
18// 20 to 400
19#define DEFAULT_BYTE_COUNT 40
20// 7500 or 10000
21#define LC3_DEFAULT_DT_US 7500
22
31class LC3Decoder : public AudioDecoder {
32 public:
33 LC3Decoder(AudioInfo info, int dt_us = LC3_DEFAULT_DT_US,
34 uint16_t inputByteCount = DEFAULT_BYTE_COUNT) {
35 this->dt_us = dt_us;
36 this->info = info;
37 this->input_byte_count = inputByteCount;
38 }
39
40 LC3Decoder(int dt_us = LC3_DEFAULT_DT_US,
41 uint16_t inputByteCount = DEFAULT_BYTE_COUNT) {
42 this->dt_us = dt_us;
43 this->input_byte_count = inputByteCount;
44 info.sample_rate = 32000;
45 info.bits_per_sample = 16;
46 info.channels = 1;
47 }
48
49 virtual bool begin() {
50 TRACEI();
51
52 // Return the number of PCM samples in a frame
53 num_frames = lc3_frame_samples(dt_us, info.sample_rate);
54 dec_size = lc3_decoder_size(dt_us, info.sample_rate);
55
56 LOGI("channels: %d", info.channels);
57 LOGI("sample_rate: %d", info.sample_rate);
58 LOGI("input_byte_count: %d", input_byte_count);
59 LOGI("dt_us: %d", dt_us);
60 LOGI("num_frames: %d", num_frames);
61 LOGI("dec_size: %d", dec_size);
62
63 if (!checkValues()) {
64 LOGE("Invalid Parameters");
65 return false;
66 }
67
68 // setup memory
69 input_buffer.resize(input_byte_count);
70 output_buffer.resize(num_frames * 2);
71 lc3_decoder_memory.resize(dec_size);
72
73 // setup decoder
74 lc3_decoder = lc3_setup_decoder(dt_us, info.sample_rate, 0,
75 (void *)lc3_decoder_memory.data());
76 notifyAudioChange(info);
77
78 input_pos = 0;
79 active = true;
80 return true;
81 }
82
83 virtual void end() {
84 TRACEI();
85 active = false;
86 }
87
88 virtual void setOutput(Print &out_stream) { p_print = &out_stream; }
89
90 operator bool() { return active; }
91
92 virtual size_t write(const uint8_t *data, size_t len) {
93 if (!active) return 0;
94 LOGD("write %u", len);
95
96 uint8_t *p_ptr8 = (uint8_t *)data;
97
98 for (int j = 0; j < len; j++) {
99 input_buffer[input_pos++] = p_ptr8[j];
100 if (input_pos >= input_buffer.size()) {
101 if (lc3_decode(lc3_decoder, input_buffer.data(), input_buffer.size(),
102 pcm_format, (int16_t *)output_buffer.data(), 1) != 0) {
103 LOGE("lc3_decode");
104 }
105
106 // write all data to final output
107 int requested = output_buffer.size();
108 int written =
109 p_print->write((const uint8_t *)output_buffer.data(), requested);
110 if (written != requested) {
111 LOGE("Decoder Bytes requested: %d - written: %d", requested, written);
112 }
113 input_pos = 0;
114 }
115 }
116 return len;
117 }
118
119 protected:
120 Print *p_print = nullptr;
121 lc3_decoder_t lc3_decoder = nullptr;
122 lc3_pcm_format pcm_format;
123 Vector<uint8_t> lc3_decoder_memory;
124 Vector<uint16_t> output_buffer;
125 Vector<uint8_t> input_buffer;
126 size_t input_pos = 0;
127 int dt_us;
128 uint16_t input_byte_count = 20; // up to 400
129 uint16_t num_frames;
130 unsigned dec_size;
131 bool active = false;
132
133 bool checkValues() {
134 if (p_print == nullptr) {
135 LOGE("Output is not defined");
136 return false;
137 }
138
139 if (!LC3_CHECK_DT_US(dt_us)) {
140 LOGE("dt_us: %d", dt_us);
141 return false;
142 }
143
144 if (!LC3_CHECK_SR_HZ(info.sample_rate)) {
145 LOGE("sample_rate: %d", info.sample_rate);
146 return false;
147 }
148
149 if (info.channels!=1){
150 LOGE("channels: %d", info.channels);
151 }
152
153 if (num_frames == -1) {
154 LOGE("num_frames could not be determined - using m");
155 return false;
156 }
157
158 if (dec_size == 0) {
159 LOGE("dec_size");
160 return false;
161 }
162
163 switch (info.bits_per_sample) {
164 case 16:
165 pcm_format = LC3_PCM_FORMAT_S16;
166 break;
167 case 24:
168 pcm_format = LC3_PCM_FORMAT_S24;
169 break;
170 default:
171 LOGE("Bits per sample not supported: %d", info.bits_per_sample);
172 return false;
173 }
174 return true;
175 }
176};
177
186class LC3Encoder : public AudioEncoder {
187 public:
188 LC3Encoder(int dt_us = LC3_DEFAULT_DT_US,
189 uint16_t outputByteCount = DEFAULT_BYTE_COUNT) {
190 this->dt_us = dt_us;
191 info.sample_rate = 32000;
192 info.bits_per_sample = 16;
193 info.channels = 1;
194 output_byte_count = outputByteCount;
195 }
196
197 bool begin() {
198 TRACEI();
199
200 unsigned enc_size = lc3_encoder_size(dt_us, info.sample_rate);
201 num_frames = lc3_frame_samples(dt_us, info.sample_rate);
202
203 LOGI("sample_rate: %d", info.sample_rate);
204 LOGI("channels: %d", info.channels);
205 LOGI("dt_us: %d", dt_us);
206 LOGI("output_byte_count: %d", output_byte_count);
207 LOGI("enc_size: %d", enc_size);
208 LOGI("num_frames: %d", num_frames);
209
210 if (!checkValues()) {
211 return false;
212 }
213
214 // setup memory
215 lc3_encoder_memory.resize(enc_size);
216 input_buffer.resize(num_frames * 2);
217 output_buffer.resize(output_byte_count);
218
219 // setup encoder
220 lc3_encoder = lc3_setup_encoder(dt_us, info.sample_rate, 0,
221 lc3_encoder_memory.data());
222
223 input_pos = 0;
224 active = true;
225 return true;
226 }
227
228 virtual void end() {
229 TRACEI();
230 active = false;
231 }
232
233 virtual const char *mime() { return "audio/lc3"; }
234
235 virtual void setOutput(Print &out_stream) { p_print = &out_stream; }
236
237 operator bool() { return lc3_encoder != nullptr; }
238
239 virtual size_t write(const uint8_t *data, size_t len) {
240 if (!active) return 0;
241 LOGD("write %u", len);
242 uint8_t *p_ptr8 = (uint8_t *)data;
243
244 for (int j = 0; j < len; j++) {
245 input_buffer[input_pos++] = p_ptr8[j];
246 if (input_pos >= num_frames * 2) {
247 if (lc3_encode(lc3_encoder, pcm_format,
248 (const int16_t *)input_buffer.data(), 1,
249 output_buffer.size(), output_buffer.data()) != 0) {
250 LOGE("lc3_encode");
251 }
252
253 // write all data to final output
254 int requested = output_buffer.size();
255 int written = p_print->write(output_buffer.data(), requested);
256 if (written != requested) {
257 LOGE("Encoder Bytes requested: %d - written: %d", requested, written);
258 }
259 input_pos = 0;
260 }
261 }
262 return len;
263 }
264
265 protected:
266 Print *p_print = nullptr;
267 unsigned dt_us = 1000;
268 uint16_t num_frames;
269 lc3_encoder_t lc3_encoder = nullptr;
270 lc3_pcm_format pcm_format;
271 uint16_t output_byte_count = 20;
272 Vector<uint8_t> lc3_encoder_memory;
273 Vector<uint8_t> output_buffer;
274 Vector<uint8_t> input_buffer;
275 int input_pos = 0;
276 bool active = false;
277
278 bool checkValues() {
279 if (p_print == nullptr) {
280 LOGE("Output is not defined");
281 return false;
282 }
283
284 if (!LC3_CHECK_DT_US(dt_us)) {
285 LOGE("dt_us: %d", dt_us);
286 return false;
287 }
288
289 if (!LC3_CHECK_SR_HZ(info.sample_rate)) {
290 LOGE("sample_rate: %d", info.sample_rate);
291 return false;
292 }
293
294 if (info.channels!=1){
295 LOGE("channels: %d", info.channels);
296 }
297
298 if (num_frames == -1) {
299 LOGE("Invalid num_frames");
300 return false;
301 }
302
303 switch (info.bits_per_sample) {
304 case 16:
305 pcm_format = LC3_PCM_FORMAT_S16;
306 break;
307 case 24:
308 pcm_format = LC3_PCM_FORMAT_S24;
309 break;
310 default:
311 LOGE("Bits per sample not supported: %d", info.bits_per_sample);
312 return false;
313 }
314 return true;
315 }
316};
317
318} // namespace audio_tools
Docoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
Encoding of PCM data.
Definition AudioCodecsBase.h:90
Decoder for LC3. Depends on https://github.com/pschatzmann/arduino-liblc3.
Definition CodecLC3.h:31
virtual void setOutput(Print &out_stream)
Defines where the decoded result is written to.
Definition CodecLC3.h:88
Encoder for LC3 - Depends on https://github.com/pschatzmann/arduino-liblc3.
Definition CodecLC3.h:186
virtual const char * mime()
Provides the mime type of the encoded result.
Definition CodecLC3.h:233
Definition NoArduino.h:62
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioConfig.h:885
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:52
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59