3 #include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4 #include "AudioTools/AudioCodecs/CodecOpus.h"
5 #include "AudioTools/CoreAudio/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 uint8_t *data,
size_t len)
override {
104 LOGD(
"write: %d", (
int)len);
107 size_t size_consumed = buffer.
writeArray((uint8_t *)data, len);
113 if (size_consumed < len) {
114 size_consumed += buffer.
writeArray((uint8_t *)data + size_consumed,
115 len - 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 *data,
size_t len)
override {
251 if (data ==
nullptr)
return 0;
252 LOGD(
"OggContainerOutput::write: %d", (
int)len);
256 op.packet = (uint8_t *)data;
260 granulepos += op.bytes / bytes_per_sample;
261 op.granulepos = granulepos;
264 op.packetno = packetno++;
266 if (!writePacket(op, OGGZ_FLUSH_AFTER)) {
271 while ((oggz_write(p_oggz, len)) > 0)
276 bool isOpen() {
return is_open; }
279 Print *p_out =
nullptr;
280 bool is_open =
false;
281 OGGZ *p_oggz =
nullptr;
284 size_t granulepos = 0;
287 bool is_audio =
false;
289 virtual bool writePacket(ogg_packet &op,
int flag = 0) {
290 LOGD(
"writePacket: %d", (
int)op.bytes);
291 long result = oggz_write_feed(p_oggz, &op, serialno, flag, NULL);
292 if (result < 0 && result != OGGZ_ERR_OUT_OF_MEMORY) {
293 LOGE(
"oggz_write_feed: %d", (
int)result);
299 virtual bool writeHeader() {
301 oh.packet = (uint8_t *)&cfg;
302 oh.bytes =
sizeof(AudioInfo);
304 oh.packetno = packetno++;
308 return writePacket(oh);
311 virtual bool writeFooter() {
313 op.packet = (uint8_t *)
nullptr;
315 op.granulepos = granulepos;
316 op.packetno = packetno++;
320 return writePacket(op, OGGZ_FLUSH_AFTER);
324 static size_t ogg_io_write(
void *user_handle,
void *buf,
size_t n) {
325 LOGD(
"ogg_io_write: %d", (
int)n);
326 OggContainerOutput *
self = (OggContainerOutput *)user_handle;
327 if (
self ==
nullptr) {
328 LOGE(
"self is null");
332 writeSamples<uint8_t>(self->p_out, (uint8_t *)buf, n);
369 if (p_codec !=
nullptr) p_codec->setAudioInfo(info);
381 if (p_codec==
nullptr)
return false;
382 p_codec->setOutput(*p_ogg);
383 return p_codec->begin(p_ogg->
audioInfo());
389 if (p_codec !=
nullptr) p_codec->end();
394 virtual size_t write(
const uint8_t *data,
size_t len)
override {
395 if (!p_ogg->isOpen() || data ==
nullptr)
return 0;
396 LOGD(
"OggContainerEncoder::write: %d", (
int)len);
398 if (p_codec ==
nullptr) {
399 result = p_ogg->
write((
const uint8_t *)data, len);
401 result = p_codec->write(data, len);
406 operator bool()
override {
return p_ogg->isOpen(); }
408 bool isOpen() {
return p_ogg->isOpen(); }
411 AudioEncoder *p_codec =
nullptr;
412 OggContainerOutput ogg;
413 OggContainerOutput *p_ogg = &ogg;
415 void setEncoder(AudioEncoder *enc) { p_codec = enc; }