arduino-audio-tools
Loading...
Searching...
No Matches
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 bool begin() override {
58 clear();
59 LOGI("mp3_blocksize: %d", mp3_blocksize);
60 return true;
61 }
62
64 virtual void end() override { clear(); }
65
68 virtual size_t write(const uint8_t* data, size_t len) override {
69 if (callback != nullptr) {
70 for (size_t j = 0; j < len; j++) {
71 processChar((char)data[j]);
72 }
73 }
74 return len;
75 }
76
78 virtual Status status() { return currentStatus; }
79
81 virtual bool isData() { return currentStatus == ProcessData; }
82
84 virtual bool hasMetaData() { return this->mp3_blocksize > 0; }
85
87 virtual int metaInt() { return mp3_blocksize; }
88
90 virtual void processChar(char ch) {
91 switch (nextStatus) {
92 case ProcessData:
93 currentStatus = ProcessData;
94 processData(ch);
95
96 // increment data counter and determine next status
97 ++totalData;
98 if (totalData >= mp3_blocksize) {
99 LOGI("Data ended")
100 totalData = 0;
101 nextStatus = SetupSize;
102 }
103 break;
104
105 case SetupSize:
106 currentStatus = SetupSize;
107 totalData = 0;
108 metaDataPos = 0;
109 metaDataLen = metaSize(ch);
110 LOGI("metaDataLen: %d", metaDataLen);
111 if (metaDataLen > 0) {
112 if (metaDataLen > 200) {
113 LOGI("Unexpected metaDataLen -> processed as data");
114 nextStatus = ProcessData;
115 } else {
116 LOGI("Metadata found");
117 setupMetaData(metaDataLen);
118 nextStatus = ProcessMetaData;
119 }
120 } else {
121 LOGI("Data found");
122 nextStatus = ProcessData;
123 }
124 break;
125
126 case ProcessMetaData:
127 currentStatus = ProcessMetaData;
128 metaData[metaDataPos++] = ch;
129 if (metaDataPos >= metaDataLen) {
130 processMetaData(metaData.data(), metaDataLen);
131 LOGI("Metadata ended")
132 nextStatus = ProcessData;
133 }
134 break;
135 }
136 }
137
138 protected:
139 Status nextStatus = ProcessData;
140 Status currentStatus = ProcessData;
141 void (*callback)(MetaDataType info, const char* str, int len) = nullptr;
142 Vector<char> metaData{0};
143 int totalData = 0;
144 int mp3_blocksize = 0;
145 int metaDataMaxLen = 0;
146 int metaDataLen = 0;
147 int metaDataPos = 0;
148 bool is_data; // indicates if the current byte is a data byte
149 // data
150 uint8_t* dataBuffer = nullptr;
151 void (*dataCallback)(const uint8_t* str, int len) = nullptr;
152 int dataLen = 0;
153 int dataPos = 0;
154
155 virtual void clear() {
156 nextStatus = ProcessData;
157 totalData = 0;
158 metaData.resize(0);
159 metaDataLen = 0;
160 metaDataPos = 0;
161 dataLen = 0;
162 dataPos = 0;
163 }
164
166 virtual int metaSize(uint8_t metaSize) { return metaSize * 16; }
167
168 inline bool isAscii(uint8_t ch){ return ch < 128;}
169
171 virtual bool isAscii(char* result, int l) {
172 // check on first 10 characters
173 int m = l < 5 ? l : 10;
174 for (int j = 0; j < m; j++) {
175 if (!isAscii(result[j])) return false;
176 }
177 return true;
178 }
179
181 virtual void setupMetaData(int meta_size) {
182 TRACED();
183 metaData.resize(meta_size + 1);
184 metaDataMaxLen = meta_size;
185 memset(metaData.data(), 0, meta_size + 1);
186 }
187
190 virtual void processMetaData(char* metaData, int len) {
191 // CHECK_MEMORY();
192 TRACED();
193 metaData[len] = 0;
194 if (isAscii(metaData, 12)) {
195 LOGI("%s", metaData);
196 StrView meta(metaData, len + 1, len);
197 int start = meta.indexOf("StreamTitle=");
198 if (start >= 0) {
199 start += 12;
200 }
201 int end = meta.indexOf("';");
202 if (start >= 0 && end > start) {
203 metaData[end] = 0;
204 if (callback != nullptr) {
205 callback(Title, (const char*)metaData + start + 1, end - start);
206 }
207 }
208 // CHECK_MEMORY();
209 } else {
210 // CHECK_MEMORY();
211 LOGW("Unexpected Data: %s", metaData);
212 }
213 }
214
217 virtual void processData(char ch) {
218 if (dataBuffer != nullptr) {
219 dataBuffer[dataPos++] = ch;
220 // output data via callback
221 if (dataPos >= dataLen) {
222 dataCallback(dataBuffer, dataLen);
223 dataPos = 0;
224 }
225 }
226 }
227};
228
237 public:
241 TRACED();
242 p_url = &url;
243 const char* iceMetaintStr = url.getReplyHeader("icy-metaint");
244 if (iceMetaintStr) {
245 LOGI("icy-metaint: %s", iceMetaintStr);
246 } else {
247 LOGE("icy-metaint not defined");
248 }
249 StrView value(iceMetaintStr);
250 int iceMetaint = value.toInt();
251 return iceMetaint;
252 }
253
256 void executeCallback(void (*callback)(MetaDataType info, const char* str,
257 int len)) {
258 TRACEI();
259 if (callback == nullptr) {
260 LOGW("callback not defined")
261 }
262 if (p_url == nullptr) {
263 LOGW("http not defined")
264 }
265 // Callbacks filled from url reply for icy
266 if (callback != nullptr && p_url != nullptr) {
267 // handle icy parameters
268 StrView genre(p_url->getReplyHeader("icy-genre"));
269 if (!genre.isEmpty()) {
270 callback(Genre, genre.c_str(), genre.length());
271 }
272
273 StrView descr(p_url->getReplyHeader("icy-description"));
274 if (!descr.isEmpty()) {
275 callback(Description, descr.c_str(), descr.length());
276 }
277
278 StrView name(p_url->getReplyHeader("icy-name"));
279 if (!name.isEmpty()) {
280 callback(Name, name.c_str(), name.length());
281 }
282 }
283 }
284
285 protected:
286 AbstractURLStream* p_url = nullptr;
287};
288
289} // 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:236
int setup(AbstractURLStream &url)
Definition MetaDataICY.h:240
void executeCallback(void(*callback)(MetaDataType info, const char *str, int len))
Definition MetaDataICY.h:256
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:78
virtual size_t write(const uint8_t *data, size_t len) override
Definition MetaDataICY.h:68
MetaDataICY(int metaint)
We just process the Metadata and ignore the audio info.
Definition MetaDataICY.h:32
virtual bool begin() override
Resets all counters and restarts the prcessing.
Definition MetaDataICY.h:57
virtual bool isAscii(char *result, int l)
Make sure that the result is a valid ASCII string.
Definition MetaDataICY.h:171
virtual void setupMetaData(int meta_size)
allocates the memory to store the metadata / we support changing sizes
Definition MetaDataICY.h:181
virtual int metaSize(uint8_t metaSize)
determines the meta data size from the size byte
Definition MetaDataICY.h:166
virtual bool hasMetaData()
Returns true if the ICY stream contains metadata.
Definition MetaDataICY.h:84
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:87
virtual void processMetaData(char *metaData, int len)
Definition MetaDataICY.h:190
virtual void end() override
Resets all counters and restarts the prcessing.
Definition MetaDataICY.h:64
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:81
virtual void processData(char ch)
Definition MetaDataICY.h:217
virtual void processChar(char ch)
character based state engine
Definition MetaDataICY.h:90
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