19 #include "AudioTools/AudioCodecs/AudioCodecsBase.h"
20 #include "AudioTools/CoreAudio/AudioBasic/StrView.h"
24 enum class ContainerType : uint8_t {
37 char header[2] = {
'\r',
'\n'};
68 static uint8_t
checkSum(
const uint8_t *data,
size_t len) {
70 for (
int j = 0; j < len; j++) {
94 void setEncoder(
AudioEncoder *encoder) { p_codec = encoder; }
96 void setOutput(
Print &outStream) {
97 LOGD(
"BinaryContainerEncoder::setOutput");
101 bool begin()
override {
104 bool rc = p_codec->begin();
121 LOGD(
"BinaryContainerEncoder::writeMeta: %d", (
int)len);
123 uint8_t tmp_array[meta.common.len];
124 memcpy(tmp_array, &meta,
sizeof(meta));
125 memcpy(tmp_array +
sizeof(meta), data, len);
126 output(tmp_array, meta.common.len);
131 size_t write(
const uint8_t *data,
size_t len) {
132 LOGD(
"BinaryContainerEncoder::write: %d", (
int)len);
135 is_beginning =
false;
137 writeAudio((uint8_t *)data, len);
141 void end() { p_codec->end(); }
143 operator bool() {
return true; };
145 virtual const char *
mime() {
return "audio/binary"; };
148 uint64_t packet_count = 0;
149 bool is_beginning =
true;
155 Print *p_out =
nullptr;
157 void writeAudio(
const uint8_t *data,
size_t len) {
158 LOGD(
"writeAudio: %d", (
int)len);
161 QueueStream<uint8_t> tmp{tmp_buffer};
163 p_codec->setOutput(tmp);
164 p_codec->write(data, len);
167 dh.common.len = tmp.available() +
sizeof(CommonHeader);
168 dh.common.checksum =
checkSum(tmp_buffer.data(), tmp_buffer.available());
169 output((uint8_t *)&dh,
sizeof(dh));
172 output(tmp_buffer.data(), tmp_buffer.available());
177 output((uint8_t *)&cfg,
sizeof(cfg));
180 size_t output(
const uint8_t *data,
size_t len) {
181 if (p_out !=
nullptr) {
182 int written = p_out->write((uint8_t *)data, len);
183 LOGD(
"output: %d -> %d", (
int)len, written);
185 LOGW(
"output not defined");
211 LOGD(
"BinaryContainerDecoder::setOutput")
215 void setMetaCallback(
void (*callback)(uint8_t*,
int,
void*)) {
216 meta_callback = callback;
225 void end() { TRACED(); }
227 size_t write(
const uint8_t *data,
size_t len) {
228 LOGD(
"write: %d", (
int)len);
229 uint8_t *data8 = (uint8_t *)data;
230 if (buffer.size() < len) {
232 std::max(
static_cast<int>(DEFAULT_BUFFER_SIZE + header_size),
233 static_cast<int>(len * 4 + header_size)));
236 size_t result = buffer.
writeArray(data8, len);
237 while (parseBuffer())
239 return ignore_write_errors ? len : result;
242 operator bool() {
return true; };
245 this->error_handler = error_handler;
250 ignore_write_errors = flag;
259 bool is_first =
true;
261 const size_t header_size =
sizeof(header);
264 Print *p_out =
nullptr;
265 void (*meta_callback)(uint8_t* data,
int len,
void* ref) =
nullptr;
267 bool ignore_write_errors =
true;
268 void * reference =
nullptr;
275 StrView str{(
const char *)buffer.
data()};
276 int start = str.indexOf(
"\r\n");
277 LOGD(
"start: %d", start);
282 if (buffer.
available() - start >
sizeof(header)) {
284 memmove((uint8_t *)&header, buffer.
data() + start,
sizeof(header));
287 if (!isValidHeader()) {
288 LOGW(
"invalid header: %d", header.type);
289 if (error_handler) error_handler(InvalidHeader,
this, reference);
294 if (buffer.
available() - start >= header.len) {
298 result = processData();
300 LOGD(
"not enough data - available %d / req: %d", buffer.
available(),
302 if (error_handler) error_handler(DataMissing,
this, reference);
306 LOGD(
"not enough data for header: %d", buffer.
available());
307 if (error_handler) error_handler(DataMissing,
this, reference);
316 switch (header.type) {
317 case ContainerType::Header: {
319 SimpleContainerConfig config;
320 buffer.
readArray((uint8_t *)&config,
sizeof(config));
322 notifyAudioChange(info);
329 case ContainerType::Audio: {
332 int data_len = header.len - header_size;
334 if (header.checksum == crc) {
336 SingleBuffer<uint8_t> tmp_buffer{data_len * 5};
337 QueueStream<uint8_t> tmp{tmp_buffer};
340 p_codec->write(buffer.
data(), data_len);
343 output(tmp_buffer.data(), tmp_buffer.available());
346 LOGW(
"invalid checksum");
347 if (error_handler) error_handler(InvalidChecksum,
this, reference);
355 case ContainerType::Meta: {
358 int data_len = header.len - header_size;
359 if (meta_callback !=
nullptr) {
360 meta_callback(buffer.
data(), data_len, reference);
369 bool isValidHeader() {
370 switch (header.type) {
371 case ContainerType::Header:
372 return header.checksum == 0;
373 case ContainerType::Audio:
375 case ContainerType::Meta:
376 return header.checksum == 0;
389 size_t output(uint8_t *data,
size_t len) {
390 LOGD(
"output: %d", (
int)len);
391 if (p_out !=
nullptr)
392 p_out->write((uint8_t *)data, len);
394 LOGW(
"output not defined");