arduino-audio-tools
CodecLC3.h
Go to the documentation of this file.
1 
11 #pragma once
12 
13 #include "AudioCodecs/AudioEncoded.h"
14 #include "lc3.h"
15 
16 namespace 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 
31 class 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 void *input, size_t length) {
93  if (!active) return 0;
94  LOGD("write %u", length);
95 
96  uint8_t *p_ptr8 = (uint8_t *)input;
97 
98  for (int j = 0; j < length; 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 length;
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 
186 class 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 void *in_ptr, size_t in_size) {
240  if (!active) return 0;
241  LOGD("write %u", in_size);
242  uint8_t *p_ptr8 = (uint8_t *)in_ptr;
243 
244  for (int j = 0; j < in_size; 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 in_size;
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: AudioEncoded.h:18
Encoding of PCM data.
Definition: AudioEncoded.h:88
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:58
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:50
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:57