arduino-audio-tools
Loading...
Searching...
No Matches
ContainerOgg.h
Go to the documentation of this file.
1#pragma once
2
6#include "oggz.h"
7
8#define OGG_READ_SIZE (1024)
9#define OGG_DEFAULT_BUFFER_SIZE (OGG_READ_SIZE)
10// #define OGG_DEFAULT_BUFFER_SIZE (246)
11// #define OGG_READ_SIZE (512)
12
13namespace audio_tools {
14
27 public:
36
38
40
41 void setDecoder(AudioDecoder *decoder) {
42 p_codec = decoder;
44 }
45
47 const char *mime() override { return p_codec != nullptr ? p_codec->mime() : nullptr; }
48
50 void setOutput(Print &print) override { out.setOutput(&print); }
51
56
57 AudioInfo audioInfo() override { return out.audioInfo(); }
58
59 bool begin(AudioInfo info) override {
60 TRACED();
61 this->info = info;
62 return begin();
63 }
64
65 bool begin() override {
66 TRACED();
68 out.begin();
69 if (p_oggz == nullptr) {
70 p_oggz = oggz_new(OGGZ_READ | OGGZ_AUTO); // OGGZ_NONSTRICT
71 is_open = true;
72 // Callback to Replace standard IO
73 if (oggz_io_set_read(p_oggz, ogg_io_read, this) != 0) {
74 LOGE("oggz_io_set_read");
75 is_open = false;
76 }
77 // Callback
78 if (oggz_set_read_callback(p_oggz, -1, read_packet, this) != 0) {
79 LOGE("oggz_set_read_callback");
80 is_open = false;
81 }
82
83 if (oggz_set_read_page(p_oggz, -1, read_page, this) != 0) {
84 LOGE("oggz_set_read_page");
85 is_open = false;
86 }
87 }
88 return is_open;
89 }
90
91 void end() override {
92 TRACED();
93 flush();
94 out.end();
95 is_open = false;
96 oggz_close(p_oggz);
97 p_oggz = nullptr;
98 }
99
100 void flush() {
101 LOGD("oggz_read...");
102 while ((oggz_read(p_oggz, OGG_READ_SIZE)) > 0)
103 ;
104 }
105
106 virtual size_t write(const uint8_t *data, size_t len) override {
107 LOGD("write: %d", (int)len);
108
109 // fill buffer
110 size_t size_consumed = buffer.writeArray((uint8_t *)data, len);
111 if (buffer.availableForWrite() == 0) {
112 // Read all bytes into oggz, calling any read callbacks on the fly.
113 flush();
114 }
115 // write remaining bytes
116 if (size_consumed < len) {
117 size_consumed += buffer.writeArray((uint8_t *)data + size_consumed,
118 len - size_consumed);
119 flush();
120 }
121 return size_consumed;
122 }
123
124 virtual operator bool() override { return is_open; }
125
126 protected:
131 OGGZ *p_oggz = nullptr;
132 bool is_open = false;
133 long pos = 0;
134
135 // Final Stream Callback -> provide data to ogg
136 static size_t ogg_io_read(void *user_handle, void *buf, size_t n) {
137 LOGD("ogg_io_read: %d", (int)n);
138 size_t result = 0;
139 OggContainerDecoder *self = (OggContainerDecoder *)user_handle;
140 if (self->buffer.available() >= n) {
141 OggContainerDecoder *self = (OggContainerDecoder *)user_handle;
142 result = self->buffer.readArray((uint8_t *)buf, n);
143 self->pos += result;
144
145 } else {
146 result = 0;
147 }
148 return result;
149 }
150
151 // Process full packet
152 static int read_packet(OGGZ *oggz, oggz_packet *zp, long serialno,
153 void *user_data) {
154 LOGD("read_packet: %d", (int)zp->op.bytes);
155 OggContainerDecoder *self = (OggContainerDecoder *)user_data;
156 ogg_packet *op = &zp->op;
157 int result = op->bytes;
158 if (op->b_o_s) {
159 self->beginOfSegment(op);
160 } else if (op->e_o_s) {
161 self->endOfSegment(op);
162 } else {
163 if (memcmp(op->packet, "OpusTags", 8) == 0) {
164 self->beginOfSegment(op);
165 } else {
166 LOGD("process audio packet");
167 int eff = self->out.write(op->packet, op->bytes);
168 if (eff != result) {
169 LOGE("Incomplere write");
170 }
171 }
172 }
173 // 0 = success
174 return 0;
175 }
176
177 static int read_page(OGGZ *oggz, const ogg_page *og, long serialno,
178 void *user_data) {
179 LOGD("read_page: %d", (int)og->body_len);
180 // 0 = success
181 return 0;
182 }
183
184 virtual void beginOfSegment(ogg_packet *op) {
185 LOGD("bos");
186 if (op->bytes == sizeof(AudioInfo)) {
187 AudioInfo cfg(*(AudioInfo*)op->packet);
188 cfg.logInfo();
189 if (cfg.bits_per_sample == 16 || cfg.bits_per_sample == 24 ||
190 cfg.bits_per_sample == 32) {
191 setAudioInfo(cfg);
192 } else {
193 LOGE("Invalid AudioInfo")
194 }
195 } else {
196 LOGE("Invalid Header")
197 }
198 }
199
200 virtual void endOfSegment(ogg_packet *op) {
201 // end segment not supported
202 LOGW("e_o_s");
203 }
204};
205
213 public:
214 // Empty Constructor - the output stream must be provided with begin()
216
218 void setOutput(Print &print) { p_out = &print; }
219
221 virtual bool begin() override {
222 TRACED();
223 assert(cfg.channels != 0);
224 assert(cfg.sample_rate != 0);
225 is_open = true;
226 if (p_oggz == nullptr) {
227 p_oggz = oggz_new(OGGZ_WRITE | OGGZ_NONSTRICT | OGGZ_AUTO);
228 serialno = oggz_serialno_new(p_oggz);
229 oggz_io_set_write(p_oggz, ogg_io_write, this);
230 packetno = 0;
231 granulepos = 0;
232
233 if (!writeHeader()) {
234 is_open = false;
235 LOGE("writeHeader");
236 }
237 }
238 return is_open;
239 }
240
242 void end() override {
243 TRACED();
244
245 writeFooter();
246
247 is_open = false;
248 oggz_close(p_oggz);
249 p_oggz = nullptr;
250 }
251
253 virtual size_t write(const uint8_t *data, size_t len) override {
254 if (data == nullptr) return 0;
255 LOGD("OggContainerOutput::write: %d", (int)len);
256 assert(cfg.channels != 0);
257
258 // encode the data
259 op.packet = (uint8_t *)data;
260 op.bytes = len;
261 if (op.bytes > 0) {
262 int bytes_per_sample = cfg.bits_per_sample / 8;
263 granulepos += op.bytes / bytes_per_sample; // sample
264 op.granulepos = granulepos;
265 op.b_o_s = false;
266 op.e_o_s = false;
267 op.packetno = packetno++;
268 is_audio = true;
269 if (!writePacket(op, OGGZ_FLUSH_AFTER)) {
270 return 0;
271 }
272 }
273 // trigger pysical write
274 while ((oggz_write(p_oggz, len)) > 0)
275 ;
276
277 return len;
278 }
279 bool isOpen() { return is_open; }
280
281 protected:
282 Print *p_out = nullptr;
283 bool is_open = false;
284 OGGZ *p_oggz = nullptr;
285 ogg_packet op;
286 ogg_packet oh;
287 size_t granulepos = 0;
288 size_t packetno = 0;
289 long serialno = -1;
290 bool is_audio = false;
291
292 virtual bool writePacket(ogg_packet &op, int flag = 0) {
293 LOGD("writePacket: %d", (int)op.bytes);
294 long result = oggz_write_feed(p_oggz, &op, serialno, flag, NULL);
295 if (result < 0 && result != OGGZ_ERR_OUT_OF_MEMORY) {
296 LOGE("oggz_write_feed: %d", (int)result);
297 return false;
298 }
299 return true;
300 }
301
302 virtual bool writeHeader() {
303 TRACED();
304 oh.packet = (uint8_t *)&cfg;
305 oh.bytes = sizeof(AudioInfo);
306 oh.granulepos = 0;
307 oh.packetno = packetno++;
308 oh.b_o_s = true;
309 oh.e_o_s = false;
310 is_audio = false;
311 return writePacket(oh);
312 }
313
314 virtual bool writeFooter() {
315 TRACED();
316 op.packet = (uint8_t *)nullptr;
317 op.bytes = 0;
318 op.granulepos = granulepos;
319 op.packetno = packetno++;
320 op.b_o_s = false;
321 op.e_o_s = true;
322 is_audio = false;
323 return writePacket(op, OGGZ_FLUSH_AFTER);
324 }
325
326 // Final Stream Callback
327 static size_t ogg_io_write(void *user_handle, void *buf, size_t n) {
328 LOGD("ogg_io_write: %d", (int)n);
329 OggContainerOutput *self = (OggContainerOutput *)user_handle;
330 if (self == nullptr) {
331 LOGE("self is null");
332 return 0;
333 }
334 // self->out.write((uint8_t *)buf, n);
335 writeData<uint8_t>(self->p_out, (uint8_t *)buf, n);
336 // 0 = continue
337 return 0;
338 }
339};
340
354 public:
355 // Empty Constructor - the output stream must be provided with begin()
357
359
361
363 void setOutput(Print &print) override { p_ogg->setOutput(print); }
364
366 const char *mime() override { return mime_pcm; }
367
369 virtual void setAudioInfo(AudioInfo info) override {
372 if (p_codec != nullptr) p_codec->setAudioInfo(info);
373 }
374
375 virtual bool begin(AudioInfo from) override {
376 setAudioInfo(from);
377 return begin();
378 }
379
381 virtual bool begin() override {
382 TRACED();
383 p_ogg->begin();
384 if (p_codec==nullptr) return false;
386 return p_codec->begin(p_ogg->audioInfo());
387 }
388
390 void end() override {
391 TRACED();
392 if (p_codec != nullptr) p_codec->end();
393 p_ogg->end();
394 }
395
397 virtual size_t write(const uint8_t *data, size_t len) override {
398 if (!p_ogg->isOpen() || data == nullptr) return 0;
399 LOGD("OggContainerEncoder::write: %d", (int)len);
400 size_t result = 0;
401 if (p_codec == nullptr) {
402 result = p_ogg->write((const uint8_t *)data, len);
403 } else {
404 result = p_codec->write(data, len);
405 }
406 return result;
407 }
408
409 operator bool() override { return p_ogg->isOpen(); }
410
411 bool isOpen() { return p_ogg->isOpen(); }
412
413 protected:
417
418 void setEncoder(AudioEncoder *enc) { p_codec = enc; }
419
422};
423
424} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define OGG_DEFAULT_BUFFER_SIZE
Definition ContainerOgg.h:9
#define OGG_READ_SIZE
Definition ContainerOgg.h:8
#define assert(T)
Definition avr.h:10
Definition Arduino.h:56
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:19
AudioInfo info
Definition AudioCodecsBase.h:80
void setAudioInfo(AudioInfo from) override
for most decoders this is not needed
Definition AudioCodecsBase.h:32
virtual const char * mime()=0
Provides the mime type of the data that is expected by this decoder.
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
virtual void setOutput(Print &out_stream) override
Default output assignment (encoders may override to store Print reference)
Definition AudioCodecsBase.h:113
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:150
Supports changes to the sampling rate, bits and channels.
Definition AudioTypes.h:132
Abstract Audio Ouptut class.
Definition AudioOutput.h:25
AudioInfo cfg
Definition AudioOutput.h:88
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition AudioOutput.h:49
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition AudioOutput.h:62
virtual size_t write(const uint8_t *data, size_t len)=0
virtual void end()=0
virtual bool begin()=0
Parent class for all container formats.
Definition AudioCodecsBase.h:90
Dummy Decoder which just copies the provided data to the output. You can define if it is PCM data.
Definition CodecCopy.h:18
A more natural Print class to process encoded data (aac, wav, mp3...). Just define the output and the...
Definition AudioEncoded.h:21
virtual size_t write(const uint8_t *data, size_t len) override
encoder decode the data
Definition AudioEncoded.h:199
void addNotifyAudioChange(AudioInfoSupport &bi) override
Define object which need to be notified if the basinfo is changing.
Definition AudioEncoded.h:74
void end() override
Ends the processing.
Definition AudioEncoded.h:189
bool begin() override
Starts the processing - sets the status to active.
Definition AudioEncoded.h:161
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition AudioEncoded.h:87
void setDecoder(AudioDecoder *decoder)
Definition AudioEncoded.h:144
AudioInfo audioInfo() override
Provide audio info from decoder if relevant.
Definition AudioEncoded.h:97
void setOutput(Print *outputStream)
Defines the output.
Definition AudioEncoded.h:107
Decoder for Ogg Container. Decodes a packet from an Ogg container. The Ogg begin segment contains the...
Definition ContainerOgg.h:26
virtual size_t write(const uint8_t *data, size_t len) override
Definition ContainerOgg.h:106
bool is_open
Definition ContainerOgg.h:132
static int read_packet(OGGZ *oggz, oggz_packet *zp, long serialno, void *user_data)
Definition ContainerOgg.h:152
OggContainerDecoder()
Construct a new OggContainerDecoder object.
Definition ContainerOgg.h:32
void setOutput(Print &print) override
Defines the output Stream.
Definition ContainerOgg.h:50
void addNotifyAudioChange(AudioInfoSupport &bi) override
Adds target to be notified about audio changes.
Definition ContainerOgg.h:52
OggContainerDecoder(AudioDecoder &decoder)
Definition ContainerOgg.h:39
long pos
Definition ContainerOgg.h:133
OGGZ * p_oggz
Definition ContainerOgg.h:131
virtual void beginOfSegment(ogg_packet *op)
Definition ContainerOgg.h:184
void end() override
Definition ContainerOgg.h:91
EncodedAudioOutput out
Definition ContainerOgg.h:127
CopyDecoder dec_copy
Definition ContainerOgg.h:128
virtual void endOfSegment(ogg_packet *op)
Definition ContainerOgg.h:200
AudioDecoder * p_codec
Definition ContainerOgg.h:129
static int read_page(OGGZ *oggz, const ogg_page *og, long serialno, void *user_data)
Definition ContainerOgg.h:177
OggContainerDecoder(AudioDecoder *decoder)
Definition ContainerOgg.h:37
const char * mime() override
Provides the mime type of the wrapped codec (default: CopyDecoder's)
Definition ContainerOgg.h:47
static size_t ogg_io_read(void *user_handle, void *buf, size_t n)
Definition ContainerOgg.h:136
bool begin(AudioInfo info) override
Definition ContainerOgg.h:59
bool begin() override
Definition ContainerOgg.h:65
void setDecoder(AudioDecoder *decoder)
Definition ContainerOgg.h:41
void flush()
Definition ContainerOgg.h:100
RingBuffer< uint8_t > buffer
Definition ContainerOgg.h:130
AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition ContainerOgg.h:57
Encoder for Ogg Container. Encodes a packet for an Ogg container. The Ogg begin segment contains the ...
Definition ContainerOgg.h:353
virtual size_t write(const uint8_t *data, size_t len) override
Writes raw data to be encoded and packaged.
Definition ContainerOgg.h:397
AudioEncoder * p_codec
Definition ContainerOgg.h:414
void setOutput(Print &print) override
Defines the output Stream.
Definition ContainerOgg.h:363
bool isOpen()
Definition ContainerOgg.h:411
virtual bool begin() override
starts the processing using the actual AudioInfo
Definition ContainerOgg.h:381
void setEncoder(AudioEncoder *enc)
Definition ContainerOgg.h:418
void end() override
stops the processing
Definition ContainerOgg.h:390
void setOggOutput(OggContainerOutput *out)
Replace the ogg output class.
Definition ContainerOgg.h:421
OggContainerEncoder(AudioEncoder &encoder)
Definition ContainerOgg.h:360
virtual void setAudioInfo(AudioInfo info) override
We actually do nothing with this.
Definition ContainerOgg.h:369
const char * mime() override
Provides "audio/pcm".
Definition ContainerOgg.h:366
OggContainerOutput ogg
Definition ContainerOgg.h:415
OggContainerEncoder(AudioEncoder *encoder)
Definition ContainerOgg.h:358
OggContainerOutput * p_ogg
Definition ContainerOgg.h:416
virtual bool begin(AudioInfo from) override
Definition ContainerOgg.h:375
Output class for the OggContainerEncoder. Each write is ending up as container entry.
Definition ContainerOgg.h:212
virtual size_t write(const uint8_t *data, size_t len) override
Writes raw data to be encoded and packaged.
Definition ContainerOgg.h:253
bool is_open
Definition ContainerOgg.h:283
size_t granulepos
Definition ContainerOgg.h:287
long serialno
Definition ContainerOgg.h:289
bool is_audio
Definition ContainerOgg.h:290
static size_t ogg_io_write(void *user_handle, void *buf, size_t n)
Definition ContainerOgg.h:327
ogg_packet op
Definition ContainerOgg.h:285
bool isOpen()
Definition ContainerOgg.h:279
OGGZ * p_oggz
Definition ContainerOgg.h:284
virtual bool begin() override
starts the processing using the actual AudioInfo
Definition ContainerOgg.h:221
virtual bool writeHeader()
Definition ContainerOgg.h:302
ogg_packet oh
Definition ContainerOgg.h:286
void end() override
stops the processing
Definition ContainerOgg.h:242
virtual bool writePacket(ogg_packet &op, int flag=0)
Definition ContainerOgg.h:292
Print * p_out
Definition ContainerOgg.h:282
size_t packetno
Definition ContainerOgg.h:288
virtual bool writeFooter()
Definition ContainerOgg.h:314
void setOutput(Print &print)
Defines the output Stream.
Definition ContainerOgg.h:218
Implements a typed Ringbuffer.
Definition Buffers.h:358
virtual int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:407
virtual int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:427
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:473
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:470
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
static const char * mime_pcm
Mime type for PCM.
Definition AudioTypes.h:514
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
virtual void logInfo(const char *source="")
Definition AudioTypes.h:122