arduino-audio-tools
Loading...
Searching...
No Matches
MultiDecoder.h
1
2#pragma once
3
4#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
5#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
6#include "AudioTools/CoreAudio/AudioHttp/AbstractURLStream.h"
7#include "AudioTools/CoreAudio/AudioMetaData/MimeDetector.h"
8#include "AudioTools/AudioCodecs/StreamingDecoder.h"
9
10namespace audio_tools {
11
42class MultiDecoder : public AudioDecoder {
43 public:
47 MultiDecoder() = default;
48
58 MultiDecoder(MimeSource& mimeSource) { setMimeSource(mimeSource); }
59
60 #ifdef USE_EXPERIMENTAL
67 // Clean up any adapters we created
68 for (auto* adapter : adapters) {
69 delete adapter;
70 }
71 adapters.clear();
72 }
73#endif
74
83 bool begin() override {
85 is_first = true;
86 if (p_print == nullptr) {
87 LOGE("No output defined");
88 return false;
89 }
90 return true;
91 }
92
100 void end() override {
101 if (actual_decoder.decoder != nullptr && actual_decoder.is_open) {
102 actual_decoder.decoder->end();
103 }
104 actual_decoder.is_open = false;
105 actual_decoder.decoder = nullptr;
106 actual_decoder.mime = nullptr;
107 is_first = true;
108 }
109
119 void addDecoder(AudioDecoder& decoder, const char* mime) {
120 DecoderInfo info{mime, &decoder};
121 decoder.addNotifyAudioChange(*this);
122 decoders.push_back(info);
123 }
124
137 void addDecoder(AudioDecoder& decoder, const char* mime,
138 bool (*check)(uint8_t* data, size_t len)) {
139 addDecoder(decoder, mime);
140 mime_detector.setCheck(mime, check);
141 }
142
151 void setOutput(Print& out_stream) override {
152 p_print = &out_stream;
153 }
154
170 void setMimeSource(MimeSource& mimeSource) { p_mime_source = &mimeSource; }
171
183 bool selectDecoder(const char* mime) {
184 bool result = false;
185 if (mime == nullptr) return false;
186 // do nothing if no change
187 if (StrView(mime).equals(actual_decoder.mime)) {
188 is_first = false;
189 return true;
190 }
191 // close actual decoder
192 if (actual_decoder.decoder != this) end();
193
194 // find the corresponding decoder
195 selected_mime = nullptr;
196 for (int j = 0; j < decoders.size(); j++) {
197 DecoderInfo info = decoders[j];
198 if (StrView(info.mime).equals(mime)) {
199 LOGI("Using decoder for %s (%s)", info.mime, mime);
200 actual_decoder = info;
201 // define output if it has not been defined
202 if (p_print != nullptr && actual_decoder.decoder != this
203 && actual_decoder.decoder->getOutput() == nullptr) {
205 }
206 if (!*actual_decoder.decoder) {
207 actual_decoder.decoder->begin();
208 LOGI("Decoder %s started", actual_decoder.mime);
209 }
210 result = true;
211 selected_mime = mime;
212 break;
213 }
214 }
215 is_first = false;
216 return result;
217 }
218
225 const char* selectedMime() { return selected_mime; }
226
241 size_t write(const uint8_t* data, size_t len) override {
242 if (is_first) {
243 const char* mime = nullptr;
244 if (p_mime_source != nullptr) {
245 // get content type from http header
246 mime = p_mime_source->mime();
247 if (mime) LOGI("mime from http request: %s", mime);
248 }
249 if (mime == nullptr) {
250 // use the mime detector
251 mime_detector.write((uint8_t*)data, len);
252 mime = mime_detector.mime();
253 if (mime) LOGI("mime from mime_detector: %s", mime);
254 }
255 if (mime != nullptr) {
256 // select the decoder based on the detemined mime type
257 if (!selectDecoder(mime)) {
258 LOGE("The decoder could not be found for %s", mime);
260 actual_decoder.is_open = true;
261 }
262 }
263 is_first = false;
264 }
265 // check if we have a decoder
266 if (actual_decoder.decoder == nullptr) return 0;
267 // decode the data
268 return actual_decoder.decoder->write(data, len);
269 }
270
277 virtual operator bool() override {
278 if (actual_decoder.decoder == &nop) return false;
280 };
281
292 bool setCodecConfig(const uint8_t* data, size_t len) override {
293 if (actual_decoder.decoder == nullptr) {
294 LOGE("No decoder defined, cannot set codec config");
295 return false;
296 }
297 return actual_decoder.decoder->setCodecConfig(data, len);
298 }
299
310
311#ifdef USE_EXPERIMENTAL
312
325 void addDecoder(StreamingDecoder& decoder, const char* mime,
326 int bufferSize = 1024) {
327 if (mime != nullptr) {
328 // Create a DecoderAdapter to wrap the StreamingDecoder
329 decoder.addNotifyAudioChange(*this);
330 auto adapter = new DecoderAdapter(decoder, bufferSize);
331 adapters.push_back(adapter); // Store for cleanup
332
333 // Add the adapter as a regular AudioDecoder
334 addDecoder(*adapter, mime);
335 } else {
336 LOGE("MIME type is nullptr - cannot add StreamingDecoder");
337 }
338 }
339#endif
340
341 protected:
345 struct DecoderInfo {
346 const char* mime = nullptr;
348 bool is_open = false;
349
353 DecoderInfo() = default;
354
362 this->mime = mime;
363 this->decoder = decoder;
364 }
366
368#ifdef USE_EXPERIMENTAL
369 Vector<DecoderAdapter*> adapters{0};
370#endif
374 bool is_first = true;
375 const char* selected_mime = nullptr;
376};
377
378} // namespace audio_tools
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
virtual void setOutput(AudioStream &out_stream)
Defines where the decoded result is written to.
Definition AudioCodecsBase.h:36
virtual bool setCodecConfig(const uint8_t *data, size_t len)
Some decoders need e.g. a magic cookie to provide the relevant info for decoding.
Definition AudioCodecsBase.h:69
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:151
Dummy no implmentation Codec. This is used so that we can initialize some pointers to decoders and en...
Definition AudioCodecsBase.h:130
Adapter class which allows the AudioDecoder API on a StreamingDecoder.
Definition StreamingDecoder.h:856
Logic to detemine the mime type from the content. By default the following mime types are supported (...
Definition MimeDetector.h:61
bool begin()
Sets is_first to true.
Definition MimeDetector.h:80
size_t write(uint8_t *data, size_t len)
write the header to determine the mime
Definition MimeDetector.h:93
const char * mime()
Definition MimeDetector.h:124
void setCheck(const char *mime, bool(*check)(uint8_t *start, size_t len), bool isActvie=true)
adds/updates the checking logic for the indicated mime
Definition MimeDetector.h:100
Abstract interface for classes that can provide MIME type information.
Definition MimeDetector.h:28
virtual const char * mime()=0
Get the MIME type string.
Manage multiple AudioDecoders with automatic format detection.
Definition MultiDecoder.h:42
void setOutput(Print &out_stream) override
Sets the output stream for decoded audio data.
Definition MultiDecoder.h:151
struct audio_tools::MultiDecoder::DecoderInfo actual_decoder
Currently active decoder information.
MultiDecoder()=default
Default constructor.
bool setCodecConfig(const uint8_t *data, size_t len) override
Sets codec-specific configuration data.
Definition MultiDecoder.h:292
void setMimeSource(MimeSource &mimeSource)
Sets an external MIME source for format detection.
Definition MultiDecoder.h:170
const char * selectedMime()
Returns the MIME type that was detected and selected.
Definition MultiDecoder.h:225
bool selectDecoder(const char *mime)
Selects the actual decoder by MIME type.
Definition MultiDecoder.h:183
CodecNOP nop
No-operation codec for unsupported formats.
Definition MultiDecoder.h:372
bool is_first
Flag for first write() call.
Definition MultiDecoder.h:374
void addDecoder(AudioDecoder &decoder, const char *mime, bool(*check)(uint8_t *data, size_t len))
Adds a decoder with custom MIME detection logic.
Definition MultiDecoder.h:137
MimeDetector mime_detector
MIME type detection engine.
Definition MultiDecoder.h:371
void end() override
Releases resources and closes the active decoder.
Definition MultiDecoder.h:100
MultiDecoder(MimeSource &mimeSource)
Constructor with external MIME source.
Definition MultiDecoder.h:58
size_t write(const uint8_t *data, size_t len) override
Writes encoded audio data to be decoded.
Definition MultiDecoder.h:241
void addDecoder(AudioDecoder &decoder, const char *mime)
Adds a decoder that will be selected by its MIME type.
Definition MultiDecoder.h:119
Vector< DecoderInfo > decoders
Collection of registered decoders.
Definition MultiDecoder.h:367
const char * selected_mime
MIME type that was selected.
Definition MultiDecoder.h:375
MimeSource * p_mime_source
Optional external MIME source.
Definition MultiDecoder.h:373
bool begin() override
Starts the processing and enables automatic MIME type determination.
Definition MultiDecoder.h:83
MimeDetector & mimeDetector()
Provides access to the internal MIME detector.
Definition MultiDecoder.h:309
Definition NoArduino.h:62
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
virtual bool equals(const char *str)
checks if the string equals indicated parameter string
Definition StrView.h:165
A Streaming Decoder where we provide both the input and output as streams.
Definition StreamingDecoder.h:29
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Information about a registered decoder.
Definition MultiDecoder.h:345
bool is_open
Whether the decoder is currently active.
Definition MultiDecoder.h:348
DecoderInfo(const char *mime, AudioDecoder *decoder)
Constructor with parameters.
Definition MultiDecoder.h:361
AudioDecoder * decoder
Pointer to the decoder instance.
Definition MultiDecoder.h:347
DecoderInfo()=default
Default constructor.
const char * mime
MIME type for this decoder.
Definition MultiDecoder.h:346