10static const char *
const TAG =
"audio.decoder";
12static const uint32_t READ_WRITE_TIMEOUT_MS = 20;
16static const uint8_t MAX_NO_OUTPUT_ITERATIONS = 32;
18static const uint32_t MAX_POTENTIALLY_FAILED_COUNT = 10;
21 : input_buffer_size_(input_buffer_size) {
29 if (source ==
nullptr) {
31 return ESP_ERR_INVALID_ARG;
38 auto source = make_unique<ConstAudioSourceBuffer>();
39 source->set_data(data_pointer,
length);
49 return ESP_ERR_NO_MEM;
58 return ESP_ERR_NO_MEM;
67 return ESP_ERR_NO_MEM;
72 return ESP_ERR_NO_MEM;
81#ifdef USE_AUDIO_FLAC_SUPPORT
88#ifdef USE_AUDIO_MP3_SUPPORT
90 this->
mp3_decoder_ = make_unique<micro_mp3::Mp3Decoder>();
95#ifdef USE_AUDIO_OPUS_SUPPORT
97 this->
opus_decoder_ = make_unique<micro_opus::OggOpusDecoder>();
102#ifdef USE_AUDIO_WAV_SUPPORT
104 this->
wav_decoder_ = make_unique<micro_wav::WAVDecoder>();
114 return ESP_ERR_NOT_SUPPORTED;
126 if (stop_gracefully) {
141 if (stop_gracefully) {
149 uint8_t no_output_iterations = 0;
155 size_t bytes_written =
171 delay(READ_WRITE_TIMEOUT_MS);
184 if (++no_output_iterations >= MAX_NO_OUTPUT_ITERATIONS) {
191 this->
input_buffer_->fill(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS),
false);
193 const size_t available_before_decode = this->
input_buffer_->available();
195 if (available_before_decode == 0) {
200#ifdef USE_AUDIO_FLAC_SUPPORT
205#ifdef USE_AUDIO_MP3_SUPPORT
210#ifdef USE_AUDIO_OPUS_SUPPORT
215#ifdef USE_AUDIO_WAV_SUPPORT
238 if ((this->
input_buffer_->available() < available_before_decode) ||
239 (this->output_transfer_buffer_->available() > 0)) {
249#ifdef USE_AUDIO_FLAC_SUPPORT
251 size_t bytes_consumed, samples_decoded;
253 micro_flac::FLACDecoderResult result = this->
flac_decoder_->decode(
254 this->
input_buffer_->data(), this->input_buffer_->available(), this->output_transfer_buffer_->get_buffer_end(),
255 this->output_transfer_buffer_->free(), bytes_consumed, samples_decoded);
257 if (result == micro_flac::FLAC_DECODER_SUCCESS) {
263 }
else if (result == micro_flac::FLAC_DECODER_HEADER_READY) {
274 }
else if (result == micro_flac::FLAC_DECODER_END_OF_STREAM) {
277 }
else if (result == micro_flac::FLAC_DECODER_NEED_MORE_DATA) {
280 }
else if (result == micro_flac::FLAC_DECODER_ERROR_OUTPUT_TOO_SMALL) {
288 ESP_LOGE(TAG,
"FLAC decoder failed: %d",
static_cast<int>(result));
296#ifdef USE_AUDIO_MP3_SUPPORT
300 size_t bytes_consumed = 0;
301 size_t samples_decoded = 0;
305 micro_mp3::Mp3Result result = this->
mp3_decoder_->decode(
306 this->
input_buffer_->data(), this->input_buffer_->available(), this->output_transfer_buffer_->get_buffer_end(),
307 this->output_transfer_buffer_->free(), bytes_consumed, samples_decoded);
311 if (result == micro_mp3::MP3_OK) {
316 }
else if (result == micro_mp3::MP3_STREAM_INFO_READY) {
326 }
else if (result == micro_mp3::MP3_NEED_MORE_DATA) {
328 }
else if (result == micro_mp3::MP3_OUTPUT_BUFFER_TOO_SMALL) {
340 }
else if (result == micro_mp3::MP3_DECODE_ERROR) {
342 ESP_LOGW(TAG,
"MP3 decoder skipped a corrupt frame");
346 ESP_LOGE(TAG,
"MP3 decoder failed: %d",
static_cast<int>(result));
354#ifdef USE_AUDIO_OPUS_SUPPORT
356 bool processed_header = this->
opus_decoder_->is_initialized();
358 size_t bytes_consumed, samples_decoded;
360 micro_opus::OggOpusResult result = this->
opus_decoder_->decode(
361 this->
input_buffer_->data(), this->input_buffer_->available(), this->output_transfer_buffer_->get_buffer_end(),
362 this->output_transfer_buffer_->free(), bytes_consumed, samples_decoded);
364 if (result == micro_opus::OGG_OPUS_OK) {
365 if (!processed_header && this->
opus_decoder_->is_initialized()) {
369 this->opus_decoder_->get_sample_rate());
377 }
else if (result == micro_opus::OGG_OPUS_OUTPUT_BUFFER_TOO_SMALL) {
385 ESP_LOGE(TAG,
"Opus decoder failed: %" PRId8, result);
392#ifdef USE_AUDIO_WAV_SUPPORT
396 size_t bytes_consumed = 0;
397 size_t samples_decoded = 0;
399 micro_wav::WAVDecoderResult result = this->
wav_decoder_->decode(
400 this->
input_buffer_->data(), this->input_buffer_->available(), this->output_transfer_buffer_->get_buffer_end(),
401 this->output_transfer_buffer_->free(), bytes_consumed, samples_decoded);
405 if (result == micro_wav::WAV_DECODER_SUCCESS) {
410 }
else if (result == micro_wav::WAV_DECODER_HEADER_READY) {
415 this->wav_decoder_->get_sample_rate());
416 }
else if (result == micro_wav::WAV_DECODER_NEED_MORE_DATA) {
418 }
else if (result == micro_wav::WAV_DECODER_END_OF_STREAM) {
421 ESP_LOGE(TAG,
"WAV decoder failed: %d",
static_cast<int>(result));
optional< AudioStreamInfo > audio_stream_info_
esp_err_t add_source(std::weak_ptr< ring_buffer::RingBuffer > &input_ring_buffer)
Adds a source ring buffer for raw file data.
uint32_t accumulated_frames_written_
esp_err_t start(AudioFileType audio_file_type)
Sets up decoding the file.
FileDecoderState decode_opus_()
std::unique_ptr< AudioReadableBuffer > input_buffer_
std::unique_ptr< micro_flac::FLACDecoder > flac_decoder_
uint32_t potentially_failed_count_
size_t free_buffer_required_
std::unique_ptr< micro_wav::WAVDecoder > wav_decoder_
std::unique_ptr< AudioSinkTransferBuffer > output_transfer_buffer_
esp_err_t add_sink(std::weak_ptr< ring_buffer::RingBuffer > &output_ring_buffer)
Adds a sink ring buffer for decoded audio.
AudioFileType audio_file_type_
FileDecoderState decode_flac_()
std::unique_ptr< micro_opus::OggOpusDecoder > opus_decoder_
FileDecoderState decode_wav_()
AudioDecoderState decode(bool stop_gracefully)
Decodes audio from the ring buffer source and writes to the sink.
FileDecoderState decode_mp3_()
std::unique_ptr< micro_mp3::Mp3Decoder > mp3_decoder_
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< RingBufferAudioSource > create(std::shared_ptr< ring_buffer::RingBuffer > ring_buffer, size_t max_fill_bytes, uint8_t alignment_bytes=1)
Creates a new ring-buffer-backed audio source after validating its parameters.
void HOT delay(uint32_t ms)