3 #include "AudioCodecs/AudioEncoded.h"
4 #include "AudioCodecs/CodecOpus.h"
5 #include "AudioTools/Buffers.h"
8 #define OGG_READ_SIZE (1024)
9 #define OGG_DEFAULT_BUFFER_SIZE (OGG_READ_SIZE)
34 out.setDecoder(p_codec);
41 void setDecoder(AudioDecoder *decoder) {
43 out.setDecoder(p_codec);
62 bool begin()
override {
66 if (p_oggz ==
nullptr) {
67 p_oggz = oggz_new(OGGZ_READ | OGGZ_AUTO);
70 if (oggz_io_set_read(p_oggz, ogg_io_read,
this) != 0) {
71 LOGE(
"oggz_io_set_read");
75 if (oggz_set_read_callback(p_oggz, -1, read_packet,
this) != 0) {
76 LOGE(
"oggz_set_read_callback");
80 if (oggz_set_read_page(p_oggz, -1, read_page,
this) != 0) {
81 LOGE(
"oggz_set_read_page");
99 while ((oggz_read(p_oggz, OGG_READ_SIZE)) > 0)
103 virtual size_t write(
const void *in_ptr,
size_t in_size)
override {
104 LOGD(
"write: %d", (
int)in_size);
107 size_t size_consumed = buffer.
writeArray((uint8_t *)in_ptr, in_size);
113 if (size_consumed < in_size) {
114 size_consumed += buffer.
writeArray((uint8_t *)in_ptr + size_consumed,
115 in_size - size_consumed);
118 return size_consumed;
121 virtual operator bool()
override {
return is_open; }
124 EncodedAudioOutput out;
125 CopyDecoder dec_copy;
126 AudioDecoder *p_codec =
nullptr;
127 RingBuffer<uint8_t> buffer{OGG_DEFAULT_BUFFER_SIZE};
128 OGGZ *p_oggz =
nullptr;
129 bool is_open =
false;
133 static size_t ogg_io_read(
void *user_handle,
void *buf,
size_t n) {
134 LOGD(
"ogg_io_read: %d", (
int)n);
137 if (self->buffer.available() >= n) {
139 result =
self->buffer.readArray((uint8_t *)buf, n);
149 static int read_packet(OGGZ *oggz, oggz_packet *zp,
long serialno,
151 LOGD(
"read_packet: %d", (
int)zp->op.bytes);
153 ogg_packet *op = &zp->op;
154 int result = op->bytes;
156 self->beginOfSegment(op);
157 }
else if (op->e_o_s) {
158 self->endOfSegment(op);
160 if (memcmp(op->packet,
"OpusTags", 8) == 0) {
161 self->beginOfSegment(op);
163 LOGD(
"process audio packet");
164 int eff =
self->out.write(op->packet, op->bytes);
166 LOGE(
"Incomplere write");
174 static int read_page(OGGZ *oggz,
const ogg_page *og,
long serialno,
176 LOGD(
"read_page: %d", (
int)og->body_len);
181 virtual void beginOfSegment(ogg_packet *op) {
183 if (op->bytes ==
sizeof(AudioInfo)) {
184 AudioInfo cfg(*(AudioInfo*)op->packet);
186 if (cfg.bits_per_sample == 16 || cfg.bits_per_sample == 24 ||
187 cfg.bits_per_sample == 32) {
190 LOGE(
"Invalid AudioInfo")
193 LOGE(
"Invalid Header")
197 virtual void endOfSegment(ogg_packet *op) {
223 if (p_oggz ==
nullptr) {
224 p_oggz = oggz_new(OGGZ_WRITE | OGGZ_NONSTRICT | OGGZ_AUTO);
225 serialno = oggz_serialno_new(p_oggz);
226 oggz_io_set_write(p_oggz, ogg_io_write,
this);
230 if (!writeHeader()) {
250 virtual size_t write(
const uint8_t *in_ptr,
size_t in_size)
override {
251 if (in_ptr ==
nullptr)
return 0;
252 LOGD(
"OggContainerOutput::write: %d", (
int)in_size);
256 uint8_t *data = (uint8_t *)in_ptr;
257 op.packet = (uint8_t *)data;
261 granulepos += op.bytes / bytes_per_sample;
262 op.granulepos = granulepos;
265 op.packetno = packetno++;
267 if (!writePacket(op, OGGZ_FLUSH_AFTER)) {
272 while ((oggz_write(p_oggz, in_size)) > 0)
277 bool isOpen() {
return is_open; }
280 Print *p_out =
nullptr;
281 bool is_open =
false;
282 OGGZ *p_oggz =
nullptr;
285 size_t granulepos = 0;
288 bool is_audio =
false;
290 virtual bool writePacket(ogg_packet &op,
int flag = 0) {
291 LOGD(
"writePacket: %d", (
int)op.bytes);
292 long result = oggz_write_feed(p_oggz, &op, serialno, flag, NULL);
293 if (result < 0 && result != OGGZ_ERR_OUT_OF_MEMORY) {
294 LOGE(
"oggz_write_feed: %d", (
int)result);
300 virtual bool writeHeader() {
302 oh.packet = (uint8_t *)&cfg;
303 oh.bytes =
sizeof(AudioInfo);
305 oh.packetno = packetno++;
309 return writePacket(oh);
312 virtual bool writeFooter() {
314 op.packet = (uint8_t *)
nullptr;
316 op.granulepos = granulepos;
317 op.packetno = packetno++;
321 return writePacket(op, OGGZ_FLUSH_AFTER);
325 static size_t ogg_io_write(
void *user_handle,
void *buf,
size_t n) {
326 LOGD(
"ogg_io_write: %d", (
int)n);
327 OggContainerOutput *
self = (OggContainerOutput *)user_handle;
328 if (
self ==
nullptr) {
329 LOGE(
"self is null");
333 writeSamples<uint8_t>(self->p_out, (uint8_t *)buf, n);
370 if (p_codec !=
nullptr) p_codec->setAudioInfo(info);
382 if (p_codec==
nullptr)
return false;
383 p_codec->setOutput(*p_ogg);
384 return p_codec->begin(p_ogg->
audioInfo());
390 if (p_codec !=
nullptr) p_codec->end();
395 virtual size_t write(
const void *in_ptr,
size_t in_size)
override {
396 if (!p_ogg->isOpen() || in_ptr ==
nullptr)
return 0;
397 LOGD(
"OggContainerEncoder::write: %d", (
int)in_size);
399 if (p_codec ==
nullptr) {
400 result = p_ogg->
write((
const uint8_t *)in_ptr, in_size);
402 result = p_codec->write(in_ptr, in_size);
407 operator bool()
override {
return p_ogg->isOpen(); }
409 bool isOpen() {
return p_ogg->isOpen(); }
412 AudioEncoder *p_codec =
nullptr;
413 OggContainerOutput ogg;
414 OggContainerOutput *p_ogg = &ogg;
416 void setEncoder(AudioEncoder *enc) { p_codec = enc; }