arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
CodecBase64.h
1
2#pragma once
3
4#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
5
6namespace audio_tools {
7
8
9enum Base46Logic { NoCR, CRforFrame, CRforWrite };
10static char encoding_table[] = {
11 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
12 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
13 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
14 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
15 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
16static int mod_table[] = {0, 2, 1};
17
18static const int B64index[256] = {
19 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55, 56, 57,
22 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6,
23 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
24 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
25 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
26
38 public:
43 DecoderBase64() { TRACED(); }
44
51 TRACED();
52 setOutput(out);
53 }
54
56 void setOutput(Print &out) override { p_print = &out; }
57
59 void setNewLine(Base46Logic logic) { newline_logic = logic; }
60
61 bool begin() override {
62 TRACED();
63 is_valid = newline_logic == NoCR;
64 active = true;
65 return true;
66 }
67
68 void end() override {
69 TRACED();
70 // deconde ramaining bytes
71 int len = buffer.available();
72 uint8_t tmp[len];
73 buffer.readArray(tmp, len);
74 decodeLine(tmp, len);
75
76 active = false;
77 buffer.resize(0);
78 }
79
80 size_t write(const uint8_t *data, size_t len) override {
81 if (p_print == nullptr) return 0;
82 TRACED();
83 addToBuffer((uint8_t *)data, len);
84 int decode_size = 4; // maybe we should increase this ?
85 while (buffer.available() >= decode_size) {
86 uint8_t tmp[decode_size];
87 buffer.readArray(tmp, decode_size);
88 decodeLine(tmp, decode_size);
89 }
90
91 return len;
92 }
93
94 operator bool() override { return active; }
95
96 protected:
97 bool active = false;
98 bool is_valid = false;
99 Base46Logic newline_logic = CRforFrame;
100 Vector<uint8_t> result;
101 RingBuffer<uint8_t> buffer{1500};
102 AudioInfo info;
103
104 void decodeLine(uint8_t *data, size_t byteCount) {
105 LOGD("decode: %d", (int)byteCount);
106 int len = byteCount;
107
108 unsigned char *p = (unsigned char *)data;
109 int pad = len > 0 && (len % 4 || p[len - 1] == '=');
110 const size_t L = ((len + 3) / 4 - pad) * 4;
111 result.resize(L / 4 * 3 + pad);
112 memset(result.data(), 0, result.size());
113
114 for (size_t i = 0, j = 0; i < L; i += 4) {
115 int32_t n = static_cast<int32_t>(B64index[p[i]]) << 18 | B64index[p[i + 1]] << 12 |
116 B64index[p[i + 2]] << 6 | B64index[p[i + 3]];
117 result[j++] = n >> 16;
118 result[j++] = n >> 8 & 0xFF;
119 result[j++] = n & 0xFF;
120 }
121 if (pad) {
122 int32_t n = static_cast<int32_t>(B64index[p[L]]) << 18 | B64index[p[L + 1]] << 12;
123 result[result.size() - 1] = n >> 16;
124
125 if (len > L + 2 && p[L + 2] != '=') {
126 n |= B64index[p[L + 2]] << 6;
127 result.push_back(n >> 8 & 0xFF);
128 }
129 }
130 writeBlocking(p_print, result.data(), result.size());
131 }
132
133 void addToBuffer(uint8_t *data, size_t len) {
134 TRACED();
135 if (buffer.size() < len) {
136 buffer.resize(len);
137 }
138 // syncronize to find a valid start position
139 int start = 0;
140 if (!is_valid) {
141 for (int j = 0; j < len; j++) {
142 if (data[j] == '\n') {
143 start = j;
144 is_valid = true;
145 break;
146 }
147 }
148 }
149
150 if (is_valid) {
151 // remove white space
152 for (int j = start; j < len; j++) {
153 if (!isspace(data[j])) {
154 buffer.write(data[j]);
155 } else if (data[j] == '\n') {
156 int offset = buffer.available() % 4;
157 if (offset > 0) {
158 LOGW("Resync %d (-%d)...", buffer.available(), offset);
159 uint8_t tmp[4];
160 buffer.readArray(tmp, offset);
161 }
162 }
163 }
164 }
165 LOGD("buffer: %d, is_valid: %s", buffer.available(),
166 is_valid ? "true" : "false");
167 }
168};
169
170
182 public:
183 // Empty Conbuffeructor - the output buffeream must be provided with begin()
184 EncoderBase64() {}
185
186 // Conbuffeructor providing the output buffeream
187 EncoderBase64(Print &out) { p_print = &out; }
188
190 void setOutput(Print &out_buffeream) override {
191 p_print = &out_buffeream;
192 }
193
195 const char *mime() override { return "text/base64"; }
196
198 void setNewLine(Base46Logic flag) { newline_logic = flag; }
199
201 virtual bool begin() override {
202 is_open = true;
203 frame_size = info.bits_per_sample * info.channels / 8;
204 if (newline_logic != NoCR) {
205 if (frame_size==0){
206 LOGW("AudioInfo not defined");
207 // assume frame size
208 frame_size = 4;
209 }
210 p_print->write('\n');
211 flush();
212 }
213 return true;
214 }
215
217 void end() override { is_open = false; }
218
220 virtual size_t write(const uint8_t *data, size_t len) override {
221 LOGD("EncoderBase64::write: %d", (int)len);
222
223 switch (newline_logic) {
224 case NoCR:
225 case CRforWrite:
226 encodeLine(data, len);
227 break;
228 case CRforFrame: {
229 int frames = len / frame_size;
230 int open = len;
231 int offset = 0;
232 while (open > 0) {
233 int write_size = min(frame_size, open);
234 encodeLine(data + offset, write_size);
235 open -= write_size;
236 offset += write_size;
237 }
238 break;
239 }
240 }
241
242 return len;
243 }
244
245 operator bool() override { return is_open; }
246
247 bool isOpen() { return is_open; }
248
249 protected:
250 Print *p_print = nullptr;
251 bool is_open;
252 Base46Logic newline_logic = CRforFrame;
253 Vector<uint8_t> ret;
254 AudioInfo info;
255 int frame_size;
256
257 void flush() {
258#if defined(ESP32)
259# if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(3, 3, 5)
260 p_print->flush();
261# endif
262#else
263 p_print->flush();
264#endif
265 }
266
267 void encodeLine(const uint8_t *data, size_t input_length) {
268 LOGD("EncoderBase64::encodeLine: %d", (int)input_length);
269 int output_length = 4 * ((input_length + 2) / 3);
270 if (ret.size() < output_length + 1) {
271 ret.resize(output_length + 1);
272 }
273
274 for (int i = 0, j = 0; i < input_length;) {
275 uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
276 uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
277 uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
278
279 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
280
281 ret[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
282 ret[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
283 ret[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
284 ret[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
285 }
286
287 for (int i = 0; i < mod_table[input_length % 3]; i++)
288 ret[output_length - 1 - i] = '=';
289
290 // add a new line to the end
291 if (newline_logic != NoCR) {
292 ret[output_length] = '\n';
293 output_length++;
294 }
295
296 writeBlocking(p_print, ret.data(), output_length);
297 flush();
298 }
299};
300
301} // namespace audio_tools
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
Encoding of PCM data.
Definition AudioCodecsBase.h:90
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:37
DecoderBase64 - Converts a Base64 encoded Stream into the original data stream. Decoding only gives a...
Definition CodecBase64.h:37
void setOutput(Print &out) override
Defines the output Stream.
Definition CodecBase64.h:56
DecoderBase64()
Constructor for a new DecoderBase64 object.
Definition CodecBase64.h:43
DecoderBase64(Print &out)
Constructor for a new DecoderBase64 object.
Definition CodecBase64.h:50
void setNewLine(Base46Logic logic)
We expect new lines to delimit the individual lines.
Definition CodecBase64.h:59
EncoderBase64s - Encodes the input data into a Base64 string. By default each audio frame is followed...
Definition CodecBase64.h:181
virtual size_t write(const uint8_t *data, size_t len) override
Writes PCM data to be encoded as RAW.
Definition CodecBase64.h:220
void setOutput(Print &out_buffeream) override
Defines the output Stream.
Definition CodecBase64.h:190
virtual bool begin() override
starts the processing using the actual RAWAudioInfo
Definition CodecBase64.h:201
void end() override
stops the processing
Definition CodecBase64.h:217
const char * mime() override
Provides "text/base64".
Definition CodecBase64.h:195
void setNewLine(Base46Logic flag)
We add a new line after each write.
Definition CodecBase64.h:198
Definition NoArduino.h:62
virtual bool write(T data) override
write add an entry to the buffer
Definition Buffers.h:358
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:394
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:377
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10