Skip to content

Commit 9703ef4

Browse files
committed
MultiDecoder comments
1 parent 610d6e7 commit 9703ef4

File tree

1 file changed

+168
-26
lines changed

1 file changed

+168
-26
lines changed

src/AudioTools/AudioCodecs/MultiDecoder.h

Lines changed: 168 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,61 @@
99
namespace audio_tools {
1010

1111
/**
12-
* @brief Manage multiple decoders: the actual decoder is only opened when it
13-
* has been selected. The relevant decoder is determined dynamically at the
14-
* first write from the determined mime type. You can add your own custom mime
15-
* type determination logic.
12+
* @brief Manage multiple AudioDecoders with automatic format detection
13+
*
14+
* This class automatically detects the audio format from incoming data and
15+
* selects the appropriate decoder from a collection of registered decoders.
16+
* The format detection is performed using the MimeDetector on the first chunk
17+
* of data written to the decoder.
18+
*
19+
* Key features:
20+
* - Automatic format detection using MimeDetector
21+
* - Support for multiple decoder registration
22+
* - Custom MIME type detection logic support
23+
* - External MIME source integration (e.g., HTTP headers)
24+
* - Lazy decoder initialization for memory efficiency
25+
* - Seamless integration with existing AudioDecoder architecture
26+
*
27+
* The actual decoder is only opened when it has been selected, which allows
28+
* for memory-efficient operation when dealing with multiple possible formats.
29+
* The relevant decoder is determined dynamically at the first write() call
30+
* based on the determined MIME type.
31+
*
32+
* @note This class uses a write-based interface, unlike StreamingDecoder
33+
* which uses a pull-based approach. For streaming scenarios with direct
34+
* access to input/output streams, consider using MultiStreamingDecoder.
35+
*
1636
* @ingroup codecs
1737
* @ingroup decoder
1838
* @author Phil Schatzmann
1939
* @copyright GPLv3
2040
*/
2141
class MultiDecoder : public AudioDecoder {
2242
public:
23-
/// Default constructor
43+
/**
44+
* @brief Default constructor
45+
*/
2446
MultiDecoder() = default;
25-
/// Provides a URLStream to look up the mime type from the http reply header
47+
48+
/**
49+
* @brief Constructor with external MIME source
50+
*
51+
* Creates a MultiDecoder that uses an external source for MIME type
52+
* determination, such as HTTP Content-Type headers. This can be more
53+
* efficient than automatic detection as it avoids analyzing data content.
54+
*
55+
* @param mimeSource Reference to a MimeSource that provides MIME type information
56+
*/
2657
MultiDecoder(MimeSource& mimeSource) { setMimeSource(mimeSource); }
2758

28-
/// Enables the automatic mime type determination
59+
/**
60+
* @brief Starts the processing and enables automatic MIME type determination
61+
*
62+
* Initializes the MIME detector and prepares the MultiDecoder for format
63+
* detection. This method must be called before any write() operations.
64+
*
65+
* @return true if initialization was successful, false if no output is defined
66+
*/
2967
bool begin() override {
3068
mime_detector.begin();
3169
is_first = true;
@@ -36,7 +74,13 @@ class MultiDecoder : public AudioDecoder {
3674
return true;
3775
}
3876

39-
/// closes the actual decoder
77+
/**
78+
* @brief Releases resources and closes the active decoder
79+
*
80+
* Stops the currently active decoder and resets the MultiDecoder state
81+
* for potential reuse. After calling end(), begin() must be called again
82+
* before the decoder can process new data.
83+
*/
4084
void end() override {
4185
if (actual_decoder.decoder != nullptr && actual_decoder.is_open) {
4286
actual_decoder.decoder->end();
@@ -47,31 +91,79 @@ class MultiDecoder : public AudioDecoder {
4791
is_first = true;
4892
}
4993

50-
/// Adds a decoder that will be selected by it's mime type
94+
/**
95+
* @brief Adds a decoder that will be selected by its MIME type
96+
*
97+
* Registers an AudioDecoder that will be automatically selected when
98+
* the corresponding MIME type is detected in the input data.
99+
*
100+
* @param decoder The AudioDecoder to register
101+
* @param mime The MIME type string to associate with this decoder
102+
*/
51103
void addDecoder(AudioDecoder& decoder, const char* mime) {
52104
DecoderInfo info{mime, &decoder};
53105
decoder.addNotifyAudioChange(*this);
54106
decoders.push_back(info);
55107
}
56108

57-
/// Adds a decoder that will be selected by it's mime type and defines the
58-
/// mime checking logic
109+
/**
110+
* @brief Adds a decoder with custom MIME detection logic
111+
*
112+
* Registers an AudioDecoder with a specific MIME type and provides custom
113+
* logic for detecting that MIME type from raw data. This allows for
114+
* specialized format detection beyond the standard MimeDetector capabilities.
115+
*
116+
* @param decoder The AudioDecoder to register
117+
* @param mime The MIME type string to associate with this decoder
118+
* @param check Custom function that analyzes data to detect this MIME type.
119+
* Should return true if the data matches this format.
120+
*/
59121
void addDecoder(AudioDecoder& decoder, const char* mime,
60122
bool (*check)(uint8_t* data, size_t len)) {
61123
addDecoder(decoder, mime);
62124
mime_detector.setCheck(mime, check);
63125
}
64126

127+
/**
128+
* @brief Sets the output stream for decoded audio data
129+
*
130+
* Defines where the decoded PCM audio data will be written to.
131+
* This output will be automatically configured for the selected decoder.
132+
*
133+
* @param out_stream The Print stream to write decoded audio data to
134+
*/
65135
void setOutput(Print& out_stream) override {
66136
p_print = &out_stream;
67137
}
68138

69-
/// Defines url stream from which we determine the mime type from the reply
70-
/// header
139+
/**
140+
* @brief Sets an external MIME source for format detection
141+
*
142+
* Provides an alternative to automatic MIME detection by allowing an external
143+
* source to provide the MIME type information. This is particularly useful
144+
* when the MIME type is available from HTTP headers or other metadata sources.
145+
*
146+
* When a MIME source is set, it takes precedence over automatic detection,
147+
* making the decoder selection process more efficient.
148+
*
149+
* @param mimeSource Reference to a MimeSource that provides MIME type information
150+
*
151+
* @note The MimeSource object must remain valid for the lifetime of this
152+
* MultiDecoder instance, as only a reference is stored.
153+
*/
71154
void setMimeSource(MimeSource& mimeSource) { p_mime_source = &mimeSource; }
72155

73-
/// selects the actual decoder by mime type - this is usually called
74-
/// automatically from the determined mime type
156+
/**
157+
* @brief Selects the actual decoder by MIME type
158+
*
159+
* Searches through registered decoders to find one that matches the
160+
* specified MIME type, then initializes it for use. This method is
161+
* usually called automatically from the determined MIME type during
162+
* the first write() operation.
163+
*
164+
* @param mime The MIME type string to match against registered decoders
165+
* @return true if a matching decoder was found and initialized, false otherwise
166+
*/
75167
bool selectDecoder(const char* mime) {
76168
bool result = false;
77169
if (mime == nullptr) return false;
@@ -108,8 +200,28 @@ class MultiDecoder : public AudioDecoder {
108200
return result;
109201
}
110202

203+
/**
204+
* @brief Returns the MIME type that was detected and selected
205+
*
206+
* @return The MIME type string that was detected and used to select
207+
* the current decoder, or nullptr if no decoder has been selected
208+
*/
111209
const char* selectedMime() { return selected_mime; }
112210

211+
/**
212+
* @brief Writes encoded audio data to be decoded
213+
*
214+
* On the first call, this method performs MIME type detection to select
215+
* the appropriate decoder. Subsequent calls delegate to the selected
216+
* decoder's write() method to process the audio data.
217+
*
218+
* The MIME detection process uses either an external MIME source (if set)
219+
* or analyzes the provided data to determine the audio format.
220+
*
221+
* @param data Buffer containing encoded audio data
222+
* @param len Number of bytes to write
223+
* @return Number of bytes actually written to the selected decoder
224+
*/
113225
size_t write(const uint8_t* data, size_t len) override {
114226
if (is_first) {
115227
const char* mime = nullptr;
@@ -140,12 +252,27 @@ class MultiDecoder : public AudioDecoder {
140252
return actual_decoder.decoder->write(data, len);
141253
}
142254

255+
/**
256+
* @brief Checks if the decoder is active and ready
257+
*
258+
* @return true if a decoder is selected and active, or if format detection
259+
* hasn't been performed yet; false if no suitable decoder was found
260+
*/
143261
virtual operator bool() override {
144262
if (actual_decoder.decoder == &nop) return false;
145263
return is_first || actual_decoder.is_open;
146264
};
147265

148-
/// Sets the config to the selected decoder
266+
/**
267+
* @brief Sets codec-specific configuration data
268+
*
269+
* Forwards codec configuration data to the currently selected decoder.
270+
* This method can only be called after a decoder has been selected.
271+
*
272+
* @param data Buffer containing codec configuration data
273+
* @param len Length of the configuration data
274+
* @return true if the configuration was successfully applied, false otherwise
275+
*/
149276
bool setCodecConfig(const uint8_t* data, size_t len) override {
150277
if (actual_decoder.decoder == nullptr) {
151278
LOGE("No decoder defined, cannot set codec config");
@@ -155,22 +282,37 @@ class MultiDecoder : public AudioDecoder {
155282
}
156283

157284
protected:
285+
/**
286+
* @brief Information about a registered decoder
287+
*/
158288
struct DecoderInfo {
159-
const char* mime = nullptr;
160-
AudioDecoder* decoder = nullptr;
161-
bool is_open = false;
289+
const char* mime = nullptr; ///< MIME type for this decoder
290+
AudioDecoder* decoder = nullptr; ///< Pointer to the decoder instance
291+
bool is_open = false; ///< Whether the decoder is currently active
292+
293+
/**
294+
* @brief Default constructor
295+
*/
162296
DecoderInfo() = default;
297+
298+
/**
299+
* @brief Constructor with parameters
300+
*
301+
* @param mime MIME type string
302+
* @param decoder Pointer to AudioDecoder instance
303+
*/
163304
DecoderInfo(const char* mime, AudioDecoder* decoder) {
164305
this->mime = mime;
165306
this->decoder = decoder;
166307
}
167-
} actual_decoder;
168-
Vector<DecoderInfo> decoders{0};
169-
MimeDetector mime_detector;
170-
CodecNOP nop;
171-
MimeSource* p_mime_source = nullptr;
172-
bool is_first = true;
173-
const char* selected_mime = nullptr;
308+
} actual_decoder; ///< Currently active decoder information
309+
310+
Vector<DecoderInfo> decoders{0}; ///< Collection of registered decoders
311+
MimeDetector mime_detector; ///< MIME type detection engine
312+
CodecNOP nop; ///< No-operation codec for unsupported formats
313+
MimeSource* p_mime_source = nullptr; ///< Optional external MIME source
314+
bool is_first = true; ///< Flag for first write() call
315+
const char* selected_mime = nullptr; ///< MIME type that was selected
174316
};
175317

176318
} // namespace audio_tools

0 commit comments

Comments
 (0)