arduino-audio-tools
Loading...
Searching...
No Matches
StreamingDecoder.h
Go to the documentation of this file.
1#pragma once
2#include <new>
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;
165 }
166 }
167
168 Print* p_print = nullptr;
169 Stream* p_input = nullptr;
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 bool resize(size_t bufferSize) {
280 return buffer.resize(bufferSize); }
281
289 const char* mime() override { return mime_str; }
290
291 protected:
294 const char* mime_str = nullptr;
295
303 size_t readBytes(uint8_t* data, size_t len) override {
304 if (p_input == nullptr) return 0;
305 return p_input->readBytes(data, len);
306 }
307};
308
335 public:
340
347 // Clean up any adapters we created
348 for (auto* adapter : adapters) {
349 delete adapter;
350 }
351 adapters.clear();
352 }
353
362 bool begin() override {
364 is_first = true;
365 if (p_print == nullptr) {
366 LOGE("No output defined");
367 return false;
368 }
369 return true;
370 }
371
377 void end() override {
378 if (actual_decoder.decoder != nullptr && actual_decoder.is_open) {
380 }
381 actual_decoder.is_open = false;
382 actual_decoder.decoder = nullptr;
383 actual_decoder.mime = nullptr;
384 is_first = true;
385 }
386
392 void setOutput(Print& out_stream) override {
393 StreamingDecoder::setOutput(out_stream);
394 }
395
401 void setOutput(AudioStream& out_stream) override {
402 StreamingDecoder::setOutput(out_stream);
403 }
404
410 void setOutput(AudioOutput& out_stream) override {
411 StreamingDecoder::setOutput(out_stream);
412 }
413
419 void setInput(Stream& inStream) {
421 }
422
432 decoder.addNotifyAudioChange(*this);
433 const char* mime = decoder.mime();
434 if (mime != nullptr) {
435 DecoderInfo info{mime, &decoder};
436 decoders.push_back(info);
437 } else {
438 LOGE("Decoder mime() returned nullptr - cannot add decoder");
439 }
440 }
441
451 void addDecoder(StreamingDecoder& decoder, const char* mime) {
452 if (mime != nullptr) {
453 decoder.addNotifyAudioChange(*this);
454 DecoderInfo info{mime, &decoder};
455 decoders.push_back(info);
456 } else {
457 LOGE("Decoder mime() returned nullptr - cannot add decoder");
458 }
459 }
460
476 void addDecoder(AudioDecoder& decoder, const char* mime,
477 int bufferSize = DEFAULT_BUFFER_SIZE) {
478 if (mime != nullptr) {
479 // Create a StreamingDecoderAdapter to wrap the AudioDecoder
480 decoder.addNotifyAudioChange(*this);
481 auto adapter = new StreamingDecoderAdapter(decoder, mime, bufferSize);
482 adapters.push_back(adapter); // Store for cleanup
483
484 DecoderInfo info{mime, adapter};
485 decoders.push_back(info);
486 } else {
487 LOGE("MIME type is nullptr - cannot add AudioDecoder");
488 }
489 }
490
497 virtual operator bool() override {
498 if (actual_decoder.decoder == nullptr) return false;
500 }
501
512 virtual bool copy() override {
513 if (p_input == nullptr) return false;
514
515 // Automatically select decoder if not already selected
516 if (is_first) {
517 // determine the mime and select the decoder
518 if (!selectDecoder()) {
519 return false;
520 }
521 is_first = false;
522 }
523
524 // Check if we have a decoder
525 if (actual_decoder.decoder == nullptr) return false;
526
527 // Use the selected decoder to process data
528 return actual_decoder.decoder->copy();
529 }
530
541 bool selectDecoder(const char* mime) {
542 TRACEI();
543 bool result = false;
544
545 // Guard against null MIME type - cannot proceed without valid MIME
546 if (mime == nullptr) {
547 LOGE("mime is null");
548 return false;
549 }
550
551 // Optimization: Check if the requested MIME type is already active
552 // This avoids unnecessary decoder switching when the same format is detected
553 if (StrView(mime).equals(actual_decoder.mime)) {
554 is_first = false; // Mark initialization as complete
555 return true; // Already using the correct decoder
556 }
557
558 // Clean shutdown of currently active decoder before switching
559 // This ensures proper resource cleanup and state reset
560 if (actual_decoder.decoder != nullptr) {
562 actual_decoder.is_open = false; // Mark as inactive
563 }
564
565 // Search through all registered decoders to find one that handles this MIME type
566 selected_mime = nullptr; // Clear previous selection
567 for (int j = 0; j < decoders.size(); j++) {
569
570 // Check if this decoder supports the detected MIME type
571 if (StrView(info.mime).equals(mime)) {
572 LOGI("Using Decoder %s for %s", toStr(info.mime), toStr(mime));
573
574 // Switch to the matching decoder
576
577 // Configure the decoder's output stream to match our output
578 // This ensures decoded audio data flows to the correct destination
579 if (p_print != nullptr) {
581 }
582
583 // Initialize the selected decoder and mark it as active
584 LOGI("available: %d", p_data_source->available());
585 assert(p_data_source != nullptr);
590 actual_decoder.is_open = true;
591 LOGI("StreamingDecoder %s started", toStr(actual_decoder.mime));
592 } else {
593 // Decoder failed to start - this is a critical error
594 LOGE("Failed to start StreamingDecoder %s", toStr(actual_decoder.mime));
595 return false;
596 }
597
598 // Successfully found and initialized a decoder
599 result = true;
600 selected_mime = mime; // Store the MIME type that was selected
601 break; // Stop searching once we find a match
602 }
603 }
604
605 // Mark initialization phase as complete regardless of success/failure
606 is_first = false;
607 return result; // true if decoder was found and started, false otherwise
608 }
609
615 const char* mime() override {
616 // fallback to actual decoder
617 if (actual_decoder.decoder != nullptr) {
618 return actual_decoder.decoder->mime();
619 }
620 return nullptr;
621 }
622
628 const char* selectedMime() { return selected_mime; }
629
636 AudioInfo audioInfo() override {
637 if (actual_decoder.decoder != nullptr) {
639 }
640 AudioInfo empty;
641 return empty;
642 }
643
664
695 void setMimeSource(MimeSource& mimeSource) { p_mime_source = &mimeSource; }
696
697 protected:
698
702 struct DecoderInfo {
703 const char* mime = nullptr;
705 bool is_open = false;
706
710 DecoderInfo() = default;
711
719 this->mime = mime;
720 this->decoder = decoder;
721 }
723
729 bool is_first = true;
730 const char* selected_mime = nullptr;
732 nullptr;
734
736 const char* toStr(const char* str){
737 return str == nullptr ? "" : str;
738 }
739
769 // Only perform MIME detection and decoder selection if no decoder is active yet
770 // This prevents re-detection on subsequent calls during the same stream
771 if (actual_decoder.decoder == nullptr) {
772 const char* mime = nullptr;
773 p_data_source = nullptr;
774
775 // Two methods for MIME type determination: external source or auto-detection
776 if (p_mime_source != nullptr) {
777 // Option 1: Use externally provided MIME source (e.g., from HTTP headers)
778 // This is more efficient as it avoids reading and analyzing stream data
780 LOGI("mime from source: %s", toStr(mime));
781 assert(p_input != nullptr);
783 } else {
784 // Option 2: Auto-detect MIME type by analyzing stream content
785 // Redirect the decoder to use the buffered stream
786 // we use the buffered stream as input
787 assert(p_input != nullptr);
791
792 // This requires reading a sample of data to identify the format
794 size_t bytesRead = buffered_stream.peekBytes(detection_buffer.data(), detection_buffer.size()); // If no data is available, we cannot proceed with detection
795 if (bytesRead == 0) return false;
796
797 // Feed the sample data to the MIME detector for format analysis
798 // The detector examines file headers, magic numbers, etc.
801 LOGI("mime from detector: %s", toStr(mime));
802
803 }
804
805 // Process the detected/provided MIME type
806 if (mime != nullptr) {
807 // Delegate to the overloaded selectDecoder(mime) method to find
808 // and initialize the appropriate decoder for this MIME type
809 if (!selectDecoder(mime)) {
810 LOGE("The decoder could not be selected for %s", toStr(mime));
811 return false; // No registered decoder can handle this format
812 }
813 } else {
814 // MIME detection failed - format is unknown or unsupported
815 LOGE("Could not determine mime type");
816 return false;
817 }
818 } else {
819 LOGI("Decoder already selected: %s", toStr(actual_decoder.mime));
820 assert(p_input != nullptr);
822 }
823
824 // Success: either decoder was already selected or selection completed successfully
825 return true;
826 }
827
835 size_t readBytes(uint8_t* data, size_t len) override {
836 if (p_input == nullptr) return 0;
837 return p_input->readBytes(data, len);
838 }
839};
840
858 public:
865 DecoderAdapter(StreamingDecoder& dec, int bufferSize) {
866 TRACED();
867 p_dec = &dec;
869 resize(bufferSize);
870 }
871
879 void setOutput(Print& out) override { p_dec->setOutput(out); }
880
886 void setInput(Stream& in) { p_dec->setInput(in); }
887
895 bool begin() override {
896 TRACED();
897 active = true;
898 bool rc = p_dec->begin();
899 return rc;
900 }
901
908 void end() override {
909 TRACED();
910 active = false;
911 }
912
921 bool resize(size_t size) {
922 buffer_size = size;
923 // setup the buffer only if needed
924 if (is_setup) return rbuffer.resize(size);
925 return true;
926 }
927
938 size_t write(const uint8_t* data, size_t len) override {
939 TRACED();
940 setupLazy();
941 size_t result = queue.write((uint8_t*)data, len);
942 // Trigger processing - process all available data
943 while (p_dec->copy());
944
945 return result;
946 }
947
957
963 operator bool() override { return active; }
964
965 protected:
966 bool active = false;
967 bool is_setup = false;
972
978 void setupLazy() {
979 if (!is_setup) {
981 queue.begin();
982 is_setup = true;
983 }
984 }
985};
986
993
994} // namespace audio_tools
#define TRACEI()
Definition AudioLoggerIDF.h:32
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define DEFAULT_BUFFER_SIZE
Definition avr.h:20
#define assert(T)
Definition avr.h:10
Definition Arduino.h:56
Definition Arduino.h:136
virtual size_t readBytes(uint8_t *data, size_t len)
Definition Arduino.h:140
virtual int available()
Definition Arduino.h:139
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
virtual bool begin(AudioInfo info) override
Definition AudioCodecsBase.h:54
void end() override
Definition AudioCodecsBase.h:59
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:146
void notifyAudioChange(AudioInfo info)
Definition AudioTypes.h:174
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:149
virtual void clearNotifyAudioChange()
Deletes all change notify subscriptions.
Definition AudioTypes.h:162
Supports changes to the sampling rate, bits and channels.
Definition AudioTypes.h:131
Abstract Audio Ouptut class.
Definition AudioOutput.h:25
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:120
virtual size_t write(const uint8_t *data, size_t len)=0
The Arduino Stream supports operations on single characters. This is usually not the best way to push...
Definition AudioStreams.h:569
void setStream(Print &out)
Definition AudioStreams.h:601
size_t peekBytes(uint8_t *data, size_t len)
Provides data w/o consuming.
Definition AudioStreams.h:665
void resize(int size)
Resize the buffer.
Definition AudioStreams.h:682
Adapter class which allows the AudioDecoder API on a StreamingDecoder.
Definition StreamingDecoder.h:857
RingBuffer< uint8_t > rbuffer
Ring buffer for data storage.
Definition StreamingDecoder.h:970
bool active
Whether the adapter is active.
Definition StreamingDecoder.h:966
void setOutput(Print &out) override
Defines the output Stream.
Definition StreamingDecoder.h:879
QueueStream< uint8_t > queue
Stream interface to the ring buffer.
Definition StreamingDecoder.h:971
StreamingDecoder * getStreamingDecoder()
Gets the wrapped StreamingDecoder.
Definition StreamingDecoder.h:956
void setupLazy()
Performs lazy initialization of the ring buffer.
Definition StreamingDecoder.h:978
void end() override
Stops the processing.
Definition StreamingDecoder.h:908
size_t write(const uint8_t *data, size_t len) override
Writes encoded audio data to be decoded.
Definition StreamingDecoder.h:938
bool is_setup
Whether lazy setup has been performed.
Definition StreamingDecoder.h:967
bool begin() override
Starts the processing.
Definition StreamingDecoder.h:895
DecoderAdapter(StreamingDecoder &dec, int bufferSize)
Constructor.
Definition StreamingDecoder.h:865
bool resize(size_t size)
Resizes the internal buffer.
Definition StreamingDecoder.h:921
int buffer_size
Size of the ring buffer.
Definition StreamingDecoder.h:968
StreamingDecoder * p_dec
Wrapped StreamingDecoder instance.
Definition StreamingDecoder.h:969
void setInput(Stream &in)
Sets the input stream for the wrapped decoder.
Definition StreamingDecoder.h:886
Logic to detemine the mime type from the content. By default the following mime types are supported (...
Definition MimeDetector.h:62
bool begin()
Sets is_first to true.
Definition MimeDetector.h:83
size_t write(uint8_t *data, size_t len)
write the header to determine the mime
Definition MimeDetector.h:95
const char * mime()
Definition MimeDetector.h:127
Abstract interface for classes that can provide MIME type information.
Definition MimeDetector.h:29
virtual const char * mime()=0
Get the MIME type string.
Manage multiple StreamingDecoders with automatic format detection.
Definition StreamingDecoder.h:334
virtual bool copy() override
Process a single read operation - to be called in the loop.
Definition StreamingDecoder.h:512
void setOutput(Print &out_stream) override
Defines the output Stream.
Definition StreamingDecoder.h:392
~MultiStreamingDecoder()
Destructor.
Definition StreamingDecoder.h:346
void addDecoder(StreamingDecoder &decoder)
Adds a decoder that will be selected by its MIME type.
Definition StreamingDecoder.h:431
void setMimeSource(MimeSource &mimeSource)
Sets an external MIME source for format detection.
Definition StreamingDecoder.h:695
const char * selectedMime()
Returns the MIME type that was detected and selected.
Definition StreamingDecoder.h:628
Stream * p_data_source
effective data source for decoder
Definition StreamingDecoder.h:733
bool selectDecoder(const char *mime)
Selects the actual decoder by MIME type.
Definition StreamingDecoder.h:541
bool is_first
Flag for first copy() call.
Definition StreamingDecoder.h:729
size_t readBytes(uint8_t *data, size_t len) override
Reads bytes from the input stream.
Definition StreamingDecoder.h:835
MimeDetector mime_detector
MIME type detection engine.
Definition StreamingDecoder.h:727
Vector< uint8_t > detection_buffer
Buffer for format detection data.
Definition StreamingDecoder.h:728
void setInput(Stream &inStream)
Stream Interface: Decode directly by taking data from the stream.
Definition StreamingDecoder.h:419
void end() override
Releases the reserved memory.
Definition StreamingDecoder.h:377
MultiStreamingDecoder()=default
Default constructor.
bool selectDecoder()
Automatically detects MIME type and selects appropriate decoder.
Definition StreamingDecoder.h:768
void addDecoder(AudioDecoder &decoder, const char *mime, int bufferSize=DEFAULT_BUFFER_SIZE)
Adds an AudioDecoder with explicit MIME type.
Definition StreamingDecoder.h:476
Vector< DecoderInfo > decoders
Collection of registered decoders.
Definition StreamingDecoder.h:724
BufferedStream buffered_stream
Buffered stream for data preservation.
Definition StreamingDecoder.h:735
void addDecoder(StreamingDecoder &decoder, const char *mime)
Adds a decoder with explicit MIME type.
Definition StreamingDecoder.h:451
const char * selected_mime
MIME type that was selected.
Definition StreamingDecoder.h:730
Vector< StreamingDecoderAdapter * > adapters
Collection of internally created adapters.
Definition StreamingDecoder.h:725
const char * mime() override
Provides the MIME type of the selected decoder.
Definition StreamingDecoder.h:615
MimeSource * p_mime_source
Optional MIME source for custom logic.
Definition StreamingDecoder.h:731
void setOutput(AudioStream &out_stream) override
Defines the output streams and register to be notified.
Definition StreamingDecoder.h:401
bool begin() override
Starts the processing.
Definition StreamingDecoder.h:362
MimeDetector & mimeDetector()
Provides access to the internal MIME detector.
Definition StreamingDecoder.h:663
void setOutput(AudioOutput &out_stream) override
Defines the output streams and register to be notified.
Definition StreamingDecoder.h:410
AudioInfo audioInfo() override
Provides the audio information from the selected decoder.
Definition StreamingDecoder.h:636
struct audio_tools::MultiStreamingDecoder::DecoderInfo actual_decoder
Currently active decoder information.
const char * toStr(const char *str)
Definition StreamingDecoder.h:736
Stream class which stores the data in a temporary queue buffer. The queue can be consumed e....
Definition BaseStream.h:359
virtual size_t write(const uint8_t *data, size_t len) override
Definition BaseStream.h:420
virtual bool begin() override
Activates the output.
Definition BaseStream.h:387
Implements a typed Ringbuffer.
Definition Buffers.h:353
virtual bool resize(size_t len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:430
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
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:303
void end() override
Releases the reserved memory.
Definition StreamingDecoder.h:225
AudioDecoder * p_decoder
Wrapped AudioDecoder instance.
Definition StreamingDecoder.h:292
const char * mime() override
Provides the MIME type.
Definition StreamingDecoder.h:289
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:294
bool resize(size_t bufferSize)
Adjust the buffer size.
Definition StreamingDecoder.h:279
AudioInfo audioInfo() override
Provides the audio information.
Definition StreamingDecoder.h:245
Vector< uint8_t > buffer
Internal buffer for data transfer.
Definition StreamingDecoder.h:293
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
AudioInfo info
Definition StreamingDecoder.h:170
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 ~StreamingDecoder()=default
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
bool resize(size_t newSize, T value)
Definition Vector.h:266
T * data()
Definition Vector.h:316
int size()
Definition Vector.h:178
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:51
Information about a registered decoder.
Definition StreamingDecoder.h:702
bool is_open
Whether the decoder is currently active.
Definition StreamingDecoder.h:705
DecoderInfo(const char *mime, StreamingDecoder *decoder)
Constructor with parameters.
Definition StreamingDecoder.h:718
DecoderInfo()=default
Default constructor.
StreamingDecoder * decoder
Pointer to the decoder instance.
Definition StreamingDecoder.h:704
const char * mime
MIME type for this decoder.
Definition StreamingDecoder.h:703