13 static const uint32_t INITIAL_BUFFER_MS = 1000;
15 static const uint32_t READ_TASK_STACK_SIZE = 5 * 1024;
16 static const uint32_t DECODE_TASK_STACK_SIZE = 3 * 1024;
18 static const uint32_t INFO_ERROR_QUEUE_COUNT = 5;
20 static 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()));
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",
125 event.
audio_stream_info.value().get_channels(),
event.audio_stream_info.value().get_sample_rate(),
126 event.audio_stream_info.value().get_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_);
184 xEventGroupClearBits(this->
event_group_, EventGroupBits::PIPELINE_COMMAND_STOP);
207 xEventGroupClearBits(this->
event_group_, EventGroupBits::READER_MESSAGE_ERROR);
212 xEventGroupClearBits(this->
event_group_, EventGroupBits::DECODER_MESSAGE_ERROR);
235 return ESP_ERR_NO_MEM;
242 return ESP_ERR_NO_MEM;
260 return ESP_ERR_NO_MEM;
265 xTaskCreateStatic(
read_task, (this->
base_name_ +
"_read").c_str(), READ_TASK_STACK_SIZE, (
void *)
this,
270 return ESP_ERR_INVALID_STATE;
286 return ESP_ERR_NO_MEM;
291 xTaskCreateStatic(
decode_task, (this->
base_name_ +
"_decode").c_str(), DECODE_TASK_STACK_SIZE, (
void *)
this,
296 return ESP_ERR_INVALID_STATE;
346 EventBits_t event_bits =
360 esp_err_t err = ESP_OK;
362 std::unique_ptr<audio::AudioReader> reader =
372 size_t file_ring_buffer_size = this_pipeline->
buffer_size_;
374 std::shared_ptr<RingBuffer> temp_ring_buffer;
382 err = ESP_ERR_NO_MEM;
404 event_bits = xEventGroupGetBits(this_pipeline->
event_group_);
406 if (event_bits & EventGroupBits::PIPELINE_COMMAND_STOP) {
420 event_bits = xEventGroupGetBits(this_pipeline->
event_group_);
437 EventBits_t event_bits = xEventGroupWaitBits(this_pipeline->
event_group_,
450 std::unique_ptr<audio::AudioDecoder> decoder =
466 bool has_stream_info =
false;
467 bool started_playback =
false;
469 size_t initial_bytes_to_buffer = 0;
472 event_bits = xEventGroupGetBits(this_pipeline->
event_group_);
474 if (event_bits & EventGroupBits::PIPELINE_COMMAND_STOP) {
479 if (!started_playback) {
481 decoder->set_pause_output_state(
true);
483 started_playback =
true;
486 decoder->set_pause_output_state(this_pipeline->
pause_state_);
494 this_pipeline->
playback_ms_ = decoder->get_playback_ms();
500 if (!has_stream_info) {
509 if (!has_stream_info && decoder->get_audio_stream_info().has_value()) {
510 has_stream_info =
true;
530 decoder->add_sink(this_pipeline->
speaker_);
537 #ifdef USE_AUDIO_MP3_SUPPORT 539 initial_bytes_to_buffer /= 8;
542 #ifdef USE_AUDIO_FLAC_SUPPORT 544 initial_bytes_to_buffer /= 2;
553 if (!started_playback && has_stream_info) {
556 if (temp_ring_buffer->available() >= initial_bytes_to_buffer) {
557 started_playback =
true;
value_type const & value() const
StaticTask_t read_task_stack_
static void decode_task(void *params)
esp_err_t start_tasks_()
Common start code for the pipeline, regardless if the source is a file or url.
optional< DecodingError > decoding_err
uint8_t get_channels() const
StaticTask_t decode_task_stack_
speaker::Speaker * speaker_
void set_pause_state(bool pause_state)
optional< audio::AudioStreamInfo > audio_stream_info
bool task_stack_in_psram_
QueueHandle_t info_error_queue_
void start_file(audio::AudioFile *audio_file)
Starts an audio pipeline given a AudioFile pointer.
uint8_t get_bits_per_sample() const
AudioPipelineState process_state()
Processes the state of the audio pipeline based on the info_error_queue_ and event_group_.
optional< esp_err_t > err
audio::AudioFile * current_audio_file_
void suspend_tasks()
Suspends any running tasks.
audio::AudioStreamInfo current_audio_stream_info_
StackType_t * decode_task_stack_buffer_
audio::AudioFileType current_audio_file_type_
TaskHandle_t read_task_handle_
EventGroupHandle_t event_group_
void set_audio_stream_info(const audio::AudioStreamInfo &audio_stream_info)
TaskHandle_t decode_task_handle_
std::weak_ptr< RingBuffer > raw_file_ring_buffer_
void resume_tasks()
Resumes any running tasks.
size_t transfer_buffer_size_
optional< audio::AudioFileType > file_type
StackType_t * read_task_stack_buffer_
size_t ms_to_bytes(uint32_t ms) const
Converts duration to bytes.
void deallocate(T *p, size_t n)
void delete_tasks_()
Resets the task related pointers and deallocates their stacks.
esp_err_t allocate_communications_()
Allocates the event group and info error queue.
Implementation of SPI Controller mode.
virtual void set_pause_state(bool pause_state)
void start_url(const std::string &uri)
Starts an audio pipeline given a media url.
esp_err_t stop()
Stops the pipeline.
static void read_task(void *params)
An STL allocator that uses SPI or internal RAM.
static std::unique_ptr< RingBuffer > create(size_t len)
const char * audio_file_type_to_string(AudioFileType file_type)
Helper function to convert file type to a const char string.
void IRAM_ATTR HOT delay(uint32_t ms)
AudioPipeline(speaker::Speaker *speaker, size_t buffer_size, bool task_stack_in_psram, std::string base_name, UBaseType_t priority)