arduino-audio-tools
Loading...
Searching...
No Matches
CodecVorbis.h
Go to the documentation of this file.
1#pragma once
3#include "AudioToolsConfig.h"
4#include "ogg.h"
5#include "vorbis-tremor.h"
6
7// #include "AudioTools/AudioCodecs/ContainerOgg.h"
8// #include "ivorbiscodec.h"
9// #include "ivorbisfile.h"
10
11// the ESP32 does not have any optimization flags set by default, so we can enable O3 for better performance
12#ifdef ARDUINO
13#pragma GCC optimize("O3")
14#endif
15
16namespace audio_tools {
17
18#ifndef VARBIS_MAX_READ_SIZE
19#define VARBIS_MAX_READ_SIZE 1024
20#endif
21
22#define VORBIS_HEADER_OPEN_LIMIT 1024
23
33 public:
34 VorbisDecoder() = default;
35
38 if (active) {
39 end();
40 }
41 }
42
44 bool begin() override {
45 LOGI("begin");
46
47 // Ensure we start with clean state
48 if (active) {
49 LOGW("Decoder already active, calling end() first");
50 end();
51 }
52
53 callbacks.read_func = read_func;
54 callbacks.seek_func = seek_func;
55 callbacks.close_func = nullptr;
56 callbacks.tell_func = tell_func;
57
58 assert(p_input != nullptr);
61 }
62 LOGI("available: %d", p_input->available());
63
65 LOGI("ovOpen result: %d", is_ov_open);
66
68 return is_ov_open;
69 }
70
72 void end() override {
73 LOGI("end");
74 if (is_ov_open && active) {
75 ov_clear(&file);
76 LOGI("ov_clear completed");
77 }
78 is_ov_open = false;
79 is_first = true;
80 active = false;
81 pcm.clear(); // Free the PCM buffer
82 }
83
85 AudioInfo audioInfo() override { return cfg; }
86
88 virtual operator bool() override { return active; }
89
90 virtual bool copy() override {
91 TRACED();
92
93 // open if not already done
94 if (!is_ov_open) {
95 if (!ovOpen()) {
96 LOGE("Failed to open Vorbis stream");
97 return false;
98 }
99 }
100
101 // Defensive checks before calling Vorbis functions
102 if (pcm.data() == nullptr) {
103 LOGE("PCM buffer is null - memory allocation failed");
104 return false;
105 }
106
107 if (pcm.size() == 0) {
108 LOGE("PCM buffer size is 0");
109 return false;
110 }
111
112 // Additional sanity check for the file structure
113 if (!active) {
114 LOGE("Decoder is not active");
115 return false;
116 }
117
118 LOGD("ov_read: buffer size %d", pcm.size());
119 bitstream = 0;
120
121 // Call ov_read with additional error checking
122 long result = ov_read(&file, (char *)pcm.data(), pcm.size(), &bitstream);
123 LOGI("copy result: %d", (int)result);
124
125 if (result > 0) {
126 AudioInfo current = currentInfo();
127 if (current != cfg) {
128 cfg = current;
129 cfg.logInfo();
131 }
132
133 if (p_print != nullptr) {
134 p_print->write(pcm.data(), result);
135 } else {
136 LOGE("Output stream is null");
137 return false;
138 }
139 delay(1);
140 return true;
141 } else {
142 if (result == 0 || result == -3) {
143 // data interruption
144 LOGD("copy: %d - %s", (int)result, readError(result));
145 } else {
146 LOGE("copy: %d - %s", (int)result, readError(result));
147 }
149 return false;
150 }
151 }
152
154 const char *mime() override { return "audio/vorbis+ogg"; }
155
158
160 void setWaitForData(size_t wait) { delay_wait_for_data_ms = wait; }
161
163 void setReadSize(size_t size) {
164 max_read_size = size;
165 // Ensure we don't set an unreasonably large size
166 if (max_read_size > 8192) {
167 LOGW("Read size %zu is very large, consider smaller buffer",
169 }
170 }
171
172 protected:
175 OggVorbis_File file;
176 ov_callbacks callbacks;
177 int bitstream = 0;
181 bool active = false;
182 bool is_first = true;
183 bool is_ov_open = false;
184
185 bool ovOpen() {
187 checkMemory(true);
188 int rc = ov_open_callbacks(this, &file, nullptr, 0, callbacks);
189 if (rc < 0) {
190 LOGE("ov_open_callbacks failed with error %d: %s", rc, getOpenError(rc));
191 } else {
192 LOGI("ov_open_callbacks succeeded");
193 is_ov_open = true;
194 }
195 checkMemory(true);
196 return is_ov_open;
197 }
198
200 AudioInfo result;
201 if (!is_ov_open) {
202 LOGE("Cannot get audio info - stream not open");
203 return result;
204 }
205
206 vorbis_info *info = ov_info(&file, -1);
207 if (info == nullptr) {
208 LOGE("ov_info returned null pointer");
209 return result;
210 }
211
212 result.sample_rate = info->rate;
213 result.channels = info->channels;
214 result.bits_per_sample = 16;
215
216 LOGD("Audio info - rate: %d, channels: %d", info->rate, info->channels);
217 return result;
218 }
219
220 virtual size_t readBytes(uint8_t *data, size_t len) override {
221 size_t read_size = min(len, (size_t)max_read_size);
222 size_t result = p_input->readBytes((uint8_t *)data, read_size);
223 LOGD("readBytes: %zu", result);
224 return result;
225 }
226
227 static size_t read_func(void *ptr, size_t size, size_t nmemb,
228 void *datasource) {
229 VorbisDecoder *self = (VorbisDecoder *)datasource;
230 assert(datasource != nullptr);
231 size_t result = self->readBytes((uint8_t *)ptr, size * nmemb);
232 LOGD("read_func: %d -> %d", size * nmemb, (int)result);
233 return result;
234 }
235
236 static int seek_func(void *datasource, ogg_int64_t offset, int whence) {
237 VorbisDecoder *self = (VorbisDecoder *)datasource;
238 return -1;
239 }
240
241 static long tell_func(void *datasource) {
242 VorbisDecoder *self = (VorbisDecoder *)datasource;
243 return -1;
244 }
245
246 // static int close_func(void *datasource) {
247 // VorbisDecoder *self = (VorbisDecoder *)datasource;
248 // self->end();
249 // return 0;
250 // }
251
252 const char *readError(long error) {
253 if (error >= 0) {
254 return "OK";
255 }
256 switch (error) {
257 case OV_HOLE:
258 return "Interruption in the data";
259 case OV_EBADLINK:
260 return "Invalid stream section";
261 case OV_EREAD:
262 return "Read error";
263 case OV_EFAULT:
264 return "Internal fault";
265 case OV_EIMPL:
266 return "Unimplemented feature";
267 case OV_EINVAL:
268 return "Invalid argument";
269 case OV_ENOTVORBIS:
270 return "Not a Vorbis file";
271 case OV_EBADHEADER:
272 return "Invalid Vorbis header";
273 case OV_EVERSION:
274 return "Vorbis version mismatch";
275 case OV_ENOSEEK:
276 return "Stream not seekable";
277 default:
278 return "Unknown error";
279 }
280 }
281
282 const char *getOpenError(int error) {
283 switch (error) {
284 case 0:
285 return "Success";
286 case OV_EREAD:
287 return "Read from media error";
288 case OV_ENOTVORBIS:
289 return "Not Vorbis data";
290 case OV_EVERSION:
291 return "Vorbis version mismatch";
292 case OV_EBADHEADER:
293 return "Invalid Vorbis bitstream header";
294 case OV_EFAULT:
295 return "Internal logic fault";
296 default:
297 return "Unknown open error";
298 }
299 }
300};
301
302} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define VARBIS_MAX_READ_SIZE
Definition CodecVorbis.h:19
#define VORBIS_HEADER_OPEN_LIMIT
Definition CodecVorbis.h:22
#define assert(T)
Definition avr.h:10
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
virtual size_t readBytes(uint8_t *data, size_t len)
Definition Arduino.h:140
virtual int available()
Definition Arduino.h:139
AudioInfo info
Definition AudioCodecsBase.h:80
void notifyAudioChange(AudioInfo info)
Definition AudioTypes.h:175
A Streaming Decoder where we provide both the input and output as streams.
Definition StreamingDecoder.h:29
Stream * p_input
Input stream for encoded audio data.
Definition StreamingDecoder.h:169
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
void clear()
Definition Vector.h:176
bool resize(size_t newSize, T value)
Definition Vector.h:266
T * data()
Definition Vector.h:316
int size()
Definition Vector.h:178
Vorbis Streaming Decoder using https://github.com/pschatzmann/arduino-libvorbis-tremor.
Definition CodecVorbis.h:32
void setWaitForData(size_t wait)
Defines the delay to wait if there is not enough data to open the decoder.
Definition CodecVorbis.h:160
virtual bool copy() override
Process a single read operation - to be called in the loop.
Definition CodecVorbis.h:90
~VorbisDecoder()
Destroy the VorbisDecoder object.
Definition CodecVorbis.h:37
bool active
Decoder active state.
Definition CodecVorbis.h:181
AudioInfo cfg
Definition CodecVorbis.h:173
static size_t read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
Definition CodecVorbis.h:227
static long tell_func(void *datasource)
Definition CodecVorbis.h:241
Vector< uint8_t > pcm
Definition CodecVorbis.h:174
AudioInfo currentInfo()
Definition CodecVorbis.h:199
size_t delay_on_no_data_ms
Definition CodecVorbis.h:178
static int seek_func(void *datasource, ogg_int64_t offset, int whence)
Definition CodecVorbis.h:236
bool is_ov_open
Definition CodecVorbis.h:183
bool is_first
Definition CodecVorbis.h:182
const char * readError(long error)
Definition CodecVorbis.h:252
int bitstream
Definition CodecVorbis.h:177
bool ovOpen()
Definition CodecVorbis.h:185
void setDelayOnNoData(size_t delay)
Defines the delay when there is no data.
Definition CodecVorbis.h:157
virtual size_t readBytes(uint8_t *data, size_t len) override
Reads bytes from the input stream.
Definition CodecVorbis.h:220
void end() override
Releases the reserved memory.
Definition CodecVorbis.h:72
OggVorbis_File file
Definition CodecVorbis.h:175
const char * getOpenError(int error)
Definition CodecVorbis.h:282
ov_callbacks callbacks
Definition CodecVorbis.h:176
size_t delay_wait_for_data_ms
Definition CodecVorbis.h:179
const char * mime() override
Provides "audio/ogg".
Definition CodecVorbis.h:154
bool begin() override
Starts the processing.
Definition CodecVorbis.h:44
Print * p_print
Output stream for PCM audio.
Definition VorbisDecoder.h:148
void setReadSize(size_t size)
Defines the default read size.
Definition CodecVorbis.h:163
AudioInfo audioInfo() override
Provides the last available MP3FrameInfo.
Definition CodecVorbis.h:85
size_t max_read_size
Definition CodecVorbis.h:180
static void checkMemory(bool printMemory=false)
Executes heap_caps_check_integrity_all()
Definition AudioRuntime.h:25
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
void delay(uint32_t ms)
Definition Arduino.h:259
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