arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
CodecVorbis.h
1#pragma once
2#include "AudioConfig.h"
3#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4#include "vorbis-tremor.h"
5
6// #include "AudioTools/AudioCodecs/ContainerOgg.h"
7// #include "ivorbiscodec.h"
8// #include "ivorbisfile.h"
9
10
11namespace audio_tools {
12
13#ifndef VARBIS_MAX_READ_SIZE
14# define VARBIS_MAX_READ_SIZE 256
15#endif
16
17#define VORBIS_HEADER_OPEN_LIMIT 1024
18
28public:
29 VorbisDecoder() = default;
30
33 if (active) {
34 end();
35 }
36 }
37
39 bool begin() override {
40 LOGI("begin");
41
42 callbacks.read_func = read_func;
43 callbacks.seek_func = seek_func;
44 callbacks.close_func = close_func;
45 callbacks.tell_func = tell_func;
46
47 if (p_input->available()>=VORBIS_HEADER_OPEN_LIMIT){
48 ovOpen();
49 }
50
51 active = true;
52 is_first = true;
53 return true;
54 }
55
57 void end() override {
58 LOGI("end");
59 active = false;
60 is_ov_open = false;
61 is_first = true;
62 ov_clear(&file);
63 }
64
66 AudioInfo audioInfo() override { return cfg; }
67
69 virtual operator bool() override { return active; }
70
71 virtual bool copy() override {
72 // wait for data
73 if (is_first){
74 // wait for some data
75 if(p_input->available()<VORBIS_HEADER_OPEN_LIMIT){
76 delay(20);
77 return false;
78 }
79 LOGI("available: %d", p_input->available());
80 is_first = false;
81 }
82
83 // open if not already done
84 if (!is_ov_open){
85 if (!ovOpen()) {
86 LOGE("not open");
87 return false;
88 }
89 }
90
91 if(pcm.data()==nullptr){
92 LOGE("Not enough memory");
93 return false;
94 }
95
96 // convert to pcm
97 long result = ov_read(&file, (char *)pcm.data(), pcm.size(), &bitstream);
98 LOGI("copy: %ld", result);
99 if (result > 0) {
100 AudioInfo current = currentInfo();
101 if (current != cfg) {
102 cfg = current;
103 cfg.logInfo();
104 notifyAudioChange(cfg);
105 }
106 p_print->write(pcm.data(), result);
107 delay(1);
108 return true;
109 } else {
110 if (result==-3){
111 // data interruption
112 LOGD("copy: %ld - %s", result, readError(result));
113 } else {
114 LOGE("copy: %ld - %s", result, readError(result));
115 }
116
117 return false;
118 }
119 }
120
121protected:
122 AudioInfo cfg;
123 Vector<uint8_t> pcm;
124 OggVorbis_File file;
125 ov_callbacks callbacks;
126 bool active;
127 int bitstream;
128 bool is_first = true;
129 bool is_ov_open = false;
130
131 bool ovOpen(){
132 pcm.resize(VARBIS_MAX_READ_SIZE);
133 int rc = ov_open_callbacks(this, &file, nullptr, 0, callbacks);
134 if (rc<0){
135 LOGE("ov_open_callbacks: %d", rc);
136 } else {
137 is_ov_open = true;
138 }
139 return is_ov_open;
140 }
141
142 AudioInfo currentInfo() {
143 AudioInfo result;
144 vorbis_info *info = ov_info(&file, -1);
145 result.sample_rate = info->rate;
146 result.channels = info->channels;
147 result.bits_per_sample = 16;
148 return result;
149 }
150
151 virtual size_t readBytes(uint8_t *data, size_t len) override {
152 size_t read_size = min(len,(size_t)VARBIS_MAX_READ_SIZE);
153 size_t result = p_input->readBytes((uint8_t *)data, read_size);
154 LOGD("readBytes: %zu",result);
155 return result;
156 }
157
158 static size_t read_func(void *ptr, size_t size, size_t nmemb,
159 void *datasource) {
160 VorbisDecoder *self = (VorbisDecoder *)datasource;
161 return self->readBytes((uint8_t *)ptr, size * nmemb);
162 }
163
164 static int seek_func(void *datasource, ogg_int64_t offset, int whence) {
165 VorbisDecoder *self = (VorbisDecoder *)datasource;
166 return -1;
167 }
168
169 static long tell_func(void *datasource) {
170 VorbisDecoder *self = (VorbisDecoder *)datasource;
171 return -1;
172 }
173
174 static int close_func(void *datasource) {
175 VorbisDecoder *self = (VorbisDecoder *)datasource;
176 self->end();
177 return 0;
178 }
179
180 const char* readError(long error){
181 switch(error){
182 case OV_HOLE:
183 return "Interruption in the data";
184 case OV_EBADLINK:
185 return "Invalid stream section ";
186 case OV_EINVAL:
187 return "Invalid header";
188 default:
189 return "N/A";
190 }
191 }
192
193};
194
195} // namespace audio_tools
A Streaming Decoder where we provide both the input and output as streams.
Definition AudioCodecsBase.h:160
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Vorbis Streaming Decoder using https://github.com/pschatzmann/arduino-libvorbis-tremor.
Definition CodecVorbis.h:27
virtual bool copy() override
Process a single read operation - to be called in the loop.
Definition CodecVorbis.h:71
~VorbisDecoder()
Destroy the VorbisDecoder object.
Definition CodecVorbis.h:32
void end() override
Releases the reserved memory.
Definition CodecVorbis.h:57
bool begin() override
Starts the processing.
Definition CodecVorbis.h:39
AudioInfo audioInfo() override
Provides the last available MP3FrameInfo.
Definition CodecVorbis.h:66
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioConfig.h:885
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:52