arduino-audio-tools
Loading...
Searching...
No Matches
CodecAPTX.h
Go to the documentation of this file.
1
11#pragma once
12#include "AudioToolsConfig.h"
14#include "openaptx.h"
15
16namespace audio_tools {
17
26class APTXDecoder : public AudioDecoder {
27 public:
28 APTXDecoder(bool isHd = false) {
29 is_hd = isHd;
30 info.sample_rate = 44100;
31 info.channels = 2;
32 info.bits_per_sample = isHd ? 24 : 16;
33 }
34
35 virtual const char *mime() override { return "audio/aptx"; }
36
37 bool begin() override {
38 TRACEI();
39 ctx = aptx_init(is_hd);
40 is_first_write = true;
42 return ctx != nullptr;
43 }
44
45 void end() override {
46 TRACEI();
47 bool dropped = aptx_decode_sync_finish(ctx);
48 aptx_finish(ctx);
49 ctx = nullptr;
50 }
51
52 virtual void setOutput(Print &out_stream) { p_print = &out_stream; }
53
54 operator bool() { return ctx != nullptr; }
55
56 virtual size_t write(const uint8_t *data, size_t len) {
57 LOGI("write: %d", len);
58 bool is_ok = true;
59 size_t dropped;
60 int synced;
61
62 if (is_first_write) {
63 is_first_write = false;
64 if (!checkPrefix(data, len)) {
65 return 0;
66 }
67 }
68
69 output_buffer.resize(len * 10);
70 memset(output_buffer.data(), 0, output_buffer.size());
71 processed = aptx_decode_sync(ctx, (const uint8_t *)data, len,
73 &written, &synced, &dropped);
74
75 checkSync(synced, dropped, is_ok);
76
77 // If we have not decoded all supplied samples then decoding unrecoverable
78 // failed
79 if (processed != len) {
80 LOGE("aptX decoding reqested: %d eff: %d", len, processed);
81 is_ok = false;
82 }
83
84 writeData(written, is_ok);
85
86 return is_ok ? len : 0;
87 }
88
89 protected:
90 struct aptx_context *ctx = nullptr;
91 Print *p_print = nullptr;
92 bool is_first_write = true;
94 bool is_hd;
95 size_t processed;
96 size_t written;
97 bool syncing;
98
100 void writeData(size_t written, bool &is_ok) {
101 if (written > 0) {
102 int samples = written / 3;
103 LOGI("written: %d", written);
104 LOGI("samples: %d", samples);
105 int24_t *p_int24 = (int24_t *)output_buffer.data();
106 int16_t *p_int16 = (int16_t *)output_buffer.data();
107 for (int j = 0; j < samples; j++) {
108 p_int16[j] = p_int24[j].getAndScale16();
109 }
110
111 if (p_print->write((uint8_t *)output_buffer.data(), samples * 2) !=
112 samples * 2) {
113 LOGE("aptX decoding failed to write decoded data");
114 is_ok = false;
115 }
116 }
117 }
118
120 void checkSync(bool synced, bool dropped, bool &is_ok) {
121 /* Check all possible states of synced, syncing and dropped status */
122 if (!synced) {
123 if (!syncing) {
124 LOGE("aptX decoding failed, synchronizing");
125 syncing = true;
126 is_ok = false;
127 }
128 if (dropped) {
129 LOGE("aptX synchronization successful, dropped %lu byte%s",
130 (unsigned long)dropped, (dropped != 1) ? "s" : "");
131 syncing = false;
132 is_ok = true;
133 }
134 if (!syncing) {
135 LOGE("aptX decoding failed, synchronizing");
136 syncing = true;
137 is_ok = false;
138 }
139 } else {
140 if (dropped) {
141 if (!syncing) LOGE("aptX decoding failed, synchronizing");
142 LOGE("aptX synchronization successful, dropped %lu byte%s",
143 (unsigned long)dropped, (dropped != 1) ? "s" : "");
144 syncing = false;
145 is_ok = false;
146 } else if (syncing) {
147 LOGI("aptX synchronization successful");
148 syncing = false;
149 is_ok = true;
150 }
151 }
152 }
153
155 bool checkPrefix(const void *input_buffer, size_t length) {
156 bool result = true;
157 if (length >= 4 && memcmp(input_buffer, "\x4b\xbf\x4b\xbf", 4) == 0) {
158 if (is_hd) {
159 LOGE("aptX audio stream (not aptX HD)");
160 result = false;
161 }
162 } else if (length >= 6 &&
163 memcmp(input_buffer, "\x73\xbe\xff\x73\xbe\xff", 6) == 0) {
164 if (!is_hd) {
165 LOGE("aptX HD audio stream");
166 result = false;
167 }
168 } else {
169 if (length >= 4 && memcmp(input_buffer, "\x6b\xbf\x6b\xbf", 4) == 0) {
170 LOGE("standard aptX audio stream - not supported");
171 result = false;
172 } else {
173 LOGE("No aptX nor aptX HD audio stream");
174 result = false;
175 }
176 }
177 return result;
178 }
179};
180
189class APTXEncoder : public AudioEncoder {
190 public:
191 APTXEncoder(bool isHd = false) {
192 is_hd = isHd;
193 info.sample_rate = 44100;
194 info.channels = 2;
195 info.bits_per_sample = isHd ? 24 : 16;
196 }
197
198 bool begin() {
199 TRACEI();
200 input_buffer.resize(4 * 2);
201 output_buffer.resize(100 * (is_hd ? 6 : 4));
202
203 LOGI("input_buffer.size: %d", input_buffer.size());
204 LOGI("output_buffer.size: %d", output_buffer.size());
205 LOGI("is_hd: %s", is_hd ? "true" : "false");
206 ctx = aptx_init(is_hd);
207 return ctx!=nullptr;
208 }
209
210 virtual void end() {
211 TRACEI();
212 if (ctx != nullptr) {
213 size_t output_written = 0;
214 aptx_encode_finish(ctx, output_buffer.data(), output_buffer.size(),
215 &output_written);
216 if (output_written > 0) {
217 // write result to final output
218 int written = p_print->write((const uint8_t *)output_buffer.data(),
219 output_written);
220 if (written != output_written) {
221 LOGE("write requested: %d eff: %d", output_written, written);
222 }
223 }
224 aptx_finish(ctx);
225 ctx = nullptr;
226 }
227 }
228
229 virtual const char *mime() { return "audio/aptx"; }
230
233 switch (info.bits_per_sample) {
234 case 16:
235 is_hd = false;
236 break;
237 case 24:
238 is_hd = true;
239 break;
240 default:
241 LOGE("invalid bits_per_sample: %d", info.bits_per_sample);
242 }
243 }
244
245 virtual void setOutput(Print &out_stream) { p_print = &out_stream; }
246
247 operator bool() { return ctx != nullptr; }
248
249 virtual size_t write(const uint8_t *data, size_t len) {
250 LOGI("write: %d", len);
251 if (ctx == nullptr) return 0;
252 size_t output_written = 0;
253
254 // process all bytes
255 int16_t *in_ptr16 = (int16_t *)data;
256 int in_samples = len / 2;
257 for (int j = 0; j < in_samples; j++) {
258 input_buffer[input_pos++].setAndScale16(in_ptr16[j]);
259
260 // if input_buffer is full we encode
261 if (input_pos >= input_buffer.size()) {
262 size_t result = aptx_encode(
263 ctx, (const uint8_t *)input_buffer.data(), input_buffer.size() * 3,
265 output_buffer.size() - output_pos, &output_written);
266
267 output_pos += output_written;
268
269 if (result != input_buffer.size() * 3) {
270 LOGW("encode requested: %d, eff: %d", input_buffer.size() * 3,
271 result);
272 }
273
274 // if output buffer is full we write the result
276 int written =
277 p_print->write((const uint8_t *)output_buffer.data(), output_pos);
278 if (written != output_pos) {
279 LOGE("write requested: %d eff: %d", output_pos, written);
280 }
281 // restart at beginning of output buffer
282 output_pos = 0;
283 }
284 // restart at beginning of input buffer
285 input_pos = 0;
286 }
287 }
288
289 return len;
290 }
291
292 protected:
293 bool is_hd;
296 int input_pos = 0;
297 int output_pos = 0;
298 Print *p_print = nullptr;
299 struct aptx_context *ctx = nullptr;
300};
301
302} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACEI()
Definition AudioLoggerIDF.h:32
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGE(...)
Definition AudioLoggerIDF.h:30
Definition Arduino.h:56
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
Decoder for OpenAptx. Depends on https://github.com/pschatzmann/libopenaptx.
Definition CodecAPTX.h:26
virtual void setOutput(Print &out_stream)
Defines where the decoded result is written to.
Definition CodecAPTX.h:52
Vector< uint8_t > output_buffer
Definition CodecAPTX.h:93
size_t processed
Definition CodecAPTX.h:95
void end() override
Definition CodecAPTX.h:45
bool syncing
Definition CodecAPTX.h:97
virtual const char * mime() override
Provides the mime type of the data that is expected by this decoder.
Definition CodecAPTX.h:35
virtual size_t write(const uint8_t *data, size_t len)
Definition CodecAPTX.h:56
void checkSync(bool synced, bool dropped, bool &is_ok)
Checks the syncronization.
Definition CodecAPTX.h:120
bool checkPrefix(const void *input_buffer, size_t length)
Checks the prefix of the received data.
Definition CodecAPTX.h:155
bool is_hd
Definition CodecAPTX.h:94
bool is_first_write
Definition CodecAPTX.h:92
size_t written
Definition CodecAPTX.h:96
bool begin() override
Definition CodecAPTX.h:37
Print * p_print
Definition CodecAPTX.h:91
APTXDecoder(bool isHd=false)
Definition CodecAPTX.h:28
struct aptx_context * ctx
Definition CodecAPTX.h:90
void writeData(size_t written, bool &is_ok)
Converts the data to 16 bit and writes it to final output.
Definition CodecAPTX.h:100
Encoder for OpenAptx - Depends on https://github.com/pschatzmann/libopenaptx.
Definition CodecAPTX.h:189
int input_pos
Definition CodecAPTX.h:296
virtual void setOutput(Print &out_stream)
Default output assignment (encoders may override to store Print reference)
Definition CodecAPTX.h:245
Vector< uint8_t > output_buffer
Definition CodecAPTX.h:295
bool begin()
Definition CodecAPTX.h:198
Vector< int24_t > input_buffer
Definition CodecAPTX.h:294
APTXEncoder(bool isHd=false)
Definition CodecAPTX.h:191
virtual const char * mime()
Provides the mime type of the encoded result.
Definition CodecAPTX.h:229
virtual void setAudioInfo(AudioInfo info)
Defines the input AudioInfo.
Definition CodecAPTX.h:231
virtual size_t write(const uint8_t *data, size_t len)
Definition CodecAPTX.h:249
bool is_hd
Definition CodecAPTX.h:293
int output_pos
Definition CodecAPTX.h:297
Print * p_print
Definition CodecAPTX.h:298
virtual void end()
Definition CodecAPTX.h:210
struct aptx_context * ctx
Definition CodecAPTX.h:299
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:19
AudioInfo info
Definition AudioCodecsBase.h:80
Encoding of PCM data.
Definition AudioCodecsBase.h:101
AudioInfo info
Definition AudioCodecsBase.h:120
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition AudioCodecsBase.h:110
void notifyAudioChange(AudioInfo info)
Definition AudioTypes.h:175
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(size_t newSize, T value)
Definition Vector.h:266
T * data()
Definition Vector.h:316
int size()
Definition Vector.h:178
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition int24_4bytes_t.h:22
int16_t getAndScale16()
Definition int24_4bytes_t.h:133
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:51
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:57