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 if (header.frame_length > 8191) { // tymically <= 768
132 LOGW(ERROR_FMT, "frame_length", (int)header.frame_length);
133 is_valid = false;
134 }
135 // on subsequent checks we need to compare with the first header
136 if (!is_first) {
137 is_valid = checkRef();
138 }
139 if (is_valid) {
140 is_first = false;
142 }
143 return is_valid;
144 }
145
146 bool checkRef() {
147 char msg[200] = "";
148 bool is_valid = true;
149 if (header.id != header_ref.id) {
150 strcat(msg, "id ");
151 is_valid = false;
152 }
153 if (header.layer != header_ref.layer) {
154 strcat(msg, "layer ");
155 is_valid = false;
156 }
158 strcat(msg, "profile ");
159 is_valid = false;
160 }
162 strcat(msg, "freq ");
163 is_valid = false;
164 }
166 strcat(msg, "channel ");
167 is_valid = false;
168 }
170 strcat(msg, "fullness");
171 is_valid = false;
172 }
173 if (!is_valid) {
175 }
176 return is_valid;
177 }
178};
179
191class ADTSDecoder : public AudioDecoder {
192 public:
193 ADTSDecoder() = default;
194 ADTSDecoder(AudioDecoder &dec) { p_dec = &dec; };
195
196 bool begin() override {
197 parser.begin();
198 if (p_dec) p_dec->begin();
199 return true;
200 }
201
202 void end() override {
203 parseBuffer();
206 buffer.resize(0);
207 if (p_dec) p_dec->end();
208 }
209
211 size_t write(const uint8_t *data, size_t len) override {
212 LOGI("AACDecoderADTS::write: %d", (int)len);
213
214 parseBuffer();
215
216 // write data to buffer
217 size_t result = buffer.writeArray(data, len);
218 // assert(result == len);
219 LOGD("buffer size: %d", buffer.available());
220
221 return result;
222 }
223
225 operator bool() override { return true; }
226
229 void setOutputBufferSize(int size) { out_buffer.resize(size); }
230
232 void setParseBufferSize(int size) { buffer.resize(size); }
233
235 void setOutput(AudioStream &out_stream) override {
236 if (p_dec) {
237 p_dec->setOutput(out_stream);
238 } else {
239 AudioDecoder::setOutput(out_stream);
240 }
241 }
242
244 void setOutput(AudioOutput &out_stream) override {
245 if (p_dec) {
246 p_dec->setOutput(out_stream);
247 } else {
248 AudioDecoder::setOutput(out_stream);
249 }
250 }
251
253 void setOutput(Print &out_stream) override {
254 if (p_dec) {
255 p_dec->setOutput(out_stream);
256 } else {
257 AudioDecoder::setOutput(out_stream);
258 }
259 }
260
261 protected:
265 AudioDecoder *p_dec = nullptr;
266
267 void parseBuffer() {
268 TRACED();
269
270 // Need at least 7 bytes for a valid ADTS header
271 while (true) {
272 if (buffer.available() <= 5) return;
273 // Needs to contain sync word
274 int syncPos = parser.findSyncWord(buffer.data(), buffer.available());
275 if (syncPos < 0) {
276 return;
277 }
278 // buffer needs to start with sync word
279 if (syncPos > 0) {
280 buffer.clearArray(syncPos);
281 LOGI("Cleared %d bytes", syncPos);
282 }
283 // assert(parser.findSyncWord(buffer.data(), buffer.available()) == 0);
284 // Try to parse the header
285 if (parser.parse(buffer.data())) {
286 // Get the frame length which includes the header
287 uint16_t frameLength = parser.getFrameLength();
288 if (frameLength > buffer.available()) {
289 // not enough data
290 return;
291 }
292 // write data to decoder
293 if (out_buffer.size() > 0) {
294 writeDataBuffered(buffer.data(), frameLength);
295 } else {
296 writeData(buffer.data(), frameLength);
297 }
298 buffer.clearArray(frameLength);
299 } else {
300 LOGI("Invalid ADTS header");
301 // ignore data and move to next synch word
302 int pos = parser.findSyncWord(buffer.data(), buffer.available(), 5);
303 if (pos < 0) {
304 // no more sync word found
305 buffer.reset();
306 } else {
307 buffer.clearArray(pos);
308 }
309 }
310 }
311 }
312
313 size_t writeDataBuffered(uint8_t *data, size_t size) {
314 LOGI("writeDataBuffered: %d", (int)size);
315 for (int j = 0; j < size; j++) {
316 out_buffer.write(data[j]);
317 if (out_buffer.isFull()) {
320 }
321 }
322 return size;
323 }
324
325 size_t writeData(uint8_t *data, size_t size) {
326 LOGI("writeData: %d", (int)size);
327 if (p_print) {
328 size_t len = audio_tools::writeData<uint8_t>(p_print, data, size);
329 assert(len == size);
330 return (len == size);
331 }
332 if (p_dec) {
333 LOGI("write to decoder: %d", (int)size);
335 assert(len == size);
336 return (len == size);
337 }
338 return 0;
339 }
340};
341
342} // 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
Audio Data Transport Stream (ADTS) is a format similar to Audio Data Interchange Format (ADIF),...
Definition CodecADTS.h:191
void setOutput(Print &out_stream) override
Defines where the decoded result is written to.
Definition CodecADTS.h:253
void setParseBufferSize(int size)
Defines the parse buffer size: default is 1024.
Definition CodecADTS.h:232
ADTSParser parser
Definition CodecADTS.h:264
ADTSDecoder(AudioDecoder &dec)
Definition CodecADTS.h:194
void end() override
Definition CodecADTS.h:202
size_t write(const uint8_t *data, size_t len) override
Write AAC data to decoder.
Definition CodecADTS.h:211
void parseBuffer()
Definition CodecADTS.h:267
size_t writeDataBuffered(uint8_t *data, size_t size)
Definition CodecADTS.h:313
SingleBuffer< uint8_t > out_buffer
Definition CodecADTS.h:263
size_t writeData(uint8_t *data, size_t size)
Definition CodecADTS.h:325
SingleBuffer< uint8_t > buffer
Definition CodecADTS.h:262
void setOutputBufferSize(int size)
Definition CodecADTS.h:229
void setOutput(AudioStream &out_stream) override
Defines where the decoded result is written to.
Definition CodecADTS.h:235
bool begin() override
Definition CodecADTS.h:196
void setOutput(AudioOutput &out_stream) override
Defines where the decoded result is written to.
Definition CodecADTS.h:244
AudioDecoder * p_dec
Definition CodecADTS.h:265
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:146
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:18
virtual bool begin(AudioInfo info) override
Definition AudioCodecsBase.h:54
void end() override
Definition AudioCodecsBase.h:59
virtual void setOutput(AudioStream &out_stream)
Defines where the decoded result is written to.
Definition AudioCodecsBase.h:36
Print * p_print
Definition AudioCodecsBase.h:75
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:123
Definition NoArduino.h:62
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:172
size_t size() override
Definition Buffers.h:303
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:206
int available() override
provides the number of entries that are available to read
Definition Buffers.h:233
bool isFull() override
checks if the buffer is full
Definition Buffers.h:240
bool resize(int size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:305
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:201
T * data()
Provides address of actual data.
Definition Buffers.h:284
void reset() override
clears the buffer
Definition Buffers.h:286
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:252
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:512
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