arduino-audio-tools
CodecADTS.h
1 #include "AACDecoderHelix.h"
2 #include "AudioCodecs/AudioEncoded.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 void *dataIn, 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  uint8_t *data = (uint8_t *)dataIn;
146  size_t result = buffer.writeArray(data, len);
147  LOGD("buffer size: %d", buffer.available());
148 
149  // process open bytes
150  if (buffer_write_size == 0) {
151  parseBuffer();
152  } else {
153  // process open frame
154  if (buffer.available() >= buffer_write_size) {
155  // write out data
156  assert(buffer_write_size == parser.size());
157  writeFrame();
158  buffer_write_size = 0;
159  }
160  }
161  return result;
162  }
163 
165  operator bool() override { return true; }
166 
167  protected:
168  SingleBuffer<uint8_t> buffer{DEFAULT_BUFFER_SIZE};
169  ADTSParser parser;
170  int buffer_write_size = 0;
171 
172  void parseBuffer() {
173  // when nothing is open
174  while (buffer.available() >= 7 && buffer_write_size == 0) {
175  int pos = parser.findSynchWord(buffer.data(), buffer.available());
176  LOGD("synchword at %d from %d", pos, buffer.available());
177  if (pos >= 0) {
178  processSync(pos);
179  } else {
180  // if no sync word was found
181  int to_delete = max(7, buffer.available());
182  buffer.clearArray(to_delete);
183  LOGW("Removed invalid %d bytes", to_delete);
184  }
185  }
186  }
187 
188  void processSync(int pos) {
189  // remove data up to the sync word
190  buffer.clearArray(pos);
191  LOGD("Removing %d", pos);
192  assert(parser.isSyncWord(buffer.data()));
193  // the header needs 7 bytes
194  if (buffer.available() < 7) {
195  return;
196  }
197 
198  if (parser.parse(buffer.data())) {
199  processValidFrame();
200  } else {
201  // header not valid -> remove current synch word
202  buffer.clearArray(2);
203  LOGD("Removing invalid synch to restart scanning: %d", buffer.available());
204  }
205  }
206 
207  void processValidFrame() {
208  resizeBuffer();
209  if (buffer.available() >= parser.size()) {
210  writeFrame();
211  } else {
212  LOGD("Expecting more data up to %d", parser.size());
213  // we must load more data
214  buffer_write_size = parser.size();
215  }
216  }
217 
218  void writeFrame() {
219  // write out data
220  parser.log();
221  int size = parser.size();
222  if (size>0){
223  LOGD("writing ADTS Frame: %d bytes", size);
224  assert(buffer.available() >= size);
225  size_t len = p_print->write(buffer.data(), size);
226  assert(len == size);
227  buffer.clearArray(parser.size());
228  } else {
229  buffer.clearArray(2);
230  }
231  }
232 
233  void resizeBuffer() {
234  if (parser.size() > buffer.size()) {
235  LOGI("resize buffer %d to %d", (int)buffer.size(), (int)parser.size());
236  buffer.resize(parser.size());
237  buffer_write_size = parser.size();
238  }
239  }
240 };
241 
242 } // 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 void *dataIn, size_t len) override
Write AAC data to decoder.
Definition: CodecADTS.h:136
Docoding of encoded audio into PCM data.
Definition: AudioEncoded.h:18
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:246
int available() override
provides the number of entries that are available to read
Definition: Buffers.h:213
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition: Buffers.h:223
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
Definition: CodecADTS.h:11