13static const uint32_t INITIAL_BUFFER_MS = 1000;
15static const uint32_t READ_TASK_STACK_SIZE = 5 * 1024;
16static const uint32_t DECODE_TASK_STACK_SIZE = 3 * 1024;
18static const uint32_t INFO_ERROR_QUEUE_COUNT = 5;
20static const char *
const TAG =
"speaker_media_player.pipeline";
47 std::string base_name, UBaseType_t
priority)
48 : base_name_(std::move(base_name)),
50 task_stack_in_psram_(task_stack_in_psram),
52 buffer_size_(buffer_size) {
112 ESP_LOGE(TAG,
"Media reader encountered an error: %s", esp_err_to_name(event.
err.
value()));
114 ESP_LOGD(TAG,
"Reading %s file type", audio_file_type_to_string(event.
file_type.
value()));
120 ESP_LOGE(TAG,
"Decoder encountered an error: %s", esp_err_to_name(event.
err.
value()));
124 ESP_LOGD(TAG,
"Decoded audio has %d channels, %" PRId32
" Hz sample rate, and %d bits per sample",
132 ESP_LOGE(TAG,
"Failed to parse the file's header.");
135 ESP_LOGE(TAG,
"Incompatible bits per sample. Only 16 bits per sample is supported");
138 ESP_LOGE(TAG,
"Incompatible number of channels. Only 1 or 2 channel audio is supported.");
151 EventBits_t event_bits = xEventGroupGetBits(this->
event_group_);
178 xEventGroupClearBits(this->
event_group_, EventGroupBits::READER_MESSAGE_ERROR);
183 xEventGroupClearBits(this->
event_group_, EventGroupBits::DECODER_MESSAGE_ERROR);
194 xEventGroupClearBits(this->
event_group_, EventGroupBits::PIPELINE_COMMAND_STOP);
247 return ESP_ERR_NO_MEM;
254 return ESP_ERR_NO_MEM;
269 return ESP_ERR_NO_MEM;
274 xTaskCreateStatic(
read_task, (this->
base_name_ +
"_read").c_str(), READ_TASK_STACK_SIZE, (
void *)
this,
279 return ESP_ERR_INVALID_STATE;
295 return ESP_ERR_NO_MEM;
300 xTaskCreateStatic(
decode_task, (this->
base_name_ +
"_decode").c_str(), DECODE_TASK_STACK_SIZE, (
void *)
this,
305 return ESP_ERR_INVALID_STATE;
355 EventBits_t event_bits = xEventGroupWaitBits(
368 esp_err_t err = ESP_OK;
370 std::unique_ptr<audio::AudioReader> reader =
380 size_t file_ring_buffer_size = this_pipeline->
buffer_size_;
382 std::shared_ptr<RingBuffer> temp_ring_buffer;
390 err = ESP_ERR_NO_MEM;
412 event_bits = xEventGroupGetBits(this_pipeline->
event_group_);
428 event_bits = xEventGroupGetBits(this_pipeline->
event_group_);
445 EventBits_t event_bits =
459 std::unique_ptr<audio::AudioDecoder> decoder =
475 bool has_stream_info =
false;
476 bool started_playback =
false;
478 size_t initial_bytes_to_buffer = 0;
481 event_bits = xEventGroupGetBits(this_pipeline->
event_group_);
488 if (!started_playback) {
490 decoder->set_pause_output_state(
true);
492 started_playback =
true;
495 decoder->set_pause_output_state(this_pipeline->
pause_state_);
503 this_pipeline->
playback_ms_ = decoder->get_playback_ms();
509 if (!has_stream_info) {
518 if (!has_stream_info && decoder->get_audio_stream_info().has_value()) {
519 has_stream_info =
true;
539 decoder->add_sink(this_pipeline->
speaker_);
546#ifdef USE_AUDIO_MP3_SUPPORT
548 initial_bytes_to_buffer /= 8;
551#ifdef USE_AUDIO_FLAC_SUPPORT
553 initial_bytes_to_buffer /= 2;
562 if (!started_playback && has_stream_info) {
565 if (temp_ring_buffer->available() >= initial_bytes_to_buffer) {
566 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 IRAM_ATTR 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