arduino-audio-tools
CodecADTS.h
1 #include "AACDecoderHelix.h"
2 #include "AudioTools/AudioCodecs/AudioCodecsBase.h"
3 
4 namespace audio_tools {
5 
6 #ifndef SYNCWORDH
7 #define SYNCWORDH 0xff
8 #define SYNCWORDL 0xf0
9 #endif
10 
11 struct ADTSParser {
12  const int adtsSamplingRates[13] = {96000, 88200, 64000, 48000, 44100,
13  32000, 24000, 22050, 16000, 12000,
14  11025, 8000, 7350};
15 
16  bool is_valid = false;
17  uint16_t syncword;
18  uint8_t id;
19  uint8_t layer;
20  uint8_t protection_absent;
21  uint8_t profile;
22  uint8_t sampling_freq_idx;
23  uint8_t private_bit;
24  uint8_t channel_cfg;
25  uint8_t original_copy;
26  uint8_t home;
27  uint8_t copyright_id_bit;
28  uint8_t copyright_id_start;
29  uint16_t frame_length;
30  uint8_t adts_buf_fullness;
31  uint8_t num_rawdata_blocks;
32  uint32_t quick_check = 0;
33 
34  bool begin() { quick_check = 0; return true;}
35 
36  bool parse(uint8_t *hdr) {
37  syncword = (hdr[0] << 4) | (hdr[1] >> 4);
38  // parse fixed header
39  id = (hdr[1] >> 3) & 0b1;
40  layer = (hdr[1] >> 1) & 0b11;
41  protection_absent = (hdr[1]) & 0b1;
42  profile = (hdr[2] >> 6) & 0b11;
43  sampling_freq_idx = (hdr[2] >> 2) & 0b1111;
44  private_bit = (hdr[2] >> 1) & 0b1;
45  channel_cfg = ((hdr[2] & 0x01) << 2) | ((hdr[3] & 0xC0) >> 6);
46  original_copy = (hdr[3] >> 5) & 0b1;
47  home = (hdr[3] >> 4) & 0b1;
48  // parse variable header
49  copyright_id_bit = (hdr[3] >> 3) & 0b1;
50  copyright_id_start = (hdr[3] >> 2) & 0b1;
51  // frame_length = ((hdr[3] & 0b11) << 11) | (hdr[4] << 3) | (hdr[5] >> 5);
52  frame_length = ((((unsigned int)hdr[3] & 0x3)) << 11) |
53  (((unsigned int)hdr[4]) << 3) | (hdr[5] >> 5);
54  adts_buf_fullness = ((hdr[5] & 0b11111) << 6) | (hdr[6] >> 2);
55  num_rawdata_blocks = (hdr[6]) & 0b11;
56 
57  LOGD("id:%d layer:%d profile:%d freq:%d channel:%d frame_length:%d", id,
58  layer, profile, rate(), channel_cfg,
59  frame_length);
60 
61  // check
62  is_valid = true;
63  if (syncword != 0b111111111111) {
64  is_valid = false;
65  }
66  if (id > 6) {
67  LOGD("- Invalid id");
68  is_valid = false;
69  }
70  if (sampling_freq_idx > 0xb) {
71  LOGD("- Invalid sampl.freq");
72  is_valid = false;
73  }
74  if (channel_cfg > 2) {
75  LOGD("- Invalid channels");
76  is_valid = false;
77  }
78  if (frame_length > 1024) {
79  LOGD("- Invalid frame_length");
80  is_valid = false;
81  }
82  if (!is_valid) {
83  LOGD("=> Invalid ADTS");
84  }
85  return is_valid;
86  }
87 
88  unsigned int size() { return frame_length; };
89 
90  void log() {
91  LOGI("%s id:%d layer:%d profile:%d freq:%d channel:%d frame_length:%d",
92  is_valid ? "+" : "-", id, layer, profile,
93  rate(), channel_cfg, frame_length);
94  }
95 
96  int rate(){
97  return sampling_freq_idx>12? sampling_freq_idx : adtsSamplingRates[sampling_freq_idx];
98  }
99 
100  bool isSyncWord(uint8_t *buf) {
101  return ((buf[0] & SYNCWORDH) == SYNCWORDH &&
102  (buf[1] & SYNCWORDL) == SYNCWORDL);
103  }
104 
105  int findSynchWord(unsigned char *buf, int nBytes, int start = 0) {
106  /* find byte-aligned syncword (12 bits = 0xFFF) */
107  for (int i = start; i < nBytes - 1; i++) {
108  if (isSyncWord(buf + i)) return i;
109  }
110  return -1;
111  }
112 };
113 
125 class ADTSDecoder : public AudioDecoder {
126  public:
127  bool begin() override {
128  parser.begin();
129  buffer_write_size = 0;
130  return true;
131  }
132 
133  void end() override { buffer.resize(0); }
134 
136  size_t write(const uint8_t *data, size_t len) override {
137  LOGD("AACDecoderADTS::write: %d", (int)len);
138 
139  // make sure that we can hold at least the len
140  if (buffer.size() < len) {
141  buffer.resize(len);
142  }
143 
144  // write data to buffer
145  size_t result = buffer.writeArray(data, len);
146  LOGD("buffer size: %d", buffer.available());
147 
148  // process open bytes
149  if (buffer_write_size == 0) {
150  parseBuffer();
151  } else {
152  // process open frame
153  if (buffer.available() >= buffer_write_size) {
154  // write out data
155  assert(buffer_write_size == parser.size());
156  writeFrame();
157  buffer_write_size = 0;
158  }
159  }
160  return result;
161  }
162 
164  operator bool() override { return true; }
165 
166  protected:
167  SingleBuffer<uint8_t> buffer{DEFAULT_BUFFER_SIZE};
168  ADTSParser parser;
169  int buffer_write_size = 0;
170 
171  void parseBuffer() {
172  // when nothing is open
173  while (buffer.available() >= 7 && buffer_write_size == 0) {
174  int pos = parser.findSynchWord(buffer.data(), buffer.available());
175  LOGD("synchword at %d from %d", pos, buffer.available());
176  if (pos >= 0) {
177  processSync(pos);
178  } else {
179  // if no sync word was found
180  int to_delete = max(7, buffer.available());
181  buffer.clearArray(to_delete);
182  LOGW("Removed invalid %d bytes", to_delete);
183  }
184  }
185  }
186 
187  void processSync(int pos) {
188  // remove data up to the sync word
189  buffer.clearArray(pos);
190  LOGD("Removing %d", pos);
191  assert(parser.isSyncWord(buffer.data()));
192  // the header needs 7 bytes
193  if (buffer.available() < 7) {
194  return;
195  }
196 
197  if (parser.parse(buffer.data())) {
198  processValidFrame();
199  } else {
200  // header not valid -> remove current synch word
201  buffer.clearArray(2);
202  LOGD("Removing invalid synch to restart scanning: %d", buffer.available());
203  }
204  }
205 
206  void processValidFrame() {
207  resizeBuffer();
208  if (buffer.available() >= parser.size()) {
209  writeFrame();
210  } else {
211  LOGD("Expecting more data up to %d", parser.size());
212  // we must load more data
213  buffer_write_size = parser.size();
214  }
215  }
216 
217  void writeFrame() {
218  // write out data
219  parser.log();
220  int size = parser.size();
221  if (size>0){
222  LOGD("writing ADTS Frame: %d bytes", size);
223  assert(buffer.available() >= size);
224  size_t len = p_print->write(buffer.data(), size);
225  assert(len == size);
226  buffer.clearArray(parser.size());
227  } else {
228  buffer.clearArray(2);
229  }
230  }
231 
232  void resizeBuffer() {
233  if (parser.size() > buffer.size()) {
234  LOGI("resize buffer %d to %d", (int)buffer.size(), (int)parser.size());
235  buffer.resize(parser.size());
236  buffer_write_size = parser.size();
237  }
238  }
239 };
240 
241 } // namespace audio_tools
Audio Data Transport Stream (ADTS) is a format similar to Audio Data Interchange Format (ADIF),...
Definition: CodecADTS.h:125
size_t write(const uint8_t *data, size_t len) override
Write AAC data to decoder.
Definition: CodecADTS.h:136
Docoding of encoded audio into PCM data.
Definition: AudioCodecsBase.h:16
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition: Buffers.h:65
T * data()
Provides address of actual data.
Definition: Buffers.h:252
int available() override
provides the number of entries that are available to read
Definition: Buffers.h:219
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition: Buffers.h:229
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:823
Definition: CodecADTS.h:11