13static const uint32_t INITIAL_BUFFER_MS = 1000;
15static const uint32_t READ_TASK_STACK_SIZE = 5 * 1024;
17#ifdef USE_AUDIO_OPUS_SUPPORT
18static const uint32_t DECODE_TASK_STACK_SIZE = 5 * 1024;
20static const uint32_t DECODE_TASK_STACK_SIZE = 3 * 1024;
23static const uint32_t INFO_ERROR_QUEUE_COUNT = 5;
25static const char *
const TAG =
"speaker_media_player.pipeline";
52 std::string base_name, UBaseType_t
priority)
53 : base_name_(std::move(base_name)),
55 task_stack_in_psram_(task_stack_in_psram),
57 buffer_size_(buffer_size) {
117 ESP_LOGE(TAG,
"Media reader encountered an error: %s", esp_err_to_name(event.
err.
value()));
119 ESP_LOGD(TAG,
"Reading %s file type", audio_file_type_to_string(event.
file_type.
value()));
125 ESP_LOGE(TAG,
"Decoder encountered an error: %s", esp_err_to_name(event.
err.
value()));
129 ESP_LOGD(TAG,
"Decoded audio has %d channels, %" PRId32
" Hz sample rate, and %d bits per sample",
137 ESP_LOGE(TAG,
"Failed to parse the file's header.");
140 ESP_LOGE(TAG,
"Incompatible bits per sample. Only 16 bits per sample is supported");
143 ESP_LOGE(TAG,
"Incompatible number of channels. Only 1 or 2 channel audio is supported.");
156 EventBits_t event_bits = xEventGroupGetBits(this->
event_group_);
183 xEventGroupClearBits(this->
event_group_, EventGroupBits::READER_MESSAGE_ERROR);
188 xEventGroupClearBits(this->
event_group_, EventGroupBits::DECODER_MESSAGE_ERROR);
199 xEventGroupClearBits(this->
event_group_, EventGroupBits::PIPELINE_COMMAND_STOP);
252 return ESP_ERR_NO_MEM;
259 return ESP_ERR_NO_MEM;
274 return ESP_ERR_NO_MEM;
279 xTaskCreateStatic(
read_task, (this->
base_name_ +
"_read").c_str(), READ_TASK_STACK_SIZE, (
void *)
this,
284 return ESP_ERR_INVALID_STATE;
300 return ESP_ERR_NO_MEM;
305 xTaskCreateStatic(
decode_task, (this->
base_name_ +
"_decode").c_str(), DECODE_TASK_STACK_SIZE, (
void *)
this,
310 return ESP_ERR_INVALID_STATE;
360 EventBits_t event_bits = xEventGroupWaitBits(
373 esp_err_t err = ESP_OK;
375 std::unique_ptr<audio::AudioReader> reader =
385 size_t file_ring_buffer_size = this_pipeline->
buffer_size_;
387 std::shared_ptr<RingBuffer> temp_ring_buffer;
395 err = ESP_ERR_NO_MEM;
417 event_bits = xEventGroupGetBits(this_pipeline->
event_group_);
433 event_bits = xEventGroupGetBits(this_pipeline->
event_group_);
450 EventBits_t event_bits =
464 std::unique_ptr<audio::AudioDecoder> decoder =
480 bool has_stream_info =
false;
481 bool started_playback =
false;
483 size_t initial_bytes_to_buffer = 0;
486 event_bits = xEventGroupGetBits(this_pipeline->
event_group_);
493 if (!started_playback) {
495 decoder->set_pause_output_state(
true);
497 started_playback =
true;
500 decoder->set_pause_output_state(this_pipeline->
pause_state_);
508 this_pipeline->
playback_ms_ = decoder->get_playback_ms();
514 if (!has_stream_info) {
523 if (!has_stream_info && decoder->get_audio_stream_info().has_value()) {
524 has_stream_info =
true;
544 decoder->add_sink(this_pipeline->
speaker_);
551#ifdef USE_AUDIO_MP3_SUPPORT
553 initial_bytes_to_buffer /= 8;
556#ifdef USE_AUDIO_FLAC_SUPPORT
558 initial_bytes_to_buffer /= 2;
561#ifdef USE_AUDIO_OPUS_SUPPORT
563 initial_bytes_to_buffer /= 8;
572 if (!started_playback && has_stream_info) {
575 if (temp_ring_buffer->available() >= initial_bytes_to_buffer) {
576 started_playback =
true;
An STL allocator that uses SPI or internal RAM.
void deallocate(T *p, size_t n)
static std::unique_ptr< RingBuffer > create(size_t len)
size_t ms_to_bytes(uint32_t ms) const
Converts duration to bytes.
uint8_t get_bits_per_sample() const
uint8_t get_channels() const
value_type const & value() const
static void read_task(void *params)
void suspend_tasks()
Suspends any running tasks.
speaker::Speaker * speaker_
void set_pause_state(bool pause_state)
void delete_tasks_()
Resets the task related pointers and deallocates their stacks.
std::weak_ptr< RingBuffer > raw_file_ring_buffer_
void start_url(const std::string &uri)
Starts an audio pipeline given a media url.
esp_err_t allocate_communications_()
Allocates the event group and info error queue.
esp_err_t start_tasks_()
Common start code for the pipeline, regardless if the source is a file or url.
audio::AudioStreamInfo current_audio_stream_info_
StackType_t * decode_task_stack_buffer_
void start_file(audio::AudioFile *audio_file)
Starts an audio pipeline given a AudioFile pointer.
TaskHandle_t decode_task_handle_
esp_err_t stop()
Stops the pipeline.
StaticTask_t decode_task_stack_
static void decode_task(void *params)
AudioPipeline(speaker::Speaker *speaker, size_t buffer_size, bool task_stack_in_psram, std::string base_name, UBaseType_t priority)
void resume_tasks()
Resumes any running tasks.
EventGroupHandle_t event_group_
audio::AudioFile * current_audio_file_
StaticTask_t read_task_stack_
bool task_stack_in_psram_
size_t transfer_buffer_size_
TaskHandle_t read_task_handle_
QueueHandle_t info_error_queue_
audio::AudioFileType current_audio_file_type_
StackType_t * read_task_stack_buffer_
AudioPipelineState process_state()
Processes the state of the audio pipeline based on the info_error_queue_ and event_group_.
virtual void set_pause_state(bool pause_state)
void set_audio_stream_info(const audio::AudioStreamInfo &audio_stream_info)
@ DECODER_MESSAGE_FINISHED
@ READER_COMMAND_INIT_FILE
@ READER_COMMAND_INIT_HTTP
@ READER_MESSAGE_LOADED_MEDIA_TYPE
@ READER_MESSAGE_FINISHED
@ INCOMPATIBLE_BITS_PER_SAMPLE
Providing packet encoding functions for exchanging data with a remote host.
void HOT delay(uint32_t ms)
optional< DecodingError > decoding_err
optional< esp_err_t > err
optional< audio::AudioFileType > file_type
optional< audio::AudioStreamInfo > audio_stream_info