arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Modules Pages
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
9namespace audio_tools {
10
21class MultiDecoder : public AudioDecoder {
22 public:
24 MultiDecoder() = default;
27
29 bool begin() override {
30 mime_detector.begin();
31 is_first = true;
32 if (p_print == nullptr) {
33 LOGE("No output defined");
34 return false;
35 }
36 return true;
37 }
38
40 void end() override {
41 if (actual_decoder.decoder != nullptr && actual_decoder.is_open) {
42 actual_decoder.decoder->end();
43 }
44 actual_decoder.is_open = false;
45 actual_decoder.decoder = nullptr;
46 actual_decoder.mime = nullptr;
47 is_first = true;
48 }
49
51 void addDecoder(AudioDecoder& decoder, const char* mime) {
52 DecoderInfo info{mime, &decoder};
53 decoder.addNotifyAudioChange(*this);
54 decoders.push_back(info);
55 }
56
59 void addDecoder(AudioDecoder& decoder, const char* mime,
60 bool (*check)(uint8_t* data, size_t len)) {
61 addDecoder(decoder, mime);
62 mime_detector.setCheck(mime, check);
63 }
64
65 void setOutput(Print& out_stream) override {
66 p_print = &out_stream;
67 }
68
71 void setMimeSource(AbstractURLStream& url) { p_url_stream = &url; }
72
75 bool selectDecoder(const char* mime) {
76 bool result = false;
77 if (mime == nullptr) return false;
78 // do nothing if no change
79 if (StrView(mime).equals(actual_decoder.mime)) {
80 is_first = false;
81 return true;
82 }
83 // close actual decoder
84 if (actual_decoder.decoder != this) end();
85
86 // find the corresponding decoder
87 selected_mime = nullptr;
88 for (int j = 0; j < decoders.size(); j++) {
89 DecoderInfo info = decoders[j];
90 if (StrView(info.mime).equals(mime)) {
91 LOGI("Using decoder for %s (%s)", info.mime, mime);
92 actual_decoder = info;
93 // define output if it has not been defined
94 if (p_print != nullptr && actual_decoder.decoder != this
95 && actual_decoder.decoder->getOutput() == nullptr) {
96 actual_decoder.decoder->setOutput(*p_print);
97 }
98 if (!*actual_decoder.decoder) {
99 actual_decoder.decoder->begin();
100 LOGI("Decoder %s started", actual_decoder.mime);
101 }
102 result = true;
103 selected_mime = mime;
104 break;
105 }
106 }
107 is_first = false;
108 return result;
109 }
110
111 const char* selectedMime() { return selected_mime; }
112
113 size_t write(const uint8_t* data, size_t len) override {
114 if (is_first) {
115 const char* mime = nullptr;
116 if (p_url_stream != nullptr) {
117 // get content type from http header
118 mime = p_url_stream->getReplyHeader(CONTENT_TYPE);
119 if (mime) LOGI("mime from http request: %s", mime);
120 }
121 if (mime == nullptr) {
122 // use the mime detector
123 mime_detector.write((uint8_t*)data, len);
124 mime = mime_detector.mime();
125 if (mime) LOGI("mime from mime_detector: %s", mime);
126 }
127 if (mime != nullptr) {
128 // select the decoder based on the detemined mime type
129 if (!selectDecoder(mime)) {
130 LOGE("The decoder could not be found for %s", mime);
131 actual_decoder.decoder = &nop;
132 actual_decoder.is_open = true;
133 }
134 }
135 is_first = false;
136 }
137 // check if we have a decoder
138 if (actual_decoder.decoder == nullptr) return 0;
139 // decode the data
140 return actual_decoder.decoder->write(data, len);
141 }
142
143 virtual operator bool() override {
144 if (actual_decoder.decoder == &nop) return false;
145 return is_first || actual_decoder.is_open;
146 };
147
149 bool setCodecConfig(const uint8_t* data, size_t len) override {
150 if (actual_decoder.decoder == nullptr) {
151 LOGE("No decoder defined, cannot set codec config");
152 return false;
153 }
154 return actual_decoder.decoder->setCodecConfig(data, len);
155 }
156
157 protected:
158 struct DecoderInfo {
159 const char* mime = nullptr;
160 AudioDecoder* decoder = nullptr;
161 bool is_open = false;
162 DecoderInfo() = default;
163 DecoderInfo(const char* mime, AudioDecoder* decoder) {
164 this->mime = mime;
165 this->decoder = decoder;
166 }
167 } actual_decoder;
168 Vector<DecoderInfo> decoders{0};
169 MimeDetector mime_detector;
170 CodecNOP nop;
171 AbstractURLStream* p_url_stream = nullptr;
172 bool is_first = true;
173 const char* selected_mime = nullptr;
174};
175
176} // namespace audio_tools
Abstract Base class for all URLStream implementations.
Definition AbstractURLStream.h:17
virtual const char * getReplyHeader(const char *header)=0
Provides reply header information.
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
Logic to detemine the mime type from the content. By default the following mime types are supported (...
Definition MimeDetector.h:23
void setCheck(const char *mime, bool(*check)(uint8_t *start, size_t len))
adds/updates the checking logic for the indicated mime
Definition MimeDetector.h:48
size_t write(uint8_t *data, size_t len)
write the header to determine the mime
Definition MimeDetector.h:41
const char * mime()
Definition MimeDetector.h:69
Manage multiple decoders: the actual decoder is only opened when it has been selected....
Definition MultiDecoder.h:21
void setOutput(Print &out_stream) override
Defines where the decoded result is written to.
Definition MultiDecoder.h:65
MultiDecoder()=default
Default constructor.
bool setCodecConfig(const uint8_t *data, size_t len) override
Sets the config to the selected decoder.
Definition MultiDecoder.h:149
bool selectDecoder(const char *mime)
Definition MultiDecoder.h:75
void addDecoder(AudioDecoder &decoder, const char *mime, bool(*check)(uint8_t *data, size_t len))
Definition MultiDecoder.h:59
void setMimeSource(AbstractURLStream &url)
Definition MultiDecoder.h:71
void end() override
closes the actual decoder
Definition MultiDecoder.h:40
void addDecoder(AudioDecoder &decoder, const char *mime)
Adds a decoder that will be selected by it's mime type.
Definition MultiDecoder.h:51
MultiDecoder(AbstractURLStream &url)
Provides a URLStream to look up the mime type from the http reply header.
Definition MultiDecoder.h:26
bool begin() override
Enables the automatic mime type determination.
Definition MultiDecoder.h:29
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
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
Definition MultiDecoder.h:158