arduino-audio-tools
Loading...
Searching...
No Matches
StreamingDecoder.h
1#pragma once
2#include <new>
3#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
5#include "AudioTools/CoreAudio/AudioMetaData/MimeDetector.h"
6#include "AudioTools/CoreAudio/AudioOutput.h"
7#include "AudioTools/CoreAudio/BaseStream.h"
8
9namespace audio_tools {
10
30 public:
31
32 virtual ~StreamingDecoder() = default;
33
42 virtual bool begin() = 0;
43
49 virtual void end() = 0;
50
58 virtual void setOutput(Print& out_stream) { p_print = &out_stream; }
59
67 virtual void setOutput(AudioStream& out_stream) {
68 Print* p_print = &out_stream;
70 addNotifyAudioChange(out_stream);
71 }
72
80 virtual void setOutput(AudioOutput& out_stream) {
81 Print* p_print = &out_stream;
83 addNotifyAudioChange(out_stream);
84 }
85
94 void setInput(Stream& inStream) { this->p_input = &inStream; }
95
104 virtual AudioInfo audioInfo() = 0;
105
111 virtual operator bool() = 0;
112
122 virtual bool copy() = 0;
123
132 bool copyAll() {
133 bool result = false;
134 while (copy()) {
135 result = true;
136 }
137 return result;
138 }
139
146 virtual const char* mime() = 0;
147
148 protected:
158 virtual size_t readBytes(uint8_t* data, size_t len) = 0;
159
160 void setAudioInfo(AudioInfo newInfo) override {
161 TRACED();
162 if (this->info != newInfo) {
163 this->info = newInfo;
164 notifyAudioChange(info);
165 }
166 }
167
168 Print* p_print = nullptr;
169 Stream* p_input = nullptr;
170 AudioInfo info;
171};
172
189 public:
198 StreamingDecoderAdapter(AudioDecoder& decoder, const char* mimeStr,
199 int copySize = DEFAULT_BUFFER_SIZE) {
200 p_decoder = &decoder;
202 mime_str = mimeStr;
203 if (copySize > 0) resize(copySize);
204 }
205
213 bool begin() override {
214 TRACED();
215 if (p_decoder == nullptr) return false;
216 if (p_input == nullptr) return false;
217 return p_decoder->begin();
218 }
219
225 void end() override { p_decoder->end(); }
226
234 void setOutput(Print& out_stream) override {
235 p_decoder->setOutput(out_stream);
236 }
237
245 AudioInfo audioInfo() override { return p_decoder->audioInfo(); }
246
252 virtual operator bool() override { return *p_decoder; }
253
262 virtual bool copy() override {
263 int read = readBytes(buffer.data(), buffer.size());
264 int written = 0;
265 if (read > 0) written = p_decoder->write(&buffer[0], read);
266 bool rc = written > 0;
267 LOGI("copy: %s", rc ? "success" : "failure");
268 return rc;
269 }
270
279 void resize(int bufferSize) { buffer.resize(bufferSize); }
280
288 const char* mime() override { return mime_str; }
289
290 protected:
293 const char* mime_str = nullptr;
294
302 size_t readBytes(uint8_t* data, size_t len) override {
303 if (p_input == nullptr) return 0;
304 return p_input->readBytes(data, len);
305 }
306};
307
334 public:
339
346 // Clean up any adapters we created
347 for (auto* adapter : adapters) {
348 delete adapter;
349 }
350 adapters.clear();
351 }
352
361 bool begin() override {
363 is_first = true;
364 if (p_print == nullptr) {
365 LOGE("No output defined");
366 return false;
367 }
368 return true;
369 }
370
376 void end() override {
377 if (actual_decoder.decoder != nullptr && actual_decoder.is_open) {
379 }
380 actual_decoder.is_open = false;
381 actual_decoder.decoder = nullptr;
382 actual_decoder.mime = nullptr;
383 is_first = true;
384 }
385
391 void setOutput(Print& out_stream) override {
392 StreamingDecoder::setOutput(out_stream);
393 }
394
400 void setOutput(AudioStream& out_stream) override {
401 StreamingDecoder::setOutput(out_stream);
402 }
403
409 void setOutput(AudioOutput& out_stream) override {
410 StreamingDecoder::setOutput(out_stream);
411 }
412
418 void setInput(Stream& inStream) {
420 }
421
431 decoder.addNotifyAudioChange(*this);
432 const char* mime = decoder.mime();
433 if (mime != nullptr) {
434 DecoderInfo info{mime, &decoder};
435 decoders.push_back(info);
436 } else {
437 LOGE("Decoder mime() returned nullptr - cannot add decoder");
438 }
439 }
440
450 void addDecoder(StreamingDecoder& decoder, const char* mime) {
451 if (mime != nullptr) {
452 decoder.addNotifyAudioChange(*this);
453 DecoderInfo info{mime, &decoder};
454 decoders.push_back(info);
455 } else {
456 LOGE("Decoder mime() returned nullptr - cannot add decoder");
457 }
458 }
459
475 void addDecoder(AudioDecoder& decoder, const char* mime,
476 int bufferSize = DEFAULT_BUFFER_SIZE) {
477 if (mime != nullptr) {
478 // Create a StreamingDecoderAdapter to wrap the AudioDecoder
479 decoder.addNotifyAudioChange(*this);
480 auto adapter = new StreamingDecoderAdapter(decoder, mime, bufferSize);
481 adapters.push_back(adapter); // Store for cleanup
482
483 DecoderInfo info{mime, adapter};
484 decoders.push_back(info);
485 } else {
486 LOGE("MIME type is nullptr - cannot add AudioDecoder");
487 }
488 }
489
496 virtual operator bool() override {
497 if (actual_decoder.decoder == nullptr) return false;
499 }
500
511 virtual bool copy() override {
512 if (p_input == nullptr) return false;
513
514 // Automatically select decoder if not already selected
515 if (is_first) {
516 // determine the mime and select the decoder
517 if (!selectDecoder()) {
518 return false;
519 }
520 is_first = false;
521 }
522
523 // Check if we have a decoder
524 if (actual_decoder.decoder == nullptr) return false;
525
526 // Use the selected decoder to process data
527 return actual_decoder.decoder->copy();
528 }
529
540 bool selectDecoder(const char* mime) {
541 TRACEI();
542 bool result = false;
543
544 // Guard against null MIME type - cannot proceed without valid MIME
545 if (mime == nullptr) {
546 LOGE("mime is null");
547 return false;
548 }
549
550 // Optimization: Check if the requested MIME type is already active
551 // This avoids unnecessary decoder switching when the same format is detected
552 if (StrView(mime).equals(actual_decoder.mime)) {
553 is_first = false; // Mark initialization as complete
554 return true; // Already using the correct decoder
555 }
556
557 // Clean shutdown of currently active decoder before switching
558 // This ensures proper resource cleanup and state reset
559 if (actual_decoder.decoder != nullptr) {
561 actual_decoder.is_open = false; // Mark as inactive
562 }
563
564 // Search through all registered decoders to find one that handles this MIME type
565 selected_mime = nullptr; // Clear previous selection
566 for (int j = 0; j < decoders.size(); j++) {
567 DecoderInfo info = decoders[j];
568
569 // Check if this decoder supports the detected MIME type
570 if (StrView(info.mime).equals(mime)) {
571 LOGI("Using Decoder %s for %s", toStr(info.mime), toStr(mime));
572
573 // Switch to the matching decoder
574 actual_decoder = info;
575
576 // Configure the decoder's output stream to match our output
577 // This ensures decoded audio data flows to the correct destination
578 if (p_print != nullptr) {
580 }
581
582 // Initialize the selected decoder and mark it as active
583 LOGI("available: %d", p_data_source->available());
584 assert(p_data_source != nullptr);
589 actual_decoder.is_open = true;
590 LOGI("StreamingDecoder %s started", toStr(actual_decoder.mime));
591 } else {
592 // Decoder failed to start - this is a critical error
593 LOGE("Failed to start StreamingDecoder %s", toStr(actual_decoder.mime));
594 return false;
595 }
596
597 // Successfully found and initialized a decoder
598 result = true;
599 selected_mime = mime; // Store the MIME type that was selected
600 break; // Stop searching once we find a match
601 }
602 }
603
604 // Mark initialization phase as complete regardless of success/failure
605 is_first = false;
606 return result; // true if decoder was found and started, false otherwise
607 }
608
614 const char* mime() override {
615 // fallback to actual decoder
616 if (actual_decoder.decoder != nullptr) {
617 return actual_decoder.decoder->mime();
618 }
619 return nullptr;
620 }
621
627 const char* selectedMime() { return selected_mime; }
628
635 AudioInfo audioInfo() override {
636 if (actual_decoder.decoder != nullptr) {
638 }
639 AudioInfo empty;
640 return empty;
641 }
642
663
694 void setMimeSource(MimeSource& mimeSource) { p_mime_source = &mimeSource; }
695
696 protected:
697
701 struct DecoderInfo {
702 const char* mime = nullptr;
704 bool is_open = false;
705
709 DecoderInfo() = default;
710
718 this->mime = mime;
719 this->decoder = decoder;
720 }
722
728 bool is_first = true;
729 const char* selected_mime = nullptr;
731 nullptr;
733
735 const char* toStr(const char* str){
736 return str == nullptr ? "" : str;
737 }
738
768 // Only perform MIME detection and decoder selection if no decoder is active yet
769 // This prevents re-detection on subsequent calls during the same stream
770 if (actual_decoder.decoder == nullptr) {
771 const char* mime = nullptr;
772 p_data_source = nullptr;
773
774 // Two methods for MIME type determination: external source or auto-detection
775 if (p_mime_source != nullptr) {
776 // Option 1: Use externally provided MIME source (e.g., from HTTP headers)
777 // This is more efficient as it avoids reading and analyzing stream data
779 LOGI("mime from source: %s", toStr(mime));
780 assert(p_input != nullptr);
782 } else {
783 // Option 2: Auto-detect MIME type by analyzing stream content
784 // Redirect the decoder to use the buffered stream
785 // we use the buffered stream as input
786 assert(p_input != nullptr);
787 buffered_stream.setStream(*p_input);
788 buffered_stream.resize(DEFAULT_BUFFER_SIZE);
790
791 // This requires reading a sample of data to identify the format
792 detection_buffer.resize(160);
793 size_t bytesRead = buffered_stream.peekBytes(detection_buffer.data(), detection_buffer.size()); // If no data is available, we cannot proceed with detection
794 if (bytesRead == 0) return false;
795
796 // Feed the sample data to the MIME detector for format analysis
797 // The detector examines file headers, magic numbers, etc.
798 mime_detector.write(detection_buffer.data(), bytesRead);
800 LOGI("mime from detector: %s", toStr(mime));
801
802 }
803
804 // Process the detected/provided MIME type
805 if (mime != nullptr) {
806 // Delegate to the overloaded selectDecoder(mime) method to find
807 // and initialize the appropriate decoder for this MIME type
808 if (!selectDecoder(mime)) {
809 LOGE("The decoder could not be selected for %s", toStr(mime));
810 return false; // No registered decoder can handle this format
811 }
812 } else {
813 // MIME detection failed - format is unknown or unsupported
814 LOGE("Could not determine mime type");
815 return false;
816 }
817 } else {
818 LOGI("Decoder already selected: %s", toStr(actual_decoder.mime));
819 assert(p_input != nullptr);
821 }
822
823 // Success: either decoder was already selected or selection completed successfully
824 return true;
825 }
826
834 size_t readBytes(uint8_t* data, size_t len) override {
835 if (p_input == nullptr) return 0;
836 return p_input->readBytes(data, len);
837 }
838};
839
857 public:
864 DecoderAdapter(StreamingDecoder& dec, int bufferSize) {
865 TRACED();
866 p_dec = &dec;
868 resize(bufferSize);
869 }
870
878 void setOutput(Print& out) override { p_dec->setOutput(out); }
879
885 void setInput(Stream& in) { p_dec->setInput(in); }
886
894 bool begin() override {
895 TRACED();
896 active = true;
897 bool rc = p_dec->begin();
898 return rc;
899 }
900
907 void end() override {
908 TRACED();
909 active = false;
910 }
911
920 void resize(int size) {
921 buffer_size = size;
922 // setup the buffer only if needed
923 if (is_setup) rbuffer.resize(size);
924 }
925
936 size_t write(const uint8_t* data, size_t len) override {
937 TRACED();
938 setupLazy();
939 size_t result = queue.write((uint8_t*)data, len);
940 // Trigger processing - process all available data
941 while (p_dec->copy());
942
943 return result;
944 }
945
955
961 operator bool() override { return active; }
962
963 protected:
964 bool active = false;
965 bool is_setup = false;
970
976 void setupLazy() {
977 if (!is_setup) {
979 queue.begin();
980 is_setup = true;
981 }
982 }
983};
984
991
992} // 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
AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition AudioCodecsBase.h:25
Supports the subscription to audio change notifications.
Definition AudioTypes.h:148
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:151
virtual void clearNotifyAudioChange()
Deletes all change notify subscriptions.
Definition AudioTypes.h:164
Supports changes to the sampling rate, bits and channels.
Definition AudioTypes.h:133
Abstract Audio Ouptut class.
Definition AudioOutput.h:22
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:122
The Arduino Stream supports operations on single characters. This is usually not the best way to push...
Definition AudioStreams.h:483
size_t peekBytes(uint8_t *data, size_t len)
Provides data w/o consuming.
Definition AudioStreams.h:579
void resize(int size)
Resize the buffer.
Definition AudioStreams.h:596
Adapter class which allows the AudioDecoder API on a StreamingDecoder.
Definition StreamingDecoder.h:856
RingBuffer< uint8_t > rbuffer
Ring buffer for data storage.
Definition StreamingDecoder.h:968
bool active
Whether the adapter is active.
Definition StreamingDecoder.h:964
void setOutput(Print &out) override
Defines the output Stream.
Definition StreamingDecoder.h:878
QueueStream< uint8_t > queue
Stream interface to the ring buffer.
Definition StreamingDecoder.h:969
StreamingDecoder * getStreamingDecoder()
Gets the wrapped StreamingDecoder.
Definition StreamingDecoder.h:954
void setupLazy()
Performs lazy initialization of the ring buffer.
Definition StreamingDecoder.h:976
void end() override
Stops the processing.
Definition StreamingDecoder.h:907
size_t write(const uint8_t *data, size_t len) override
Writes encoded audio data to be decoded.
Definition StreamingDecoder.h:936
bool is_setup
Whether lazy setup has been performed.
Definition StreamingDecoder.h:965
bool begin() override
Starts the processing.
Definition StreamingDecoder.h:894
void resize(int size)
Resizes the internal buffer.
Definition StreamingDecoder.h:920
DecoderAdapter(StreamingDecoder &dec, int bufferSize)
Constructor.
Definition StreamingDecoder.h:864
int buffer_size
Size of the ring buffer.
Definition StreamingDecoder.h:966
StreamingDecoder * p_dec
Wrapped StreamingDecoder instance.
Definition StreamingDecoder.h:967
void setInput(Stream &in)
Sets the input stream for the wrapped decoder.
Definition StreamingDecoder.h:885
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
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 StreamingDecoders with automatic format detection.
Definition StreamingDecoder.h:333
virtual bool copy() override
Process a single read operation - to be called in the loop.
Definition StreamingDecoder.h:511
void setOutput(Print &out_stream) override
Defines the output Stream.
Definition StreamingDecoder.h:391
~MultiStreamingDecoder()
Destructor.
Definition StreamingDecoder.h:345
void addDecoder(StreamingDecoder &decoder)
Adds a decoder that will be selected by its MIME type.
Definition StreamingDecoder.h:430
void setMimeSource(MimeSource &mimeSource)
Sets an external MIME source for format detection.
Definition StreamingDecoder.h:694
const char * selectedMime()
Returns the MIME type that was detected and selected.
Definition StreamingDecoder.h:627
Stream * p_data_source
effective data source for decoder
Definition StreamingDecoder.h:732
bool selectDecoder(const char *mime)
Selects the actual decoder by MIME type.
Definition StreamingDecoder.h:540
bool is_first
Flag for first copy() call.
Definition StreamingDecoder.h:728
size_t readBytes(uint8_t *data, size_t len) override
Reads bytes from the input stream.
Definition StreamingDecoder.h:834
MimeDetector mime_detector
MIME type detection engine.
Definition StreamingDecoder.h:726
Vector< uint8_t > detection_buffer
Buffer for format detection data.
Definition StreamingDecoder.h:727
void setInput(Stream &inStream)
Stream Interface: Decode directly by taking data from the stream.
Definition StreamingDecoder.h:418
void end() override
Releases the reserved memory.
Definition StreamingDecoder.h:376
MultiStreamingDecoder()=default
Default constructor.
bool selectDecoder()
Automatically detects MIME type and selects appropriate decoder.
Definition StreamingDecoder.h:767
void addDecoder(AudioDecoder &decoder, const char *mime, int bufferSize=DEFAULT_BUFFER_SIZE)
Adds an AudioDecoder with explicit MIME type.
Definition StreamingDecoder.h:475
Vector< DecoderInfo > decoders
Collection of registered decoders.
Definition StreamingDecoder.h:723
BufferedStream buffered_stream
Buffered stream for data preservation.
Definition StreamingDecoder.h:734
void addDecoder(StreamingDecoder &decoder, const char *mime)
Adds a decoder with explicit MIME type.
Definition StreamingDecoder.h:450
const char * selected_mime
MIME type that was selected.
Definition StreamingDecoder.h:729
Vector< StreamingDecoderAdapter * > adapters
Collection of internally created adapters.
Definition StreamingDecoder.h:724
const char * mime() override
Provides the MIME type of the selected decoder.
Definition StreamingDecoder.h:614
MimeSource * p_mime_source
Optional MIME source for custom logic.
Definition StreamingDecoder.h:730
void setOutput(AudioStream &out_stream) override
Defines the output streams and register to be notified.
Definition StreamingDecoder.h:400
bool begin() override
Starts the processing.
Definition StreamingDecoder.h:361
MimeDetector & mimeDetector()
Provides access to the internal MIME detector.
Definition StreamingDecoder.h:662
void setOutput(AudioOutput &out_stream) override
Defines the output streams and register to be notified.
Definition StreamingDecoder.h:409
AudioInfo audioInfo() override
Provides the audio information from the selected decoder.
Definition StreamingDecoder.h:635
struct audio_tools::MultiStreamingDecoder::DecoderInfo actual_decoder
Currently active decoder information.
Definition NoArduino.h:62
Stream class which stores the data in a temporary queue buffer. The queue can be consumed e....
Definition BaseStream.h:311
virtual bool begin() override
Activates the output.
Definition BaseStream.h:339
Implements a typed Ringbuffer.
Definition Buffers.h:336
virtual bool resize(int len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:413
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
Definition NoArduino.h:142
Converts any AudioDecoder to a StreamingDecoder.
Definition StreamingDecoder.h:188
virtual bool copy() override
Process a single read operation - to be called in the loop.
Definition StreamingDecoder.h:262
void setOutput(Print &out_stream) override
Defines the output Stream.
Definition StreamingDecoder.h:234
size_t readBytes(uint8_t *data, size_t len) override
Reads bytes from the input stream.
Definition StreamingDecoder.h:302
void end() override
Releases the reserved memory.
Definition StreamingDecoder.h:225
AudioDecoder * p_decoder
Wrapped AudioDecoder instance.
Definition StreamingDecoder.h:291
void resize(int bufferSize)
Adjust the buffer size.
Definition StreamingDecoder.h:279
const char * mime() override
Provides the MIME type.
Definition StreamingDecoder.h:288
bool begin() override
Starts the processing.
Definition StreamingDecoder.h:213
StreamingDecoderAdapter(AudioDecoder &decoder, const char *mimeStr, int copySize=DEFAULT_BUFFER_SIZE)
Constructor.
Definition StreamingDecoder.h:198
const char * mime_str
MIME type string.
Definition StreamingDecoder.h:293
AudioInfo audioInfo() override
Provides the audio information.
Definition StreamingDecoder.h:245
Vector< uint8_t > buffer
Internal buffer for data transfer.
Definition StreamingDecoder.h:292
A Streaming Decoder where we provide both the input and output as streams.
Definition StreamingDecoder.h:29
bool copyAll()
Process all available data.
Definition StreamingDecoder.h:132
virtual bool copy()=0
Process a single read operation - to be called in the loop.
void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition StreamingDecoder.h:160
Stream * p_input
Input stream for encoded audio data.
Definition StreamingDecoder.h:169
virtual void setOutput(Print &out_stream)
Defines the output Stream.
Definition StreamingDecoder.h:58
void setInput(Stream &inStream)
Stream Interface: Decode directly by taking data from the stream.
Definition StreamingDecoder.h:94
virtual void setOutput(AudioStream &out_stream)
Defines the output streams and register to be notified.
Definition StreamingDecoder.h:67
virtual void end()=0
Releases the reserved memory.
virtual size_t readBytes(uint8_t *data, size_t len)=0
Reads bytes from the input stream.
Print * p_print
Output stream for decoded PCM data.
Definition StreamingDecoder.h:168
virtual void setOutput(AudioOutput &out_stream)
Defines the output streams and register to be notified.
Definition StreamingDecoder.h:80
virtual AudioInfo audioInfo()=0
Provides the audio information for the current stream.
virtual const char * mime()=0
Provides the MIME type of the audio format handled by this decoder.
virtual bool begin()=0
Starts the processing.
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
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
Information about a registered decoder.
Definition StreamingDecoder.h:701
bool is_open
Whether the decoder is currently active.
Definition StreamingDecoder.h:704
DecoderInfo(const char *mime, StreamingDecoder *decoder)
Constructor with parameters.
Definition StreamingDecoder.h:717
DecoderInfo()=default
Default constructor.
StreamingDecoder * decoder
Pointer to the decoder instance.
Definition StreamingDecoder.h:703
const char * mime
MIME type for this decoder.
Definition StreamingDecoder.h:702