arduino-audio-tools
Loading...
Searching...
No Matches
CodecADTS.h
Go to the documentation of this file.
1#pragma once
3
4namespace audio_tools {
5
6#ifndef SYNCWORDH
7#define SYNCWORDH 0xff
8#define SYNCWORDL 0xf0
9#endif
10
11#define ERROR_FMT_CHANGE "- Invalid ADTS change: %s"
12#define ERROR_FMT "- Invalid ADTS: %s (0x%x)"
13
19 public:
20 struct ADTSHeader {
21 uint16_t syncword = 0;
22 uint8_t id = 0;
23 uint8_t layer = 0;
24 uint8_t protection_absent = 0;
25 uint8_t profile = 0;
26 uint8_t sampling_freq_idx = 0;
27 uint8_t private_bit = 0;
28 uint8_t channel_cfg = 0;
29 uint8_t original_copy = 0;
30 uint8_t home = 0;
31 uint8_t copyright_id_bit = 0;
32 uint8_t copyright_id_start = 0;
33 uint16_t frame_length = 0;
34 uint8_t adts_buf_fullness = 0;
35 uint8_t num_rawdata_blocks = 0;
36 };
37
38 bool begin() {
39 is_first = true;
40 is_valid = true;
41 return true;
42 }
43
44 bool parse(uint8_t *hdr) {
45 header.syncword = (hdr[0] << 4) | (hdr[1] >> 4);
46 // parse fixed header
47 header.id = (hdr[1] >> 3) & 0b1;
48 header.layer = (hdr[1] >> 1) & 0b11;
49 header.protection_absent = (hdr[1]) & 0b1;
50 header.profile = (hdr[2] >> 6) & 0b11;
51 header.sampling_freq_idx = (hdr[2] >> 2) & 0b1111;
52 header.private_bit = (hdr[2] >> 1) & 0b1;
53 header.channel_cfg = ((hdr[2] & 0x01) << 2) | ((hdr[3] & 0xC0) >> 6);
54 header.original_copy = (hdr[3] >> 5) & 0b1;
55 header.home = (hdr[3] >> 4) & 0b1;
56 // parse variable header
57 header.copyright_id_bit = (hdr[3] >> 3) & 0b1;
58 header.copyright_id_start = (hdr[3] >> 2) & 0b1;
59 header.frame_length = ((((unsigned int)hdr[3] & 0x3)) << 11) |
60 (((unsigned int)hdr[4]) << 3) | (hdr[5] >> 5);
61 header.adts_buf_fullness = ((hdr[5] & 0b11111) << 6) | (hdr[6] >> 2);
62 header.num_rawdata_blocks = (hdr[6]) & 0b11;
63
64 LOGD("id:%d layer:%d profile:%d freq:%d channel:%d frame_length:%d",
67
68 // check
69 is_valid = check();
70 return is_valid;
71 }
72
73 uint32_t getFrameLength() { return header.frame_length; };
74
75 void log() {
76 LOGI("%s id:%d layer:%d profile:%d freq:%d channel:%d frame_length:%d",
79 }
80
86
87 bool isSyncWord(const uint8_t *buf) {
88 return ((buf[0] & SYNCWORDH) == SYNCWORDH &&
89 (buf[1] & SYNCWORDL) == SYNCWORDL);
90 }
91
92 int findSyncWord(const uint8_t *buf, int nBytes, int start = 0) {
93 /* find byte-aligned syncword (12 bits = 0xFFF) */
94 for (int i = start; i < nBytes - 1; i++) {
95 if (isSyncWord(buf + i)) return i;
96 }
97 return -1;
98 }
99
100 ADTSHeader &data() { return header; }
101
102 protected:
103 const int adtsSamplingRates[13] = {96000, 88200, 64000, 48000, 44100,
104 32000, 24000, 22050, 16000, 12000,
105 11025, 8000, 7350};
106
109 bool is_first = true;
110 bool is_valid = false;
111
112 bool check() {
113 if (header.syncword != 0b111111111111) {
114 LOGW(ERROR_FMT, "sync", (int)header.syncword);
115 is_valid = false;
116 }
117 if (header.id > 6) {
118 LOGW(ERROR_FMT, "id", (int)header.id);
119 is_valid = false;
120 }
121 if (header.sampling_freq_idx > 0xb) {
122 LOGW(ERROR_FMT, "freq", (int)header.sampling_freq_idx);
123 is_valid = false;
124 }
125 // valid value 0-7
126 // if (header.channel_cfg == 0 || header.channel_cfg > 7) {
127 if (header.channel_cfg > 7) {
128 LOGW(ERROR_FMT, "channels", (int)header.channel_cfg);
129 is_valid = false;
130 }
131 // ADTS always sets the (historic MPEG) layer field to 0: a non-zero
132 // value here means we are actually looking at an MP3 frame header,
133 // whose overlapping sync pattern (0xFFE-0xFFF) is otherwise
134 // indistinguishable from ADTS at this point.
135 if (header.layer != 0) {
136 LOGW(ERROR_FMT, "layer", (int)header.layer);
137 is_valid = false;
138 }
139 if (header.frame_length > 8191) { // tymically <= 768
140 LOGW(ERROR_FMT, "frame_length", (int)header.frame_length);
141 is_valid = false;
142 }
143 // on subsequent checks we need to compare with the first header
144 if (!is_first) {
145 is_valid = checkRef();
146 }
147 if (is_valid) {
148 is_first = false;
150 }
151 return is_valid;
152 }
153
154 bool checkRef() {
155 char msg[200] = "";
156 bool is_valid = true;
157 if (header.id != header_ref.id) {
158 strcat(msg, "id ");
159 is_valid = false;
160 }
161 if (header.layer != header_ref.layer) {
162 strcat(msg, "layer ");
163 is_valid = false;
164 }
166 strcat(msg, "profile ");
167 is_valid = false;
168 }
170 strcat(msg, "freq ");
171 is_valid = false;
172 }
174 strcat(msg, "channel ");
175 is_valid = false;
176 }
178 strcat(msg, "fullness");
179 is_valid = false;
180 }
181 if (!is_valid) {
183 }
184 return is_valid;
185 }
186};
187
199class ADTSDecoder : public AudioDecoder {
200 public:
201 ADTSDecoder() = default;
202 ADTSDecoder(AudioDecoder &dec) { p_dec = &dec; };
203
204 const char *mime() override { return "audio/aac"; }
205
206 bool begin() override {
207 parser.begin();
208 if (p_dec) p_dec->begin();
209 return true;
210 }
211
212 void end() override {
213 parseBuffer();
216 buffer.resize(0);
217 if (p_dec) p_dec->end();
218 }
219
221 size_t write(const uint8_t *data, size_t len) override {
222 LOGI("AACDecoderADTS::write: %d", (int)len);
223
224 parseBuffer();
225
226 // write data to buffer
227 size_t result = buffer.writeArray(data, len);
228 // assert(result == len);
229 LOGD("buffer size: %d", buffer.available());
230
231 return result;
232 }
233
235 operator bool() override { return true; }
236
239 void setOutputBufferSize(int size) { out_buffer.resize(size); }
240
242 void setParseBufferSize(int size) { buffer.resize(size); }
243
245 void setOutput(AudioStream &out_stream) override {
246 if (p_dec) {
247 p_dec->setOutput(out_stream);
248 } else {
249 AudioDecoder::setOutput(out_stream);
250 }
251 }
252
254 void setOutput(AudioOutput &out_stream) override {
255 if (p_dec) {
256 p_dec->setOutput(out_stream);
257 } else {
258 AudioDecoder::setOutput(out_stream);
259 }
260 }
261
263 void setOutput(Print &out_stream) override {
264 if (p_dec) {
265 p_dec->setOutput(out_stream);
266 } else {
267 AudioDecoder::setOutput(out_stream);
268 }
269 }
270
271 protected:
275 AudioDecoder *p_dec = nullptr;
276
277 void parseBuffer() {
278 TRACED();
279
280 // Need at least 7 bytes for a valid ADTS header
281 while (true) {
282 if (buffer.available() <= 5) return;
283 // Needs to contain sync word
284 int syncPos = parser.findSyncWord(buffer.data(), buffer.available());
285 if (syncPos < 0) {
286 return;
287 }
288 // buffer needs to start with sync word
289 if (syncPos > 0) {
290 buffer.clearArray(syncPos);
291 LOGI("Cleared %d bytes", syncPos);
292 }
293 // assert(parser.findSyncWord(buffer.data(), buffer.available()) == 0);
294 // Try to parse the header
295 if (parser.parse(buffer.data())) {
296 // Get the frame length which includes the header
297 uint16_t frameLength = parser.getFrameLength();
298 if (frameLength > buffer.available()) {
299 // not enough data
300 return;
301 }
302 // write data to decoder
303 if (out_buffer.size() > 0) {
304 writeDataBuffered(buffer.data(), frameLength);
305 } else {
306 writeData(buffer.data(), frameLength);
307 }
308 buffer.clearArray(frameLength);
309 } else {
310 LOGI("Invalid ADTS header");
311 // ignore data and move to next synch word
312 int pos = parser.findSyncWord(buffer.data(), buffer.available(), 5);
313 if (pos < 0) {
314 // no more sync word found
315 buffer.reset();
316 } else {
317 buffer.clearArray(pos);
318 }
319 }
320 }
321 }
322
323 size_t writeDataBuffered(uint8_t *data, size_t size) {
324 LOGI("writeDataBuffered: %d", (int)size);
325 for (int j = 0; j < size; j++) {
326 out_buffer.write(data[j]);
327 if (out_buffer.isFull()) {
330 }
331 }
332 return size;
333 }
334
335 size_t writeData(uint8_t *data, size_t size) {
336 LOGI("writeData: %d", (int)size);
337 if (p_print) {
338 size_t len = audio_tools::writeData<uint8_t>(p_print, data, size);
339 assert(len == size);
340 return (len == size);
341 }
342 if (p_dec) {
343 LOGI("write to decoder: %d", (int)size);
344 size_t len = audio_tools::writeDataT<uint8_t, AudioDecoder>(p_dec, data, size);
345 assert(len == size);
346 return (len == size);
347 }
348 return 0;
349 }
350};
351
352} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define ERROR_FMT_CHANGE
Definition CodecADTS.h:11
#define SYNCWORDL
Definition CodecADTS.h:8
#define SYNCWORDH
Definition CodecADTS.h:7
#define ERROR_FMT
Definition CodecADTS.h:12
#define DEFAULT_BUFFER_SIZE
Definition avr.h:20
#define assert(T)
Definition avr.h:10
Definition Arduino.h:56
Audio Data Transport Stream (ADTS) is a format similar to Audio Data Interchange Format (ADIF),...
Definition CodecADTS.h:199
void setOutput(Print &out_stream) override
Defines where the decoded result is written to.
Definition CodecADTS.h:263
void setParseBufferSize(int size)
Defines the parse buffer size: default is 1024.
Definition CodecADTS.h:242
ADTSParser parser
Definition CodecADTS.h:274
ADTSDecoder(AudioDecoder &dec)
Definition CodecADTS.h:202
void end() override
Definition CodecADTS.h:212
size_t write(const uint8_t *data, size_t len) override
Write AAC data to decoder.
Definition CodecADTS.h:221
void parseBuffer()
Definition CodecADTS.h:277
size_t writeDataBuffered(uint8_t *data, size_t size)
Definition CodecADTS.h:323
SingleBuffer< uint8_t > out_buffer
Definition CodecADTS.h:273
size_t writeData(uint8_t *data, size_t size)
Definition CodecADTS.h:335
SingleBuffer< uint8_t > buffer
Definition CodecADTS.h:272
const char * mime() override
Provides the mime type of the data that is expected by this decoder.
Definition CodecADTS.h:204
void setOutputBufferSize(int size)
Definition CodecADTS.h:239
void setOutput(AudioStream &out_stream) override
Defines where the decoded result is written to.
Definition CodecADTS.h:245
bool begin() override
Definition CodecADTS.h:206
void setOutput(AudioOutput &out_stream) override
Defines where the decoded result is written to.
Definition CodecADTS.h:254
AudioDecoder * p_dec
Definition CodecADTS.h:275
Structure to hold ADTS header field values.
Definition CodecADTS.h:18
ADTSHeader & data()
Definition CodecADTS.h:100
int findSyncWord(const uint8_t *buf, int nBytes, int start=0)
Definition CodecADTS.h:92
bool checkRef()
Definition CodecADTS.h:154
bool is_first
Definition CodecADTS.h:109
ADTSHeader header_ref
Definition CodecADTS.h:108
bool begin()
Definition CodecADTS.h:38
int getSampleRate()
Definition CodecADTS.h:81
bool is_valid
Definition CodecADTS.h:110
bool isSyncWord(const uint8_t *buf)
Definition CodecADTS.h:87
void log()
Definition CodecADTS.h:75
const int adtsSamplingRates[13]
Definition CodecADTS.h:103
ADTSHeader header
Definition CodecADTS.h:107
bool parse(uint8_t *hdr)
Definition CodecADTS.h:44
uint32_t getFrameLength()
Definition CodecADTS.h:73
bool check()
Definition CodecADTS.h:112
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:19
virtual bool begin(AudioInfo info) override
Definition AudioCodecsBase.h:58
void end() override
Definition AudioCodecsBase.h:63
virtual void setOutput(AudioStream &out_stream)
Defines where the decoded result is written to.
Definition AudioCodecsBase.h:40
Print * p_print
Definition AudioCodecsBase.h:79
Abstract Audio Ouptut class.
Definition AudioOutput.h:25
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:120
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:189
size_t size() override
Definition Buffers.h:320
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:223
int available() override
provides the number of entries that are available to read
Definition Buffers.h:250
bool isFull() override
checks if the buffer is full
Definition Buffers.h:257
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:218
T * data()
Provides address of actual data.
Definition Buffers.h:301
bool resize(size_t size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:322
void reset() override
clears the buffer
Definition Buffers.h:303
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:269
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
Definition CodecADTS.h:20
uint16_t syncword
Definition CodecADTS.h:21
uint8_t id
Definition CodecADTS.h:22
uint8_t protection_absent
Definition CodecADTS.h:24
uint8_t adts_buf_fullness
Definition CodecADTS.h:34
uint8_t num_rawdata_blocks
Definition CodecADTS.h:35
uint8_t channel_cfg
Definition CodecADTS.h:28
uint8_t copyright_id_start
Definition CodecADTS.h:32
uint8_t sampling_freq_idx
Definition CodecADTS.h:26
uint8_t profile
Definition CodecADTS.h:25
uint8_t home
Definition CodecADTS.h:30
uint8_t copyright_id_bit
Definition CodecADTS.h:31
uint8_t layer
Definition CodecADTS.h:23
uint16_t frame_length
Definition CodecADTS.h:33
uint8_t original_copy
Definition CodecADTS.h:29
uint8_t private_bit
Definition CodecADTS.h:27