11static const char *
const TAG =
"audio.decoder";
13static const uint32_t DECODING_TIMEOUT_MS = 50;
14static const uint32_t READ_WRITE_TIMEOUT_MS = 20;
16static const uint32_t MAX_POTENTIALLY_FAILED_COUNT = 10;
19 : input_buffer_size_(input_buffer_size) {
24#ifdef USE_AUDIO_MP3_SUPPORT
26 esp_audio_libs::helix_decoder::MP3FreeDecoder(this->
mp3_decoder_);
33 if (source ==
nullptr) {
34 return ESP_ERR_NO_MEM;
36 source->set_source(input_ring_buffer);
42 auto source = make_unique<ConstAudioSourceBuffer>();
43 source->set_data(data_pointer,
length);
53 return ESP_ERR_NO_MEM;
62 return ESP_ERR_NO_MEM;
71 return ESP_ERR_NO_MEM;
76 return ESP_ERR_NO_MEM;
85#ifdef USE_AUDIO_FLAC_SUPPORT
87 this->
flac_decoder_ = make_unique<esp_audio_libs::flac::FLACDecoder>();
96#ifdef USE_AUDIO_MP3_SUPPORT
98 this->
mp3_decoder_ = esp_audio_libs::helix_decoder::MP3InitDecoder();
107#ifdef USE_AUDIO_OPUS_SUPPORT
109 this->
opus_decoder_ = make_unique<micro_opus::OggOpusDecoder>();
116 this->
wav_decoder_ = make_unique<esp_audio_libs::wav_decoder::WAVDecoder>();
128 return ESP_ERR_NOT_SUPPORTED;
140 if (stop_gracefully) {
155 if (stop_gracefully) {
164 uint32_t decoding_start =
millis();
166 bool first_loop_iteration =
true;
168 size_t bytes_processed = 0;
169 size_t bytes_available_before_processing = 0;
175 size_t bytes_written =
185 delay(READ_WRITE_TIMEOUT_MS);
190 (
millis() - decoding_start > DECODING_TIMEOUT_MS)) {
198 size_t bytes_read = this->
input_buffer_->fill(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS),
201 if (!first_loop_iteration && (this->
input_buffer_->available() < bytes_processed)) {
209 bytes_available_before_processing = this->
input_buffer_->available();
214 if ((this->
input_buffer_->free() == 0) && first_loop_iteration) {
228#ifdef USE_AUDIO_FLAC_SUPPORT
233#ifdef USE_AUDIO_MP3_SUPPORT
238#ifdef USE_AUDIO_OPUS_SUPPORT
253 first_loop_iteration =
false;
254 bytes_processed = bytes_available_before_processing - this->
input_buffer_->available();
269#ifdef USE_AUDIO_FLAC_SUPPORT
275 if (result > esp_audio_libs::flac::FLAC_DECODER_HEADER_OUT_OF_DATA) {
280 size_t bytes_consumed = this->
flac_decoder_->get_bytes_index();
283 if (result == esp_audio_libs::flac::FLAC_DECODER_HEADER_OUT_OF_DATA) {
296 this->flac_decoder_->get_sample_rate());
301 uint32_t output_samples = 0;
303 this->output_transfer_buffer_->get_buffer_end(), &output_samples);
305 if (result == esp_audio_libs::flac::FLAC_DECODER_ERROR_OUT_OF_DATA) {
310 size_t bytes_consumed = this->
flac_decoder_->get_bytes_index();
313 if (result > esp_audio_libs::flac::FLAC_DECODER_ERROR_OUT_OF_DATA) {
322 if (result == esp_audio_libs::flac::FLAC_DECODER_NO_MORE_FRAMES) {
330#ifdef USE_AUDIO_MP3_SUPPORT
334 int32_t offset = esp_audio_libs::helix_decoder::MP3FindSyncWord(this->
input_buffer_->data(), buffer_length);
347 int err = esp_audio_libs::helix_decoder::MP3Decode(this->
mp3_decoder_, &buffer_start, &buffer_length,
350 size_t consumed = this->
input_buffer_->available() - buffer_length;
355 case esp_audio_libs::helix_decoder::ERR_MP3_OUT_OF_MEMORY:
357 case esp_audio_libs::helix_decoder::ERR_MP3_NULL_POINTER:
366 esp_audio_libs::helix_decoder::MP3FrameInfo mp3_frame_info;
367 esp_audio_libs::helix_decoder::MP3GetLastFrameInfo(this->
mp3_decoder_, &mp3_frame_info);
368 if (mp3_frame_info.outputSamps > 0) {
369 int bytes_per_sample = (mp3_frame_info.bitsPerSample / 8);
383#ifdef USE_AUDIO_OPUS_SUPPORT
385 bool processed_header = this->
opus_decoder_->is_initialized();
387 size_t bytes_consumed, samples_decoded;
389 micro_opus::OggOpusResult result = this->
opus_decoder_->decode(
390 this->
input_buffer_->data(), this->input_buffer_->available(), this->output_transfer_buffer_->get_buffer_end(),
391 this->output_transfer_buffer_->free(), bytes_consumed, samples_decoded);
393 if (result == micro_opus::OGG_OPUS_OK) {
394 if (!processed_header && this->
opus_decoder_->is_initialized()) {
398 this->opus_decoder_->get_sample_rate());
406 }
else if (result == micro_opus::OGG_OPUS_OUTPUT_BUFFER_TOO_SMALL) {
414 ESP_LOGE(TAG,
"Opus decoder failed: %" PRId8, result);
425 esp_audio_libs::wav_decoder::WAVDecoderResult result =
428 if (result == esp_audio_libs::wav_decoder::WAV_DECODER_SUCCESS_IN_DATA) {
432 this->
wav_decoder_->bits_per_sample(), this->wav_decoder_->num_channels(), this->wav_decoder_->sample_rate());
437 }
else if (result == esp_audio_libs::wav_decoder::WAV_DECODER_WARNING_INCOMPLETE_DATA) {
453 if (bytes_to_copy > 0) {
bool decoder_buffers_internally_
optional< AudioStreamInfo > audio_stream_info_
uint32_t accumulated_frames_written_
esp_err_t start(AudioFileType audio_file_type)
Sets up decoding the file.
esp_audio_libs::helix_decoder::HMP3Decoder mp3_decoder_
FileDecoderState decode_opus_()
std::unique_ptr< AudioReadableBuffer > input_buffer_
uint32_t potentially_failed_count_
size_t free_buffer_required_
std::unique_ptr< esp_audio_libs::flac::FLACDecoder > flac_decoder_
~AudioDecoder()
Deallocates the MP3 decoder (the flac, opus, and wav decoders are deallocated automatically)
std::unique_ptr< AudioSinkTransferBuffer > output_transfer_buffer_
size_t input_buffer_size_
AudioFileType audio_file_type_
FileDecoderState decode_flac_()
std::unique_ptr< micro_opus::OggOpusDecoder > opus_decoder_
esp_err_t add_source(std::weak_ptr< RingBuffer > &input_ring_buffer)
Adds a source ring buffer for raw file data.
std::unique_ptr< esp_audio_libs::wav_decoder::WAVDecoder > wav_decoder_
esp_err_t add_sink(std::weak_ptr< RingBuffer > &output_ring_buffer)
Adds a sink ring buffer for decoded audio.
FileDecoderState decode_wav_()
AudioDecoderState decode(bool stop_gracefully)
Decodes audio from the ring buffer source and writes to the sink.
FileDecoderState decode_mp3_()
AudioDecoder(size_t input_buffer_size, size_t output_buffer_size)
Allocates the output transfer buffer and stores the input buffer size for later use by add_source()
Abstract interface for writing decoded audio data to a sink.
static std::unique_ptr< AudioSinkTransferBuffer > create(size_t buffer_size)
Creates a new sink transfer buffer.
static std::unique_ptr< AudioSourceTransferBuffer > create(size_t buffer_size)
Creates a new source transfer buffer.
Providing packet encoding functions for exchanging data with a remote host.
void HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()