18static const UBaseType_t RESAMPLER_TASK_PRIORITY = 1;
20static const uint32_t TRANSFER_BUFFER_DURATION_MS = 50;
22static const uint32_t TASK_STACK_SIZE = 3072;
24static const uint32_t STATE_TRANSITION_TIMEOUT_MS = 5000;
26static const char *
const TAG =
"resampler_speaker";
45 "Resampler Speaker:\n"
46 " Target Bits Per Sample: %u\n"
47 " Target Sample Rate: %" PRIu32
" Hz",
54 ESP_LOGE(TAG,
"Failed to create event group");
77 uint32_t event_group_bits = xEventGroupGetBits(this->
event_group_);
84 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::COMMAND_STOP |
91 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::COMMAND_STOP |
98 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::COMMAND_FINISH);
102 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::COMMAND_FINISH);
107 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::COMMAND_START);
111 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::COMMAND_START);
117 event_group_bits = xEventGroupGetBits(this->
event_group_);
120 ESP_LOGD(TAG,
"Starting");
121 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::STATE_STARTING);
126 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::ERR_ESP_NO_MEM);
131 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::ERR_ESP_NOT_SUPPORTED);
136 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::ERR_ESP_FAIL);
141 ESP_LOGV(TAG,
"Started");
143 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::STATE_RUNNING);
146 ESP_LOGV(TAG,
"Stopping");
147 xEventGroupClearBits(this->
event_group_, ResamplingEventGroupBits::STATE_STOPPING);
151 ESP_LOGD(TAG,
"Stopped");
158 esp_err_t err = this->
start_();
201 event_group_bits = xEventGroupGetBits(this->
event_group_);
202 if (event_group_bits == 0) {
212 case ESP_ERR_INVALID_STATE:
229 size_t bytes_written = 0;
233 std::shared_ptr<RingBuffer> temp_ring_buffer = this->
ring_buffer_.lock();
234 if (temp_ring_buffer) {
236 bytes_written = temp_ring_buffer->write_without_replacement(data,
length, ticks_to_wait);
239 vTaskDelay(ticks_to_wait);
243 return bytes_written;
248 uint32_t event_bits = xEventGroupGetBits(this->
event_group_);
249 if (!(event_bits & command_bit)) {
251#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
288 return ESP_ERR_NO_MEM;
297 return ESP_ERR_INVALID_STATE;
338 bool has_ring_buffer_data =
false;
340 std::shared_ptr<RingBuffer> temp_ring_buffer = this->
ring_buffer_.lock();
341 if (temp_ring_buffer) {
342 has_ring_buffer_data = (temp_ring_buffer->available() > 0);
368 std::unique_ptr<audio::AudioResampler> resampler =
376 std::shared_ptr<RingBuffer> temp_ring_buffer =
379 if (!temp_ring_buffer) {
380 err = ESP_ERR_NO_MEM;
392 }
else if (err == ESP_ERR_NO_MEM) {
394 }
else if (err == ESP_ERR_NOT_SUPPORTED) {
398 while (err == ESP_OK) {
399 uint32_t event_bits = xEventGroupGetBits(this_resampler->
event_group_);
406 int32_t ms_differential = 0;
421 vTaskSuspend(
nullptr);
void wake_loop_threadsafe()
Wake the main event loop from another FreeRTOS task.
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void mark_failed()
Mark this component as failed.
void status_clear_error()
void enable_loop_soon_any_context()
Thread and ISR-safe version of enable_loop() that can be called from any context.
void disable_loop()
Disable this component's loop.
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
uint32_t get_sample_rate() const
void set_start_error_(esp_err_t err)
Sets the appropriate status error based on the start failure reason.
void set_volume(float volume) override
Volume state changes are passed to the parent's output speaker.
std::weak_ptr< RingBuffer > ring_buffer_
bool requires_resampling_() const
audio::AudioStreamInfo target_stream_info_
uint32_t buffer_duration_ms_
bool task_stack_in_psram_
esp_err_t start_()
Starts the output speaker after setting the resampled stream info.
uint8_t target_bits_per_sample_
size_t play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) override
TaskHandle_t task_handle_
void enter_stopping_state_()
Transitions to STATE_STOPPING, records the stopping timestamp, sends the task stop command if the tas...
speaker::Speaker * output_speaker_
void dump_config() override
StackType_t * task_stack_buffer_
bool has_buffered_data() const override
void delete_task_()
Deletes the resampler task if suspended, deallocates the task stack, and resets the related pointers.
void send_command_(uint32_t command_bit, bool wake_loop=false)
Sends a command via event group bits, enables the loop, and optionally wakes the main loop.
EventGroupHandle_t event_group_
uint64_t callback_remainder_
esp_err_t start_task_()
Starts the resampler task after allocating the task stack.
uint32_t target_sample_rate_
static void resample_task(void *params)
void set_mute_state(bool mute_state) override
Mute state changes are passed to the parent's output speaker.
virtual size_t play(const uint8_t *data, size_t length)=0
Plays the provided audio data.
virtual void set_volume(float volume)
void add_audio_output_callback(std::function< void(uint32_t, int64_t)> &&callback)
Callback function for sending the duration of the audio written to the speaker since the last callbac...
virtual bool get_pause_state() const
CallbackManager< void(uint32_t, int64_t)> audio_output_callback_
void set_audio_stream_info(const audio::AudioStreamInfo &audio_stream_info)
virtual void set_mute_state(bool mute_state)
virtual bool has_buffered_data() const =0
audio::AudioStreamInfo audio_stream_info_
Providing packet encoding functions for exchanging data with a remote host.
Application App
Global storage of Application pointer - only one Application can exist.