ESPHome  2025.2.0
i2s_audio_speaker.cpp
Go to the documentation of this file.
1 #include "i2s_audio_speaker.h"
2 
3 #ifdef USE_ESP32
4 
5 #include <driver/i2s.h>
6 
8 
10 #include "esphome/core/hal.h"
11 #include "esphome/core/log.h"
12 
13 namespace esphome {
14 namespace i2s_audio {
15 
16 static const uint8_t DMA_BUFFER_DURATION_MS = 15;
17 static const size_t DMA_BUFFERS_COUNT = 4;
18 
19 static const size_t TASK_DELAY_MS = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT / 2;
20 
21 static const size_t TASK_STACK_SIZE = 4096;
22 static const ssize_t TASK_PRIORITY = 23;
23 
24 static const size_t I2S_EVENT_QUEUE_COUNT = DMA_BUFFERS_COUNT + 1;
25 
26 static const char *const TAG = "i2s_audio.speaker";
27 
28 enum SpeakerEventGroupBits : uint32_t {
29  COMMAND_START = (1 << 0), // starts the speaker task
30  COMMAND_STOP = (1 << 1), // stops the speaker task
31  COMMAND_STOP_GRACEFULLY = (1 << 2), // Stops the speaker task once all data has been written
32  STATE_STARTING = (1 << 10),
33  STATE_RUNNING = (1 << 11),
34  STATE_STOPPING = (1 << 12),
35  STATE_STOPPED = (1 << 13),
37  ERR_ESP_INVALID_STATE = (1 << 15),
38  ERR_ESP_NOT_SUPPORTED = (1 << 16),
39  ERR_ESP_INVALID_ARG = (1 << 17),
40  ERR_ESP_INVALID_SIZE = (1 << 18),
41  ERR_ESP_NO_MEM = (1 << 19),
42  ERR_ESP_FAIL = (1 << 20),
45  ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
46 };
47 
48 // Translates a SpeakerEventGroupBits ERR_ESP bit to the coressponding esp_err_t
49 static esp_err_t err_bit_to_esp_err(uint32_t bit) {
50  switch (bit) {
52  return ESP_ERR_INVALID_STATE;
54  return ESP_ERR_INVALID_ARG;
56  return ESP_ERR_INVALID_SIZE;
58  return ESP_ERR_NO_MEM;
60  return ESP_ERR_NOT_SUPPORTED;
61  default:
62  return ESP_FAIL;
63  }
64 }
65 
75 static void q15_multiplication(const int16_t *input, int16_t *output, size_t len, int16_t c) {
76  for (int i = 0; i < len; i++) {
77  int32_t acc = (int32_t) input[i] * (int32_t) c;
78  output[i] = (int16_t) (acc >> 15);
79  }
80 }
81 
82 // Lists the Q15 fixed point scaling factor for volume reduction.
83 // Has 100 values representing silence and a reduction [49, 48.5, ... 0.5, 0] dB.
84 // dB to PCM scaling factor formula: floating_point_scale_factor = 2^(-db/6.014)
85 // float to Q15 fixed point formula: q15_scale_factor = floating_point_scale_factor * 2^(15)
86 static const std::vector<int16_t> Q15_VOLUME_SCALING_FACTORS = {
87  0, 116, 122, 130, 137, 146, 154, 163, 173, 183, 194, 206, 218, 231, 244,
88  259, 274, 291, 308, 326, 345, 366, 388, 411, 435, 461, 488, 517, 548, 580,
89  615, 651, 690, 731, 774, 820, 868, 920, 974, 1032, 1094, 1158, 1227, 1300, 1377,
90  1459, 1545, 1637, 1734, 1837, 1946, 2061, 2184, 2313, 2450, 2596, 2750, 2913, 3085, 3269,
91  3462, 3668, 3885, 4116, 4360, 4619, 4893, 5183, 5490, 5816, 6161, 6527, 6914, 7324, 7758,
92  8218, 8706, 9222, 9770, 10349, 10963, 11613, 12302, 13032, 13805, 14624, 15491, 16410, 17384, 18415,
93  19508, 20665, 21891, 23189, 24565, 26022, 27566, 29201, 30933, 32767};
94 
96  ESP_LOGCONFIG(TAG, "Setting up I2S Audio Speaker...");
97 
98  this->event_group_ = xEventGroupCreate();
99 
100  if (this->event_group_ == nullptr) {
101  ESP_LOGE(TAG, "Failed to create event group");
102  this->mark_failed();
103  return;
104  }
105 }
106 
108  uint32_t event_group_bits = xEventGroupGetBits(this->event_group_);
109 
110  if (event_group_bits & SpeakerEventGroupBits::STATE_STARTING) {
111  ESP_LOGD(TAG, "Starting Speaker");
113  xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STARTING);
114  }
115  if (event_group_bits & SpeakerEventGroupBits::STATE_RUNNING) {
116  ESP_LOGD(TAG, "Started Speaker");
118  xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
119  this->status_clear_warning();
120  this->status_clear_error();
121  }
122  if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPING) {
123  ESP_LOGD(TAG, "Stopping Speaker");
125  xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
126  }
127  if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPED) {
128  if (!this->task_created_) {
129  ESP_LOGD(TAG, "Stopped Speaker");
131  xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ALL_BITS);
132  this->speaker_task_handle_ = nullptr;
133  }
134  }
135 
136  if (event_group_bits & SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START) {
137  this->status_set_error("Failed to start speaker task");
138  xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
139  }
140 
141  if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) {
142  uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS;
143  ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits)));
144  this->status_set_warning();
145  }
146 
147  if (event_group_bits & SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED) {
148  this->status_set_error("Failed to adjust I2S bus to match the incoming audio");
149  ESP_LOGE(TAG,
150  "Incompatible audio format: sample rate = %" PRIu32 ", channels = %" PRIu8 ", bits per sample = %" PRIu8,
153  }
154 
155  xEventGroupClearBits(this->event_group_, ALL_ERR_ESP_BITS);
156 }
157 
158 void I2SAudioSpeaker::set_volume(float volume) {
159  this->volume_ = volume;
160 #ifdef USE_AUDIO_DAC
161  if (this->audio_dac_ != nullptr) {
162  if (volume > 0.0) {
163  this->audio_dac_->set_mute_off();
164  }
165  this->audio_dac_->set_volume(volume);
166  } else
167 #endif
168  {
169  // Fallback to software volume control by using a Q15 fixed point scaling factor
170  ssize_t decibel_index = remap<ssize_t, float>(volume, 0.0f, 1.0f, 0, Q15_VOLUME_SCALING_FACTORS.size() - 1);
171  this->q15_volume_factor_ = Q15_VOLUME_SCALING_FACTORS[decibel_index];
172  }
173 }
174 
175 void I2SAudioSpeaker::set_mute_state(bool mute_state) {
176  this->mute_state_ = mute_state;
177 #ifdef USE_AUDIO_DAC
178  if (this->audio_dac_) {
179  if (mute_state) {
180  this->audio_dac_->set_mute_on();
181  } else {
182  this->audio_dac_->set_mute_off();
183  }
184  } else
185 #endif
186  {
187  if (mute_state) {
188  // Fallback to software volume control and scale by 0
189  this->q15_volume_factor_ = 0;
190  } else {
191  // Revert to previous volume when unmuting
192  this->set_volume(this->volume_);
193  }
194  }
195 }
196 
197 size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) {
198  if (this->is_failed()) {
199  ESP_LOGE(TAG, "Cannot play audio, speaker failed to setup");
200  return 0;
201  }
202  if (this->state_ != speaker::STATE_RUNNING && this->state_ != speaker::STATE_STARTING) {
203  this->start();
204  }
205 
206  if ((this->state_ != speaker::STATE_RUNNING) || (this->audio_ring_buffer_.use_count() == 1)) {
207  // Unable to write data to a running speaker, so delay the max amount of time so it can get ready
208  vTaskDelay(ticks_to_wait);
209  ticks_to_wait = 0;
210  }
211 
212  size_t bytes_written = 0;
213  if ((this->state_ == speaker::STATE_RUNNING) && (this->audio_ring_buffer_.use_count() == 1)) {
214  // Only one owner of the ring buffer (the speaker task), so the ring buffer is allocated and no other components are
215  // attempting to write to it.
216 
217  // Temporarily share ownership of the ring buffer so it won't be deallocated while writing
218  std::shared_ptr<RingBuffer> temp_ring_buffer = this->audio_ring_buffer_;
219  bytes_written = temp_ring_buffer->write_without_replacement((void *) data, length, ticks_to_wait);
220  }
221 
222  return bytes_written;
223 }
224 
226  if (this->audio_ring_buffer_ != nullptr) {
227  return this->audio_ring_buffer_->available() > 0;
228  }
229  return false;
230 }
231 
232 void I2SAudioSpeaker::speaker_task(void *params) {
233  I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params;
234  this_speaker->task_created_ = true;
235 
236  uint32_t event_group_bits =
237  xEventGroupWaitBits(this_speaker->event_group_,
239  SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY, // Bit message to read
240  pdTRUE, // Clear the bits on exit
241  pdFALSE, // Don't wait for all the bits,
242  portMAX_DELAY); // Block indefinitely until a bit is set
243 
245  // Received a stop signal before the task was requested to start
246  this_speaker->delete_task_(0);
247  }
248 
249  xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STARTING);
250 
251  audio::AudioStreamInfo audio_stream_info = this_speaker->audio_stream_info_;
252 
253  const uint32_t dma_buffers_duration_ms = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT;
254  // Ensure ring buffer duration is at least the duration of all DMA buffers
255  const uint32_t ring_buffer_duration = std::max(dma_buffers_duration_ms, this_speaker->buffer_duration_ms_);
256 
257  // The DMA buffers may have more bits per sample, so calculate buffer sizes based in the input audio stream info
258  const size_t data_buffer_size = audio_stream_info.ms_to_bytes(dma_buffers_duration_ms);
259  const size_t ring_buffer_size = audio_stream_info.ms_to_bytes(ring_buffer_duration);
260 
261  const size_t single_dma_buffer_input_size = data_buffer_size / DMA_BUFFERS_COUNT;
262 
263  if (this_speaker->send_esp_err_to_event_group_(this_speaker->allocate_buffers_(data_buffer_size, ring_buffer_size))) {
264  // Failed to allocate buffers
265  xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
266  this_speaker->delete_task_(data_buffer_size);
267  }
268 
269  if (!this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_(audio_stream_info))) {
270  xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
271 
272  bool stop_gracefully = false;
273  uint32_t last_data_received_time = millis();
274  bool tx_dma_underflow = false;
275 
276  this_speaker->accumulated_frames_written_ = 0;
277 
278  // Keep looping if paused, there is no timeout configured, or data was received more recently than the configured
279  // timeout
280  while (this_speaker->pause_state_ || !this_speaker->timeout_.has_value() ||
281  (millis() - last_data_received_time) <= this_speaker->timeout_.value()) {
282  event_group_bits = xEventGroupGetBits(this_speaker->event_group_);
283 
284  if (event_group_bits & SpeakerEventGroupBits::COMMAND_STOP) {
285  xEventGroupClearBits(this_speaker->event_group_, SpeakerEventGroupBits::COMMAND_STOP);
286  break;
287  }
288  if (event_group_bits & SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY) {
289  xEventGroupClearBits(this_speaker->event_group_, SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY);
290  stop_gracefully = true;
291  }
292 
293  if (this_speaker->audio_stream_info_ != audio_stream_info) {
294  // Audio stream info changed, stop the speaker task so it will restart with the proper settings.
295  break;
296  }
297 
298  i2s_event_t i2s_event;
299  while (xQueueReceive(this_speaker->i2s_event_queue_, &i2s_event, 0)) {
300  if (i2s_event.type == I2S_EVENT_TX_Q_OVF) {
301  tx_dma_underflow = true;
302  }
303  }
304 
305  if (this_speaker->pause_state_) {
306  // Pause state is accessed atomically, so thread safe
307  // Delay so the task can yields, then skip transferring audio data
308  delay(TASK_DELAY_MS);
309  continue;
310  }
311 
312  size_t bytes_read = this_speaker->audio_ring_buffer_->read((void *) this_speaker->data_buffer_, data_buffer_size,
313  pdMS_TO_TICKS(TASK_DELAY_MS));
314 
315  if (bytes_read > 0) {
316  if ((audio_stream_info.get_bits_per_sample() == 16) && (this_speaker->q15_volume_factor_ < INT16_MAX)) {
317  // Scale samples by the volume factor in place
318  q15_multiplication((int16_t *) this_speaker->data_buffer_, (int16_t *) this_speaker->data_buffer_,
319  bytes_read / sizeof(int16_t), this_speaker->q15_volume_factor_);
320  }
321 
322  // Write the audio data to a single DMA buffer at a time to reduce latency for the audio duration played
323  // callback.
324  const uint32_t batches = (bytes_read + single_dma_buffer_input_size - 1) / single_dma_buffer_input_size;
325 
326  for (uint32_t i = 0; i < batches; ++i) {
327  size_t bytes_written = 0;
328  size_t bytes_to_write = std::min(single_dma_buffer_input_size, bytes_read);
329 
330  if (audio_stream_info.get_bits_per_sample() == (uint8_t) this_speaker->bits_per_sample_) {
331  i2s_write(this_speaker->parent_->get_port(), this_speaker->data_buffer_ + i * single_dma_buffer_input_size,
332  bytes_to_write, &bytes_written, pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS * 5));
333  } else if (audio_stream_info.get_bits_per_sample() < (uint8_t) this_speaker->bits_per_sample_) {
334  i2s_write_expand(this_speaker->parent_->get_port(),
335  this_speaker->data_buffer_ + i * single_dma_buffer_input_size, bytes_to_write,
336  audio_stream_info.get_bits_per_sample(), this_speaker->bits_per_sample_, &bytes_written,
337  pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS * 5));
338  }
339 
340  uint32_t write_timestamp = micros();
341 
342  if (bytes_written != bytes_to_write) {
343  xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE);
344  }
345 
346  bytes_read -= bytes_written;
347 
348  this_speaker->accumulated_frames_written_ += audio_stream_info.bytes_to_frames(bytes_written);
349  const uint32_t new_playback_ms =
350  audio_stream_info.frames_to_milliseconds_with_remainder(&this_speaker->accumulated_frames_written_);
351  const uint32_t remainder_us =
352  audio_stream_info.frames_to_microseconds(this_speaker->accumulated_frames_written_);
353 
354  uint32_t pending_frames =
355  audio_stream_info.bytes_to_frames(bytes_read + this_speaker->audio_ring_buffer_->available());
356  const uint32_t pending_ms = audio_stream_info.frames_to_milliseconds_with_remainder(&pending_frames);
357 
358  this_speaker->audio_output_callback_(new_playback_ms, remainder_us, pending_ms, write_timestamp);
359 
360  tx_dma_underflow = false;
361  last_data_received_time = millis();
362  }
363  } else {
364  // No data received
365  if (stop_gracefully && tx_dma_underflow) {
366  break;
367  }
368  }
369  }
370 
371  xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
372 
373  i2s_driver_uninstall(this_speaker->parent_->get_port());
374 
375  this_speaker->parent_->unlock();
376  }
377 
378  this_speaker->delete_task_(data_buffer_size);
379 }
380 
382  if (!this->is_ready() || this->is_failed() || this->status_has_error())
383  return;
384  if ((this->state_ == speaker::STATE_STARTING) || (this->state_ == speaker::STATE_RUNNING))
385  return;
386 
387  if (!this->task_created_ && (this->speaker_task_handle_ == nullptr)) {
388  xTaskCreate(I2SAudioSpeaker::speaker_task, "speaker_task", TASK_STACK_SIZE, (void *) this, TASK_PRIORITY,
389  &this->speaker_task_handle_);
390 
391  if (this->speaker_task_handle_ != nullptr) {
392  xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_START);
393  } else {
395  }
396  }
397 }
398 
399 void I2SAudioSpeaker::stop() { this->stop_(false); }
400 
401 void I2SAudioSpeaker::finish() { this->stop_(true); }
402 
403 void I2SAudioSpeaker::stop_(bool wait_on_empty) {
404  if (this->is_failed())
405  return;
406  if (this->state_ == speaker::STATE_STOPPED)
407  return;
408 
409  if (wait_on_empty) {
411  } else {
412  xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_STOP);
413  }
414 }
415 
417  switch (err) {
418  case ESP_OK:
419  return false;
420  case ESP_ERR_INVALID_STATE:
422  return true;
423  case ESP_ERR_INVALID_ARG:
424  xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_ARG);
425  return true;
426  case ESP_ERR_INVALID_SIZE:
428  return true;
429  case ESP_ERR_NO_MEM:
430  xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
431  return true;
432  case ESP_ERR_NOT_SUPPORTED:
434  return true;
435  default:
436  xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_FAIL);
437  return true;
438  }
439 }
440 
441 esp_err_t I2SAudioSpeaker::allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size) {
442  if (this->data_buffer_ == nullptr) {
443  // Allocate data buffer for temporarily storing audio from the ring buffer before writing to the I2S bus
445  this->data_buffer_ = allocator.allocate(data_buffer_size);
446  }
447 
448  if (this->data_buffer_ == nullptr) {
449  return ESP_ERR_NO_MEM;
450  }
451 
452  if (this->audio_ring_buffer_.use_count() == 0) {
453  // Allocate ring buffer. Uses a shared_ptr to ensure it isn't improperly deallocated.
454  this->audio_ring_buffer_ = RingBuffer::create(ring_buffer_size);
455  }
456 
457  if (this->audio_ring_buffer_ == nullptr) {
458  return ESP_ERR_NO_MEM;
459  }
460 
461  return ESP_OK;
462 }
463 
465  if ((this->i2s_mode_ & I2S_MODE_SLAVE) && (this->sample_rate_ != audio_stream_info.get_sample_rate())) { // NOLINT
466  // Can't reconfigure I2S bus, so the sample rate must match the configured value
467  return ESP_ERR_NOT_SUPPORTED;
468  }
469 
470  if ((i2s_bits_per_sample_t) audio_stream_info.get_bits_per_sample() > this->bits_per_sample_) {
471  // Currently can't handle the case when the incoming audio has more bits per sample than the configured value
472  return ESP_ERR_NOT_SUPPORTED;
473  }
474 
475  if (!this->parent_->try_lock()) {
476  return ESP_ERR_INVALID_STATE;
477  }
478 
479  i2s_channel_fmt_t channel = this->channel_;
480 
481  if (audio_stream_info.get_channels() == 1) {
482  if (this->channel_ == I2S_CHANNEL_FMT_ONLY_LEFT) {
483  channel = I2S_CHANNEL_FMT_ONLY_LEFT;
484  } else {
485  channel = I2S_CHANNEL_FMT_ONLY_RIGHT;
486  }
487  } else if (audio_stream_info.get_channels() == 2) {
488  channel = I2S_CHANNEL_FMT_RIGHT_LEFT;
489  }
490 
491  int dma_buffer_length = audio_stream_info.ms_to_frames(DMA_BUFFER_DURATION_MS);
492 
493  i2s_driver_config_t config = {
494  .mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX),
495  .sample_rate = audio_stream_info.get_sample_rate(),
496  .bits_per_sample = this->bits_per_sample_,
497  .channel_format = channel,
498  .communication_format = this->i2s_comm_fmt_,
499  .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
500  .dma_buf_count = DMA_BUFFERS_COUNT,
501  .dma_buf_len = dma_buffer_length,
502  .use_apll = this->use_apll_,
503  .tx_desc_auto_clear = true,
504  .fixed_mclk = I2S_PIN_NO_CHANGE,
505  .mclk_multiple = I2S_MCLK_MULTIPLE_256,
506  .bits_per_chan = this->bits_per_channel_,
507 #if SOC_I2S_SUPPORTS_TDM
508  .chan_mask = (i2s_channel_t) (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1),
509  .total_chan = 2,
510  .left_align = false,
511  .big_edin = false,
512  .bit_order_msb = false,
513  .skip_msk = false,
514 #endif
515  };
516 #if SOC_I2S_SUPPORTS_DAC
517  if (this->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) {
518  config.mode = (i2s_mode_t) (config.mode | I2S_MODE_DAC_BUILT_IN);
519  }
520 #endif
521 
522  esp_err_t err =
523  i2s_driver_install(this->parent_->get_port(), &config, I2S_EVENT_QUEUE_COUNT, &this->i2s_event_queue_);
524  if (err != ESP_OK) {
525  // Failed to install the driver, so unlock the I2S port
526  this->parent_->unlock();
527  return err;
528  }
529 
530 #if SOC_I2S_SUPPORTS_DAC
531  if (this->internal_dac_mode_ == I2S_DAC_CHANNEL_DISABLE) {
532 #endif
533  i2s_pin_config_t pin_config = this->parent_->get_pin_config();
534  pin_config.data_out_num = this->dout_pin_;
535 
536  err = i2s_set_pin(this->parent_->get_port(), &pin_config);
537 #if SOC_I2S_SUPPORTS_DAC
538  } else {
539  i2s_set_dac_mode(this->internal_dac_mode_);
540  }
541 #endif
542 
543  if (err != ESP_OK) {
544  // Failed to set the data out pin, so uninstall the driver and unlock the I2S port
545  i2s_driver_uninstall(this->parent_->get_port());
546  this->parent_->unlock();
547  }
548 
549  return err;
550 }
551 
552 void I2SAudioSpeaker::delete_task_(size_t buffer_size) {
553  this->audio_ring_buffer_.reset(); // Releases ownership of the shared_ptr
554 
555  if (this->data_buffer_ != nullptr) {
557  allocator.deallocate(this->data_buffer_, buffer_size);
558  this->data_buffer_ = nullptr;
559  }
560 
561  xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPED);
562 
563  this->task_created_ = false;
564  vTaskDelete(nullptr);
565 }
566 
567 } // namespace i2s_audio
568 } // namespace esphome
569 
570 #endif // USE_ESP32
value_type const & value() const
Definition: optional.h:89
size_t play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) override
Plays the provided audio data.
void stop_(bool wait_on_empty)
Sends a stop command to the speaker task via event_group_.
bool send_esp_err_to_event_group_(esp_err_t err)
Sets the corresponding ERR_ESP event group bits.
esp_err_t allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size)
Allocates the data buffer and ring buffer.
virtual bool set_mute_off()=0
virtual bool set_mute_on()=0
uint8_t get_channels() const
Definition: audio.h:29
static void speaker_task(void *params)
Function for the FreeRTOS task handling audio output.
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
uint32_t ms_to_frames(uint32_t ms) const
Converts duration to frames.
Definition: audio.h:63
bool is_failed() const
Definition: component.cpp:143
void set_volume(float volume) override
Sets the volume of the speaker.
uint8_t get_bits_per_sample() const
Definition: audio.h:28
T * allocate(size_t n)
Definition: helpers.h:703
bool has_value() const
Definition: optional.h:87
uint32_t frames_to_milliseconds_with_remainder(uint32_t *frames) const
Computes the duration, in milliseconds, the given amount of frames represents.
Definition: audio.cpp:26
uint32_t IRAM_ATTR HOT micros()
Definition: core.cpp:27
CallbackManager< void(uint32_t, uint32_t, uint32_t, uint32_t)> audio_output_callback_
Definition: speaker.h:126
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
bool is_ready() const
Definition: component.cpp:144
bool status_has_error() const
Definition: component.cpp:150
void status_set_error(const char *message="unspecified")
Definition: component.cpp:159
i2s_channel_fmt_t channel_
Definition: i2s_audio.h:25
esp_err_t start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info)
Starts the ESP32 I2S driver.
void status_clear_warning()
Definition: component.cpp:166
void set_mute_state(bool mute_state) override
Mutes or unmute the speaker.
uint32_t get_sample_rate() const
Definition: audio.h:30
size_t ms_to_bytes(uint32_t ms) const
Converts duration to bytes.
Definition: audio.h:73
void deallocate(T *p, size_t n)
Definition: helpers.h:720
virtual bool set_volume(float volume)=0
void status_clear_error()
Definition: component.cpp:172
uint32_t frames_to_microseconds(uint32_t frames) const
Computes the duration, in microseconds, the given amount of frames represents.
Definition: audio.cpp:22
i2s_bits_per_sample_t bits_per_sample_
Definition: i2s_audio.h:27
std::string size_t len
Definition: helpers.h:301
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
audio_dac::AudioDac * audio_dac_
Definition: speaker.h:123
void delete_task_(size_t buffer_size)
Deletes the speaker&#39;s task.
std::shared_ptr< RingBuffer > audio_ring_buffer_
uint16_t length
Definition: tt21100.cpp:12
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
i2s_bits_per_chan_t bits_per_channel_
Definition: i2s_audio.h:28
uint32_t bytes_to_frames(size_t bytes) const
Convert bytes to frames.
Definition: audio.h:43
An STL allocator that uses SPI or internal RAM.
Definition: helpers.h:683
static std::unique_ptr< RingBuffer > create(size_t len)
Definition: ring_buffer.cpp:22
audio::AudioStreamInfo audio_stream_info_
Definition: speaker.h:118
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26