arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
MetaDataICY.h
1#pragma once
2#include <ctype.h> //isascii
3#include "AudioToolsConfig.h"
4#include "AbstractMetaData.h"
5#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
6#include "AudioTools/CoreAudio/AudioHttp/AbstractURLStream.h"
7
8namespace audio_tools {
9
26 enum Status { ProcessData, ProcessMetaData, SetupSize };
27
28 public:
29 MetaDataICY() = default;
30
32 MetaDataICY(int metaint) { setIcyMetaInt(metaint); }
33
34 virtual ~MetaDataICY() {}
35
37 virtual void setIcyMetaInt(int value) override {
38 this->mp3_blocksize = value;
39 }
40
42 virtual void setCallback(void (*fn)(MetaDataType info, const char* str,
43 int len)) override {
44 callback = fn;
45 }
46
48 virtual void setAudioDataCallback(void (*fn)(const uint8_t* str, int len),
49 int bufferLen = 1024) {
50 dataBuffer = new uint8_t[bufferLen];
51 dataCallback = fn;
52 dataLen = 0;
53 dataPos = 0;
54 }
55
57 virtual void begin() override {
58 clear();
59 LOGI("mp3_blocksize: %d", mp3_blocksize);
60 }
61
63 virtual void end() override { clear(); }
64
67 virtual size_t write(const uint8_t* data, size_t len) override {
68 if (callback != nullptr) {
69 for (size_t j = 0; j < len; j++) {
70 processChar((char)data[j]);
71 }
72 }
73 return len;
74 }
75
77 virtual Status status() { return currentStatus; }
78
80 virtual bool isData() { return currentStatus == ProcessData; }
81
83 virtual bool hasMetaData() { return this->mp3_blocksize > 0; }
84
86 virtual int metaInt() { return mp3_blocksize; }
87
89 virtual void processChar(char ch) {
90 switch (nextStatus) {
91 case ProcessData:
92 currentStatus = ProcessData;
93 processData(ch);
94
95 // increment data counter and determine next status
96 ++totalData;
97 if (totalData >= mp3_blocksize) {
98 LOGI("Data ended")
99 totalData = 0;
100 nextStatus = SetupSize;
101 }
102 break;
103
104 case SetupSize:
105 currentStatus = SetupSize;
106 totalData = 0;
107 metaDataPos = 0;
108 metaDataLen = metaSize(ch);
109 LOGI("metaDataLen: %d", metaDataLen);
110 if (metaDataLen > 0) {
111 if (metaDataLen > 200) {
112 LOGI("Unexpected metaDataLen -> processed as data");
113 nextStatus = ProcessData;
114 } else {
115 LOGI("Metadata found");
116 setupMetaData(metaDataLen);
117 nextStatus = ProcessMetaData;
118 }
119 } else {
120 LOGI("Data found");
121 nextStatus = ProcessData;
122 }
123 break;
124
125 case ProcessMetaData:
126 currentStatus = ProcessMetaData;
127 metaData[metaDataPos++] = ch;
128 if (metaDataPos >= metaDataLen) {
129 processMetaData(metaData.data(), metaDataLen);
130 LOGI("Metadata ended")
131 nextStatus = ProcessData;
132 }
133 break;
134 }
135 }
136
137 protected:
138 Status nextStatus = ProcessData;
139 Status currentStatus = ProcessData;
140 void (*callback)(MetaDataType info, const char* str, int len) = nullptr;
141 Vector<char> metaData{0};
142 int totalData = 0;
143 int mp3_blocksize = 0;
144 int metaDataMaxLen = 0;
145 int metaDataLen = 0;
146 int metaDataPos = 0;
147 bool is_data; // indicates if the current byte is a data byte
148 // data
149 uint8_t* dataBuffer = nullptr;
150 void (*dataCallback)(const uint8_t* str, int len) = nullptr;
151 int dataLen = 0;
152 int dataPos = 0;
153
154 virtual void clear() {
155 nextStatus = ProcessData;
156 totalData = 0;
157 metaData.resize(0);
158 metaDataLen = 0;
159 metaDataPos = 0;
160 dataLen = 0;
161 dataPos = 0;
162 }
163
165 virtual int metaSize(uint8_t metaSize) { return metaSize * 16; }
166
167 inline bool isAscii(uint8_t ch){ return ch < 128;}
168
170 virtual bool isAscii(char* result, int l) {
171 // check on first 10 characters
172 int m = l < 5 ? l : 10;
173 for (int j = 0; j < m; j++) {
174 if (!isAscii(result[j])) return false;
175 }
176 return true;
177 }
178
180 virtual void setupMetaData(int meta_size) {
181 TRACED();
182 metaData.resize(meta_size + 1);
183 metaDataMaxLen = meta_size;
184 memset(metaData.data(), 0, meta_size + 1);
185 }
186
189 virtual void processMetaData(char* metaData, int len) {
190 // CHECK_MEMORY();
191 TRACED();
192 metaData[len] = 0;
193 if (isAscii(metaData, 12)) {
194 LOGI("%s", metaData);
195 StrView meta(metaData, len + 1, len);
196 int start = meta.indexOf("StreamTitle=");
197 if (start >= 0) {
198 start += 12;
199 }
200 int end = meta.indexOf("';");
201 if (start >= 0 && end > start) {
202 metaData[end] = 0;
203 if (callback != nullptr) {
204 callback(Title, (const char*)metaData + start + 1, end - start);
205 }
206 }
207 // CHECK_MEMORY();
208 } else {
209 // CHECK_MEMORY();
210 LOGW("Unexpected Data: %s", metaData);
211 }
212 }
213
216 virtual void processData(char ch) {
217 if (dataBuffer != nullptr) {
218 dataBuffer[dataPos++] = ch;
219 // output data via callback
220 if (dataPos >= dataLen) {
221 dataCallback(dataBuffer, dataLen);
222 dataPos = 0;
223 }
224 }
225 }
226};
227
236 public:
240 TRACED();
241 p_url = &url;
242 const char* iceMetaintStr = url.getReplyHeader("icy-metaint");
243 if (iceMetaintStr) {
244 LOGI("icy-metaint: %s", iceMetaintStr);
245 } else {
246 LOGE("icy-metaint not defined");
247 }
248 StrView value(iceMetaintStr);
249 int iceMetaint = value.toInt();
250 return iceMetaint;
251 }
252
255 void executeCallback(void (*callback)(MetaDataType info, const char* str,
256 int len)) {
257 TRACEI();
258 if (callback == nullptr) {
259 LOGW("callback not defined")
260 }
261 if (p_url == nullptr) {
262 LOGW("http not defined")
263 }
264 // Callbacks filled from url reply for icy
265 if (callback != nullptr && p_url != nullptr) {
266 // handle icy parameters
267 StrView genre(p_url->getReplyHeader("icy-genre"));
268 if (!genre.isEmpty()) {
269 callback(Genre, genre.c_str(), genre.length());
270 }
271
272 StrView descr(p_url->getReplyHeader("icy-description"));
273 if (!descr.isEmpty()) {
274 callback(Description, descr.c_str(), descr.length());
275 }
276
277 StrView name(p_url->getReplyHeader("icy-name"));
278 if (!name.isEmpty()) {
279 callback(Name, name.c_str(), name.length());
280 }
281 }
282 }
283
284 protected:
285 AbstractURLStream* p_url = nullptr;
286};
287
288} // namespace audio_tools
Common Metadata methods.
Definition AbstractMetaData.h:34
Abstract Base class for all URLStream implementations.
Definition AbstractURLStream.h:17
virtual const char * getReplyHeader(const char *header)=0
Provides reply header information.
Resolve icy-metaint from HttpRequest and execute metadata callbacks.
Definition MetaDataICY.h:235
int setup(AbstractURLStream &url)
Definition MetaDataICY.h:239
void executeCallback(void(*callback)(MetaDataType info, const char *str, int len))
Definition MetaDataICY.h:255
Icecast/Shoutcast Metadata Handling. Metadata class which splits the data into audio and metadata....
Definition MetaDataICY.h:25
virtual void setCallback(void(*fn)(MetaDataType info, const char *str, int len)) override
Defines the metadata callback function.
Definition MetaDataICY.h:42
virtual Status status()
Returns the actual status of the state engine for the current byte.
Definition MetaDataICY.h:77
virtual size_t write(const uint8_t *data, size_t len) override
Definition MetaDataICY.h:67
MetaDataICY(int metaint)
We just process the Metadata and ignore the audio info.
Definition MetaDataICY.h:32
virtual bool isAscii(char *result, int l)
Make sure that the result is a valid ASCII string.
Definition MetaDataICY.h:170
virtual void setupMetaData(int meta_size)
allocates the memory to store the metadata / we support changing sizes
Definition MetaDataICY.h:180
virtual int metaSize(uint8_t metaSize)
determines the meta data size from the size byte
Definition MetaDataICY.h:165
virtual void begin() override
Resets all counters and restarts the prcessing.
Definition MetaDataICY.h:57
virtual bool hasMetaData()
Returns true if the ICY stream contains metadata.
Definition MetaDataICY.h:83
virtual void setAudioDataCallback(void(*fn)(const uint8_t *str, int len), int bufferLen=1024)
Defines the audio callback function.
Definition MetaDataICY.h:48
virtual int metaInt()
provides the metaint
Definition MetaDataICY.h:86
virtual void processMetaData(char *metaData, int len)
Definition MetaDataICY.h:189
virtual void end() override
Resets all counters and restarts the prcessing.
Definition MetaDataICY.h:63
virtual void setIcyMetaInt(int value) override
Defines the ICE metaint value which is provided by the web call!
Definition MetaDataICY.h:37
virtual bool isData()
returns true if the actual bytes is an audio data byte (e.g.mp3)
Definition MetaDataICY.h:80
virtual void processData(char ch)
Definition MetaDataICY.h:216
virtual void processChar(char ch)
character based state engine
Definition MetaDataICY.h:89
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
virtual int length()
Definition StrView.h:383
virtual bool isEmpty()
checks if the string is empty
Definition StrView.h:386
virtual const char * c_str()
provides the string value as const char*
Definition StrView.h:379
int toInt()
Converts the string to an int.
Definition StrView.h:575
virtual int indexOf(const char c, int start=0)
Definition StrView.h:260
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
MetaDataType
Type of meta info.
Definition AbstractMetaData.h:11
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10