[audio][media_player][speaker] WAV decoding is no longer always built (#16244)

This commit is contained in:
Kevin Ahrendt
2026-05-04 23:45:11 +00:00
committed by GitHub
parent d28498ac2c
commit f33d137669
10 changed files with 42 additions and 8 deletions
+3 -2
View File
@@ -64,8 +64,7 @@ class AudioData:
flac_support: bool = False
mp3_support: bool = False
opus_support: bool = False
# WAV defaults to True for backward compatibility; will become opt-in in a future release
wav_support: bool = True
wav_support: bool = False
micro_decoder_support: bool = False
flac: FlacOptions = field(default_factory=FlacOptions)
mp3: Mp3Options = field(default_factory=Mp3Options)
@@ -428,3 +427,5 @@ async def to_code(config):
add_idf_sdkconfig_option(
"CONFIG_OPUS_PSEUDOSTACK_SIZE", data.opus.pseudostack.size
)
if data.wav_support:
cg.add_define("USE_AUDIO_WAV_SUPPORT")
+6
View File
@@ -55,8 +55,10 @@ const char *audio_file_type_to_string(AudioFileType file_type) {
case AudioFileType::OPUS:
return "OPUS";
#endif
#ifdef USE_AUDIO_WAV_SUPPORT
case AudioFileType::WAV:
return "WAV";
#endif
default:
return "unknown";
}
@@ -71,9 +73,11 @@ AudioFileType detect_audio_file_type(const char *content_type, const char *url)
return AudioFileType::MP3;
}
#endif
#ifdef USE_AUDIO_WAV_SUPPORT
if (strcasecmp(content_type, "audio/wav") == 0) {
return AudioFileType::WAV;
}
#endif
#ifdef USE_AUDIO_FLAC_SUPPORT
if (strcasecmp(content_type, "audio/flac") == 0 || strcasecmp(content_type, "audio/x-flac") == 0) {
return AudioFileType::FLAC;
@@ -91,9 +95,11 @@ AudioFileType detect_audio_file_type(const char *content_type, const char *url)
// Fallback to URL extension
if (url != nullptr && url[0] != '\0') {
#ifdef USE_AUDIO_WAV_SUPPORT
if (str_endswith_ignore_case(url, ".wav")) {
return AudioFileType::WAV;
}
#endif
#ifdef USE_AUDIO_MP3_SUPPORT
if (str_endswith_ignore_case(url, ".mp3")) {
return AudioFileType::MP3;
+2
View File
@@ -116,7 +116,9 @@ enum class AudioFileType : uint8_t {
#ifdef USE_AUDIO_OPUS_SUPPORT
OPUS,
#endif
#ifdef USE_AUDIO_WAV_SUPPORT
WAV,
#endif
};
struct AudioFile {
@@ -98,6 +98,7 @@ esp_err_t AudioDecoder::start(AudioFileType audio_file_type) {
this->decoder_buffers_internally_ = true;
break;
#endif
#ifdef USE_AUDIO_WAV_SUPPORT
case AudioFileType::WAV:
this->wav_decoder_ = make_unique<esp_audio_libs::wav_decoder::WAVDecoder>();
this->wav_decoder_->reset();
@@ -109,6 +110,7 @@ esp_err_t AudioDecoder::start(AudioFileType audio_file_type) {
this->output_transfer_buffer_->reallocate(this->free_buffer_required_);
}
break;
#endif
case AudioFileType::NONE:
default:
return ESP_ERR_NOT_SUPPORTED;
@@ -226,9 +228,11 @@ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
state = this->decode_opus_();
break;
#endif
#ifdef USE_AUDIO_WAV_SUPPORT
case AudioFileType::WAV:
state = this->decode_wav_();
break;
#endif
case AudioFileType::NONE:
default:
state = FileDecoderState::IDLE;
@@ -395,6 +399,7 @@ FileDecoderState AudioDecoder::decode_opus_() {
}
#endif
#ifdef USE_AUDIO_WAV_SUPPORT
FileDecoderState AudioDecoder::decode_wav_() {
if (!this->audio_stream_info_.has_value()) {
// Header hasn't been processed
@@ -441,6 +446,7 @@ FileDecoderState AudioDecoder::decode_wav_() {
return FileDecoderState::END_OF_FILE;
}
#endif
} // namespace audio
} // namespace esphome
+13 -5
View File
@@ -15,9 +15,6 @@
#include "esp_err.h"
// esp-audio-libs
#include <wav_decoder.h>
// micro-flac
#ifdef USE_AUDIO_FLAC_SUPPORT
#include <micro_flac/flac_decoder.h>
@@ -33,6 +30,11 @@
#include <micro_opus/ogg_opus_decoder.h>
#endif
// esp-audio-libs
#ifdef USE_AUDIO_WAV_SUPPORT
#include <wav_decoder.h>
#endif
namespace esphome {
namespace audio {
@@ -56,7 +58,7 @@ class AudioDecoder {
* @brief Class that facilitates decoding an audio file.
* The audio file is read from a source (ring buffer or const data pointer), decoded, and sent to an audio sink
* (ring buffer, speaker component, or callback).
* Supports wav, flac, mp3, and ogg opus formats.
* Supports flac, mp3, ogg opus, and wav formats (each enabled independently at compile time).
*/
public:
/// @brief Allocates the output transfer buffer and stores the input buffer size for later use by add_source()
@@ -119,7 +121,6 @@ class AudioDecoder {
void set_pause_output_state(bool pause_state) { this->pause_output_ = pause_state; }
protected:
std::unique_ptr<esp_audio_libs::wav_decoder::WAVDecoder> wav_decoder_;
#ifdef USE_AUDIO_FLAC_SUPPORT
FileDecoderState decode_flac_();
std::unique_ptr<micro_flac::FLACDecoder> flac_decoder_;
@@ -132,7 +133,10 @@ class AudioDecoder {
FileDecoderState decode_opus_();
std::unique_ptr<micro_opus::OggOpusDecoder> opus_decoder_;
#endif
#ifdef USE_AUDIO_WAV_SUPPORT
FileDecoderState decode_wav_();
std::unique_ptr<esp_audio_libs::wav_decoder::WAVDecoder> wav_decoder_;
#endif
std::unique_ptr<AudioReadableBuffer> input_buffer_;
std::unique_ptr<AudioSinkTransferBuffer> output_transfer_buffer_;
@@ -142,14 +146,18 @@ class AudioDecoder {
size_t input_buffer_size_{0};
size_t free_buffer_required_{0};
#ifdef USE_AUDIO_WAV_SUPPORT
size_t wav_bytes_left_{0};
#endif
uint32_t potentially_failed_count_{0};
uint32_t accumulated_frames_written_{0};
uint32_t playback_ms_{0};
bool end_of_file_{false};
#ifdef USE_AUDIO_WAV_SUPPORT
bool wav_has_known_end_{false};
#endif
bool decoder_buffers_internally_{false};
@@ -193,6 +193,8 @@ def _validate_supported_local_file(config: list[ConfigType]) -> list[ConfigType]
audio.request_mp3_support()
elif media_file_type_str == str(audio.AUDIO_FILE_TYPE_ENUM["OPUS"]):
audio.request_opus_support()
elif media_file_type_str == str(audio.AUDIO_FILE_TYPE_ENUM["WAV"]):
audio.request_wav_support()
return config
@@ -133,6 +133,7 @@ def request_codecs_for_format_configs(
audio.request_flac_support()
audio.request_mp3_support()
audio.request_opus_support()
audio.request_wav_support()
else:
if "FLAC" in needed_formats:
audio.request_flac_support()
@@ -140,6 +141,8 @@ def request_codecs_for_format_configs(
audio.request_mp3_support()
if "OPUS" in needed_formats:
audio.request_opus_support()
if "WAV" in needed_formats:
audio.request_wav_support()
# Local config key constants
@@ -210,6 +210,8 @@ def _final_validate(config):
audio.request_mp3_support()
elif fmt_name == "OPUS":
audio.request_opus_support()
elif fmt_name == "WAV":
audio.request_wav_support()
break
return config
@@ -17,9 +17,12 @@ namespace speaker {
// - Each stream has an individual speaker component for output
// - Each stream is handled by an ``AudioPipeline`` object with two parts/tasks
// - ``AudioReader`` handles reading from an HTTP source or from a PROGMEM flash set at compile time
// - ``AudioDecoder`` handles decoding the audio file. All formats are limited to two channels and 16 bits per sample
// - ``AudioDecoder`` handles decoding the audio file. All formats are limited to two channels and 16 bits per
// sample.
// Each format is enabled independently at compile time:
// - FLAC
// - MP3 (based on the libhelix decoder)
// - Ogg Opus
// - WAV
// - Each task runs until it is done processing the file or it receives a stop command
// - Inter-task communication uses a FreeRTOS Event Group
+1
View File
@@ -180,6 +180,7 @@
#define USE_AUDIO_FLAC_SUPPORT
#define USE_AUDIO_MP3_SUPPORT
#define USE_AUDIO_OPUS_SUPPORT
#define USE_AUDIO_WAV_SUPPORT
#define USE_API
#define USE_API_CLIENT_CONNECTED_TRIGGER
#define USE_API_CLIENT_DISCONNECTED_TRIGGER