5#include <driver/i2s_std.h>
19static const uint32_t DMA_BUFFER_DURATION_MS = 15;
20static const size_t DMA_BUFFERS_COUNT = 4;
22static const size_t TASK_STACK_SIZE = 4096;
23static const ssize_t TASK_PRIORITY = 19;
25static const size_t I2S_EVENT_QUEUE_COUNT = DMA_BUFFERS_COUNT + 1;
27static const char *
const TAG =
"i2s_audio.speaker";
50static const std::vector<int16_t> Q15_VOLUME_SCALING_FACTORS = {
51 0, 116, 122, 130, 137, 146, 154, 163, 173, 183, 194, 206, 218, 231, 244,
52 259, 274, 291, 308, 326, 345, 366, 388, 411, 435, 461, 488, 517, 548, 580,
53 615, 651, 690, 731, 774, 820, 868, 920, 974, 1032, 1094, 1158, 1227, 1300, 1377,
54 1459, 1545, 1637, 1734, 1837, 1946, 2061, 2184, 2313, 2450, 2596, 2750, 2913, 3085, 3269,
55 3462, 3668, 3885, 4116, 4360, 4619, 4893, 5183, 5490, 5816, 6161, 6527, 6914, 7324, 7758,
56 8218, 8706, 9222, 9770, 10349, 10963, 11613, 12302, 13032, 13805, 14624, 15491, 16410, 17384, 18415,
57 19508, 20665, 21891, 23189, 24565, 26022, 27566, 29201, 30933, 32767};
63 ESP_LOGE(TAG,
"Failed to create event group");
73 " Buffer duration: %" PRIu32,
76 ESP_LOGCONFIG(TAG,
" Timeout: %" PRIu32
" ms", this->
timeout_.value());
78 ESP_LOGCONFIG(TAG,
" Communication format: %s", this->
i2s_comm_fmt_.c_str());
86 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::COMMAND_START);
91 ESP_LOGD(TAG,
"Starting");
92 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::TASK_STARTING);
95 ESP_LOGD(TAG,
"Started");
96 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::TASK_RUNNING);
100 ESP_LOGD(TAG,
"Stopping");
101 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::TASK_STOPPING);
105 ESP_LOGD(TAG,
"Stopped");
119 ESP_LOGE(TAG,
"Not enough memory");
120 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
125 ESP_LOGW(TAG,
"Event dropped, synchronized playback accuracy is reduced");
126 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::WARN_DROPPED_EVENT);
137 ESP_LOGE(TAG,
"Driver failed to start; retrying in 1 second");
143 xTaskCreate(I2SAudioSpeaker::speaker_task,
"speaker_task", TASK_STACK_SIZE, (
void *)
this, TASK_PRIORITY,
147 ESP_LOGE(TAG,
"Task failed to start, retrying in 1 second");
201 ESP_LOGE(TAG,
"Setup failed; cannot play audio");
210 vTaskDelay(ticks_to_wait);
214 size_t bytes_written = 0;
217 if (temp_ring_buffer.use_count() == 2) {
219 bytes_written = temp_ring_buffer->write_without_replacement((
void *) data,
length, ticks_to_wait);
223 return bytes_written;
229 return temp_ring_buffer->available() > 0;
234void I2SAudioSpeaker::speaker_task(
void *params) {
235 I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params;
239 const uint32_t dma_buffers_duration_ms = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT;
241 const uint32_t ring_buffer_duration = std::max(dma_buffers_duration_ms, this_speaker->buffer_duration_ms_);
244 const size_t ring_buffer_size = this_speaker->current_stream_info_.ms_to_bytes(ring_buffer_duration);
246 const uint32_t frames_to_fill_single_dma_buffer =
247 this_speaker->current_stream_info_.ms_to_frames(DMA_BUFFER_DURATION_MS);
248 const size_t bytes_to_fill_single_dma_buffer =
249 this_speaker->current_stream_info_.frames_to_bytes(frames_to_fill_single_dma_buffer);
251 bool successful_setup =
false;
252 std::unique_ptr<audio::AudioSourceTransferBuffer> transfer_buffer =
255 if (transfer_buffer !=
nullptr) {
257 if (temp_ring_buffer.use_count() == 1) {
258 transfer_buffer->set_source(temp_ring_buffer);
259 this_speaker->audio_ring_buffer_ = temp_ring_buffer;
260 successful_setup =
true;
264 if (!successful_setup) {
267 bool stop_gracefully =
false;
268 bool tx_dma_underflow =
true;
275 while (this_speaker->pause_state_ || !this_speaker->timeout_.has_value() ||
276 (
millis() - last_data_received_time) <= this_speaker->timeout_.value()) {
277 uint32_t event_group_bits = xEventGroupGetBits(this_speaker->event_group_);
285 stop_gracefully =
true;
288 if (this_speaker->audio_stream_info_ != this_speaker->current_stream_info_) {
292 int64_t write_timestamp;
293 while (xQueueReceive(this_speaker->i2s_event_queue_, &write_timestamp, 0)) {
296 uint32_t frames_sent = frames_to_fill_single_dma_buffer;
297 if (frames_to_fill_single_dma_buffer > frames_written) {
298 tx_dma_underflow =
true;
299 frames_sent = frames_written;
300 const uint32_t frames_zeroed = frames_to_fill_single_dma_buffer - frames_written;
301 write_timestamp -= this_speaker->current_stream_info_.frames_to_microseconds(frames_zeroed);
303 tx_dma_underflow =
false;
305 frames_written -= frames_sent;
306 if (frames_sent > 0) {
307 this_speaker->audio_output_callback_(frames_sent, write_timestamp);
311 if (this_speaker->pause_state_) {
314 vTaskDelay(pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS));
321 (this_speaker->current_stream_info_.frames_to_microseconds(frames_written) / 1000) / 2;
323 size_t bytes_read = transfer_buffer->transfer_data_from_source(pdMS_TO_TICKS(read_delay));
324 uint8_t *
new_data = transfer_buffer->get_buffer_end() - bytes_read;
326 if (bytes_read > 0) {
327 if (this_speaker->q15_volume_factor_ < INT16_MAX) {
331 const size_t bytes_per_sample = this_speaker->current_stream_info_.samples_to_bytes(1);
332 const uint32_t len = bytes_read / bytes_per_sample;
336 int32_t gain_factor = this_speaker->q15_volume_factor_;
338 if (bytes_per_sample >= 3) {
349 sample *= gain_factor;
354#ifdef USE_ESP32_VARIANT_ESP32
356 if (this_speaker->current_stream_info_.get_channels() == 1 &&
357 this_speaker->current_stream_info_.get_bits_per_sample() == 16) {
358 int16_t *samples =
reinterpret_cast<int16_t *
>(
new_data);
359 size_t sample_count = bytes_read /
sizeof(int16_t);
360 for (
size_t i = 0; i + 1 < sample_count; i += 2) {
361 int16_t tmp = samples[i];
362 samples[i] = samples[i + 1];
363 samples[i + 1] = tmp;
369 if (transfer_buffer->available() == 0) {
370 if (stop_gracefully && tx_dma_underflow) {
373 vTaskDelay(pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS / 2));
375 size_t bytes_written = 0;
376 if (tx_dma_underflow) {
379 i2s_channel_disable(this_speaker->tx_handle_);
380 const i2s_event_callbacks_t callbacks = {
384 i2s_channel_register_event_callback(this_speaker->tx_handle_, &callbacks, this_speaker);
385 i2s_channel_preload_data(this_speaker->tx_handle_, transfer_buffer->get_buffer_start(),
386 transfer_buffer->available(), &bytes_written);
389 i2s_channel_write(this_speaker->tx_handle_, transfer_buffer->get_buffer_start(), transfer_buffer->available(),
390 &bytes_written, DMA_BUFFER_DURATION_MS);
392 if (bytes_written > 0) {
393 last_data_received_time =
millis();
394 frames_written += this_speaker->current_stream_info_.bytes_to_frames(bytes_written);
395 transfer_buffer->decrease_buffer_length(bytes_written);
396 if (tx_dma_underflow) {
397 tx_dma_underflow =
false;
402 xQueueReset(this_speaker->i2s_event_queue_);
404 const i2s_event_callbacks_t callbacks = {
407 i2s_channel_register_event_callback(this_speaker->tx_handle_, &callbacks, this_speaker);
409 i2s_channel_enable(this_speaker->tx_handle_);
418 if (transfer_buffer !=
nullptr) {
419 transfer_buffer.reset();
426 vTaskDelay(pdMS_TO_TICKS(10));
450 xEventGroupSetBits(this->
event_group_, SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY);
452 xEventGroupSetBits(this->
event_group_, SpeakerEventGroupBits::COMMAND_STOP);
461 ESP_LOGE(TAG,
"Audio stream settings are not compatible with this I2S configuration");
462 return ESP_ERR_NOT_SUPPORTED;
468 ESP_LOGE(TAG,
"Audio streams with more bits per sample than the I2S speaker's configuration is not supported");
469 return ESP_ERR_NOT_SUPPORTED;
472 if (!this->
parent_->try_lock()) {
473 ESP_LOGE(TAG,
"Parent I2S bus not free");
474 return ESP_ERR_INVALID_STATE;
479 i2s_chan_config_t chan_cfg = {
480 .id = this->
parent_->get_port(),
482 .dma_desc_num = DMA_BUFFERS_COUNT,
483 .dma_frame_num = dma_buffer_length,
488 esp_err_t err = i2s_new_channel(&chan_cfg, &this->
tx_handle_, NULL);
490 ESP_LOGE(TAG,
"Failed to allocate new I2S channel");
495 i2s_clock_src_t clk_src = I2S_CLK_SRC_DEFAULT;
496#ifdef I2S_CLK_SRC_APLL
498 clk_src = I2S_CLK_SRC_APLL;
501 i2s_std_gpio_config_t pin_config = this->
parent_->get_pin_config();
503 i2s_std_clk_config_t clk_cfg = {
512 slot_mode = I2S_SLOT_MODE_MONO;
514 slot_mode = I2S_SLOT_MODE_STEREO;
515 slot_mask = I2S_STD_SLOT_BOTH;
518 i2s_std_slot_config_t std_slot_cfg;
521 I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(), slot_mode);
524 I2S_STD_PCM_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(), slot_mode);
527 I2S_STD_MSB_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(), slot_mode);
529#ifdef USE_ESP32_VARIANT_ESP32
535 std_slot_cfg.ws_width = configured_bit_width;
536 if (configured_bit_width > 16) {
537 std_slot_cfg.msb_right =
false;
543 std_slot_cfg.slot_mask = slot_mask;
547 i2s_std_config_t std_cfg = {
549 .slot_cfg = std_slot_cfg,
550 .gpio_cfg = pin_config,
553 err = i2s_channel_init_std_mode(this->
tx_handle_, &std_cfg);
556 ESP_LOGE(TAG,
"Failed to initialize channel");
563 this->
i2s_event_queue_ = xQueueCreate(I2S_EVENT_QUEUE_COUNT,
sizeof(int64_t));
572 int64_t now = esp_timer_get_time();
574 BaseType_t need_yield1 = pdFALSE;
575 BaseType_t need_yield2 = pdFALSE;
576 BaseType_t need_yield3 = pdFALSE;
587 xQueueSendToBackFromISR(this_speaker->
i2s_event_queue_, &now, &need_yield3);
589 return need_yield1 | need_yield2 | need_yield3;
void mark_failed()
Mark this component as failed.
void status_momentary_error(const char *name, uint32_t length=5000)
Set error status flag and automatically clear it after a timeout.
void status_clear_error()
bool status_has_error() const
I2SAudioComponent * parent_
static std::unique_ptr< RingBuffer > create(size_t len)
static std::unique_ptr< AudioSourceTransferBuffer > create(size_t buffer_size)
Creates a new source transfer buffer.
uint8_t get_bits_per_sample() const
uint8_t get_channels() const
uint32_t ms_to_frames(uint32_t ms) const
Converts duration to frames.
uint32_t get_sample_rate() const
virtual bool set_mute_off()=0
virtual bool set_volume(float volume)=0
virtual bool set_mute_on()=0
i2s_std_slot_mask_t std_slot_mask_
i2s_slot_bit_width_t slot_bit_width_
i2s_slot_mode_t slot_mode_
i2s_mclk_multiple_t mclk_multiple_
esp_err_t start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info)
Starts the ESP32 I2S driver.
TaskHandle_t speaker_task_handle_
static bool i2s_on_sent_cb(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx)
Callback function used to send playback timestamps the to the speaker task.
int16_t q15_volume_factor_
void stop_(bool wait_on_empty)
Plays the provided audio data.
void stop_i2s_driver_()
Stops the I2S driver and unlocks the I2S port.
std::weak_ptr< RingBuffer > audio_ring_buffer_
void dump_config() override
optional< uint32_t > timeout_
uint32_t buffer_duration_ms_
std::string i2s_comm_fmt_
i2s_chan_handle_t tx_handle_
audio::AudioStreamInfo current_stream_info_
QueueHandle_t i2s_event_queue_
EventGroupHandle_t event_group_
virtual size_t play(const uint8_t *data, size_t length)=0
Plays the provided audio data.
virtual void set_volume(float volume)
audio_dac::AudioDac * audio_dac_
virtual void set_mute_state(bool mute_state)
virtual bool has_buffered_data() const =0
audio::AudioStreamInfo audio_stream_info_
int32_t unpack_audio_sample_to_q31(const uint8_t *data, size_t bytes_per_sample)
Unpacks a quantized audio sample into a Q31 fixed-point number.
void pack_q31_as_audio_sample(int32_t sample, uint8_t *data, size_t bytes_per_sample)
Packs a Q31 fixed-point number as an audio sample with the specified number of bytes per sample.
@ COMMAND_STOP_GRACEFULLY
Providing packet encoding functions for exchanging data with a remote host.
uint32_t IRAM_ATTR HOT millis()
T remap(U value, U min, U max, T min_out, T max_out)
Remap value from the range (min, max) to (min_out, max_out).