ESPHome 2025.9.0-dev
Loading...
Searching...
No Matches
i2s_audio_speaker.cpp
Go to the documentation of this file.
1#include "i2s_audio_speaker.h"
2
3#ifdef USE_ESP32
4
5#ifdef USE_I2S_LEGACY
6#include <driver/i2s.h>
7#else
8#include <driver/i2s_std.h>
9#endif
10
13
15#include "esphome/core/hal.h"
16#include "esphome/core/log.h"
17
18#include "esp_timer.h"
19
20namespace esphome {
21namespace i2s_audio {
22
23static const uint32_t DMA_BUFFER_DURATION_MS = 15;
24static const size_t DMA_BUFFERS_COUNT = 4;
25
26static const size_t TASK_STACK_SIZE = 4096;
27static const ssize_t TASK_PRIORITY = 19;
28
29static const size_t I2S_EVENT_QUEUE_COUNT = DMA_BUFFERS_COUNT + 1;
30
31static const char *const TAG = "i2s_audio.speaker";
32
33enum SpeakerEventGroupBits : uint32_t {
34 COMMAND_START = (1 << 0), // indicates loop should start speaker task
35 COMMAND_STOP = (1 << 1), // stops the speaker task
36 COMMAND_STOP_GRACEFULLY = (1 << 2), // Stops the speaker task once all data has been written
37
38 TASK_STARTING = (1 << 10),
39 TASK_RUNNING = (1 << 11),
40 TASK_STOPPING = (1 << 12),
41 TASK_STOPPED = (1 << 13),
42
43 ERR_ESP_NO_MEM = (1 << 19),
44
45 WARN_DROPPED_EVENT = (1 << 20),
46
47 ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
48};
49
50// Lists the Q15 fixed point scaling factor for volume reduction.
51// Has 100 values representing silence and a reduction [49, 48.5, ... 0.5, 0] dB.
52// dB to PCM scaling factor formula: floating_point_scale_factor = 2^(-db/6.014)
53// float to Q15 fixed point formula: q15_scale_factor = floating_point_scale_factor * 2^(15)
54static const std::vector<int16_t> Q15_VOLUME_SCALING_FACTORS = {
55 0, 116, 122, 130, 137, 146, 154, 163, 173, 183, 194, 206, 218, 231, 244,
56 259, 274, 291, 308, 326, 345, 366, 388, 411, 435, 461, 488, 517, 548, 580,
57 615, 651, 690, 731, 774, 820, 868, 920, 974, 1032, 1094, 1158, 1227, 1300, 1377,
58 1459, 1545, 1637, 1734, 1837, 1946, 2061, 2184, 2313, 2450, 2596, 2750, 2913, 3085, 3269,
59 3462, 3668, 3885, 4116, 4360, 4619, 4893, 5183, 5490, 5816, 6161, 6527, 6914, 7324, 7758,
60 8218, 8706, 9222, 9770, 10349, 10963, 11613, 12302, 13032, 13805, 14624, 15491, 16410, 17384, 18415,
61 19508, 20665, 21891, 23189, 24565, 26022, 27566, 29201, 30933, 32767};
62
64 this->event_group_ = xEventGroupCreate();
65
66 if (this->event_group_ == nullptr) {
67 ESP_LOGE(TAG, "Failed to create event group");
68 this->mark_failed();
69 return;
70 }
71}
72
74 ESP_LOGCONFIG(TAG,
75 "Speaker:\n"
76 " Pin: %d\n"
77 " Buffer duration: %" PRIu32,
78 static_cast<int8_t>(this->dout_pin_), this->buffer_duration_ms_);
79 if (this->timeout_.has_value()) {
80 ESP_LOGCONFIG(TAG, " Timeout: %" PRIu32 " ms", this->timeout_.value());
81 }
82#ifdef USE_I2S_LEGACY
83#if SOC_I2S_SUPPORTS_DAC
84 ESP_LOGCONFIG(TAG, " Internal DAC mode: %d", static_cast<int8_t>(this->internal_dac_mode_));
85#endif
86 ESP_LOGCONFIG(TAG, " Communication format: %d", static_cast<int8_t>(this->i2s_comm_fmt_));
87#else
88 ESP_LOGCONFIG(TAG, " Communication format: %s", this->i2s_comm_fmt_.c_str());
89#endif
90}
91
93 uint32_t event_group_bits = xEventGroupGetBits(this->event_group_);
94
95 if ((event_group_bits & SpeakerEventGroupBits::COMMAND_START) && (this->state_ == speaker::STATE_STOPPED)) {
97 xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::COMMAND_START);
98 }
99
100 // Handle the task's state
101 if (event_group_bits & SpeakerEventGroupBits::TASK_STARTING) {
102 ESP_LOGD(TAG, "Starting");
103 xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::TASK_STARTING);
104 }
105 if (event_group_bits & SpeakerEventGroupBits::TASK_RUNNING) {
106 ESP_LOGD(TAG, "Started");
107 xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::TASK_RUNNING);
109 }
110 if (event_group_bits & SpeakerEventGroupBits::TASK_STOPPING) {
111 ESP_LOGD(TAG, "Stopping");
112 xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::TASK_STOPPING);
114 }
115 if (event_group_bits & SpeakerEventGroupBits::TASK_STOPPED) {
116 ESP_LOGD(TAG, "Stopped");
117
118 vTaskDelete(this->speaker_task_handle_);
119 this->speaker_task_handle_ = nullptr;
120
121 this->stop_i2s_driver_();
122 xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ALL_BITS);
123 this->status_clear_error();
124
126 }
127
128 // Log any errors encounted by the task
129 if (event_group_bits & SpeakerEventGroupBits::ERR_ESP_NO_MEM) {
130 ESP_LOGE(TAG, "Not enough memory");
131 xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
132 }
133
134 // Warn if any playback timestamp events are dropped, which drastically reduces synced playback accuracy
135 if (event_group_bits & SpeakerEventGroupBits::WARN_DROPPED_EVENT) {
136 ESP_LOGW(TAG, "Event dropped, synchronized playback accuracy is reduced");
137 xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::WARN_DROPPED_EVENT);
138 }
139
140 // Handle the speaker's state
141 switch (this->state_) {
143 if (this->status_has_error()) {
144 break;
145 }
146
147 if (this->start_i2s_driver_(this->audio_stream_info_) != ESP_OK) {
148 ESP_LOGE(TAG, "Driver failed to start; retrying in 1 second");
149 this->status_momentary_error("driver-faiure", 1000);
150 break;
151 }
152
153 if (this->speaker_task_handle_ == nullptr) {
154 xTaskCreate(I2SAudioSpeaker::speaker_task, "speaker_task", TASK_STACK_SIZE, (void *) this, TASK_PRIORITY,
155 &this->speaker_task_handle_);
156
157 if (this->speaker_task_handle_ == nullptr) {
158 ESP_LOGE(TAG, "Task failed to start, retrying in 1 second");
159 this->status_momentary_error("task-failure", 1000);
160 this->stop_i2s_driver_(); // Stops the driver to return the lock; will be reloaded in next attempt
161 }
162 }
163 break;
164 case speaker::STATE_RUNNING: // Intentional fallthrough
165 case speaker::STATE_STOPPING: // Intentional fallthrough
167 break;
168 }
169}
170
171void I2SAudioSpeaker::set_volume(float volume) {
172 this->volume_ = volume;
173#ifdef USE_AUDIO_DAC
174 if (this->audio_dac_ != nullptr) {
175 if (volume > 0.0) {
176 this->audio_dac_->set_mute_off();
177 }
178 this->audio_dac_->set_volume(volume);
179 } else
180#endif
181 {
182 // Fallback to software volume control by using a Q15 fixed point scaling factor
183 ssize_t decibel_index = remap<ssize_t, float>(volume, 0.0f, 1.0f, 0, Q15_VOLUME_SCALING_FACTORS.size() - 1);
184 this->q15_volume_factor_ = Q15_VOLUME_SCALING_FACTORS[decibel_index];
185 }
186}
187
188void I2SAudioSpeaker::set_mute_state(bool mute_state) {
189 this->mute_state_ = mute_state;
190#ifdef USE_AUDIO_DAC
191 if (this->audio_dac_) {
192 if (mute_state) {
193 this->audio_dac_->set_mute_on();
194 } else {
195 this->audio_dac_->set_mute_off();
196 }
197 } else
198#endif
199 {
200 if (mute_state) {
201 // Fallback to software volume control and scale by 0
202 this->q15_volume_factor_ = 0;
203 } else {
204 // Revert to previous volume when unmuting
205 this->set_volume(this->volume_);
206 }
207 }
208}
209
210size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) {
211 if (this->is_failed()) {
212 ESP_LOGE(TAG, "Setup failed; cannot play audio");
213 return 0;
214 }
216 this->start();
217 }
218
219 if (this->state_ != speaker::STATE_RUNNING) {
220 // Unable to write data to a running speaker, so delay the max amount of time so it can get ready
221 vTaskDelay(ticks_to_wait);
222 ticks_to_wait = 0;
223 }
224
225 size_t bytes_written = 0;
226 if (this->state_ == speaker::STATE_RUNNING) {
227 std::shared_ptr<RingBuffer> temp_ring_buffer = this->audio_ring_buffer_.lock();
228 if (temp_ring_buffer.use_count() == 2) {
229 // Only the speaker task and this temp_ring_buffer own the ring buffer, so its safe to write to
230 bytes_written = temp_ring_buffer->write_without_replacement((void *) data, length, ticks_to_wait);
231 }
232 }
233
234 return bytes_written;
235}
236
238 if (this->audio_ring_buffer_.use_count() > 0) {
239 std::shared_ptr<RingBuffer> temp_ring_buffer = this->audio_ring_buffer_.lock();
240 return temp_ring_buffer->available() > 0;
241 }
242 return false;
243}
244
245void I2SAudioSpeaker::speaker_task(void *params) {
246 I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params;
247
248 xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::TASK_STARTING);
249
250 const uint32_t dma_buffers_duration_ms = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT;
251 // Ensure ring buffer duration is at least the duration of all DMA buffers
252 const uint32_t ring_buffer_duration = std::max(dma_buffers_duration_ms, this_speaker->buffer_duration_ms_);
253
254 // The DMA buffers may have more bits per sample, so calculate buffer sizes based in the input audio stream info
255 const size_t ring_buffer_size = this_speaker->current_stream_info_.ms_to_bytes(ring_buffer_duration);
256
257 const uint32_t frames_to_fill_single_dma_buffer =
258 this_speaker->current_stream_info_.ms_to_frames(DMA_BUFFER_DURATION_MS);
259 const size_t bytes_to_fill_single_dma_buffer =
260 this_speaker->current_stream_info_.frames_to_bytes(frames_to_fill_single_dma_buffer);
261
262 bool successful_setup = false;
263 std::unique_ptr<audio::AudioSourceTransferBuffer> transfer_buffer =
264 audio::AudioSourceTransferBuffer::create(bytes_to_fill_single_dma_buffer);
265
266 if (transfer_buffer != nullptr) {
267 std::shared_ptr<RingBuffer> temp_ring_buffer = RingBuffer::create(ring_buffer_size);
268 if (temp_ring_buffer.use_count() == 1) {
269 transfer_buffer->set_source(temp_ring_buffer);
270 this_speaker->audio_ring_buffer_ = temp_ring_buffer;
271 successful_setup = true;
272 }
273 }
274
275 if (!successful_setup) {
276 xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
277 } else {
278 bool stop_gracefully = false;
279 bool tx_dma_underflow = true;
280
281 uint32_t frames_written = 0;
282 uint32_t last_data_received_time = millis();
283
284 xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::TASK_RUNNING);
285
286 while (this_speaker->pause_state_ || !this_speaker->timeout_.has_value() ||
287 (millis() - last_data_received_time) <= this_speaker->timeout_.value()) {
288 uint32_t event_group_bits = xEventGroupGetBits(this_speaker->event_group_);
289
290 if (event_group_bits & SpeakerEventGroupBits::COMMAND_STOP) {
291 xEventGroupClearBits(this_speaker->event_group_, SpeakerEventGroupBits::COMMAND_STOP);
292 break;
293 }
294 if (event_group_bits & SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY) {
295 xEventGroupClearBits(this_speaker->event_group_, SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY);
296 stop_gracefully = true;
297 }
298
299 if (this_speaker->audio_stream_info_ != this_speaker->current_stream_info_) {
300 // Audio stream info changed, stop the speaker task so it will restart with the proper settings.
301 break;
302 }
303#ifdef USE_I2S_LEGACY
304 i2s_event_t i2s_event;
305 while (xQueueReceive(this_speaker->i2s_event_queue_, &i2s_event, 0)) {
306 if (i2s_event.type == I2S_EVENT_TX_Q_OVF) {
307 tx_dma_underflow = true;
308 }
309 }
310#else
311 int64_t write_timestamp;
312 while (xQueueReceive(this_speaker->i2s_event_queue_, &write_timestamp, 0)) {
313 // Receives timing events from the I2S on_sent callback. If actual audio data was sent in this event, it passes
314 // on the timing info via the audio_output_callback.
315 uint32_t frames_sent = frames_to_fill_single_dma_buffer;
316 if (frames_to_fill_single_dma_buffer > frames_written) {
317 tx_dma_underflow = true;
318 frames_sent = frames_written;
319 const uint32_t frames_zeroed = frames_to_fill_single_dma_buffer - frames_written;
320 write_timestamp -= this_speaker->current_stream_info_.frames_to_microseconds(frames_zeroed);
321 } else {
322 tx_dma_underflow = false;
323 }
324 frames_written -= frames_sent;
325 if (frames_sent > 0) {
326 this_speaker->audio_output_callback_(frames_sent, write_timestamp);
327 }
328 }
329#endif
330
331 if (this_speaker->pause_state_) {
332 // Pause state is accessed atomically, so thread safe
333 // Delay so the task yields, then skip transferring audio data
334 vTaskDelay(pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS));
335 continue;
336 }
337
338 // Wait half the duration of the data already written to the DMA buffers for new audio data
339 // The millisecond helper modifies the frames_written variable, so use the microsecond helper and divide by 1000
340 const uint32_t read_delay =
341 (this_speaker->current_stream_info_.frames_to_microseconds(frames_written) / 1000) / 2;
342
343 uint8_t *new_data = transfer_buffer->get_buffer_end(); // track start of any newly copied bytes
344 size_t bytes_read = transfer_buffer->transfer_data_from_source(pdMS_TO_TICKS(read_delay));
345
346 if (bytes_read > 0) {
347 if (this_speaker->q15_volume_factor_ < INT16_MAX) {
348 // Apply the software volume adjustment by unpacking the sample into a Q31 fixed-point number, shifting it,
349 // multiplying by the volume factor, and packing the sample back into the original bytes per sample.
350
351 const size_t bytes_per_sample = this_speaker->current_stream_info_.samples_to_bytes(1);
352 const uint32_t len = bytes_read / bytes_per_sample;
353
354 // Use Q16 for samples with 1 or 2 bytes: shifted_sample * gain_factor is Q16 * Q15 -> Q31
355 int32_t shift = 15; // Q31 -> Q16
356 int32_t gain_factor = this_speaker->q15_volume_factor_; // Q15
357
358 if (bytes_per_sample >= 3) {
359 // Use Q23 for samples with 3 or 4 bytes: shifted_sample * gain_factor is Q23 * Q8 -> Q31
360
361 shift = 8; // Q31 -> Q23
362 gain_factor >>= 7; // Q15 -> Q8
363 }
364
365 for (uint32_t i = 0; i < len; ++i) {
366 int32_t sample =
367 audio::unpack_audio_sample_to_q31(&new_data[i * bytes_per_sample], bytes_per_sample); // Q31
368 sample >>= shift;
369 sample *= gain_factor; // Q31
370 audio::pack_q31_as_audio_sample(sample, &new_data[i * bytes_per_sample], bytes_per_sample);
371 }
372 }
373
374#ifdef USE_ESP32_VARIANT_ESP32
375 // For ESP32 8/16 bit mono mode samples need to be switched.
376 if (this_speaker->current_stream_info_.get_channels() == 1 &&
377 this_speaker->current_stream_info_.get_bits_per_sample() <= 16) {
378 size_t len = bytes_read / sizeof(int16_t);
379 int16_t *tmp_buf = (int16_t *) new_data;
380 for (int i = 0; i < len; i += 2) {
381 int16_t tmp = tmp_buf[i];
382 tmp_buf[i] = tmp_buf[i + 1];
383 tmp_buf[i + 1] = tmp;
384 }
385 }
386#endif
387 }
388
389 if (transfer_buffer->available() == 0) {
390 if (stop_gracefully && tx_dma_underflow) {
391 break;
392 }
393 vTaskDelay(pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS / 2));
394 } else {
395 size_t bytes_written = 0;
396#ifdef USE_I2S_LEGACY
397 if (this_speaker->current_stream_info_.get_bits_per_sample() == (uint8_t) this_speaker->bits_per_sample_) {
398 i2s_write(this_speaker->parent_->get_port(), transfer_buffer->get_buffer_start(),
399 transfer_buffer->available(), &bytes_written, pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS));
400 } else if (this_speaker->current_stream_info_.get_bits_per_sample() <
401 (uint8_t) this_speaker->bits_per_sample_) {
402 i2s_write_expand(this_speaker->parent_->get_port(), transfer_buffer->get_buffer_start(),
403 transfer_buffer->available(), this_speaker->current_stream_info_.get_bits_per_sample(),
404 this_speaker->bits_per_sample_, &bytes_written, pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS));
405 }
406#else
407 if (tx_dma_underflow) {
408 // Temporarily disable channel and callback to reset the I2S driver's internal DMA buffer queue so timing
409 // callbacks are accurate. Preload the data.
410 i2s_channel_disable(this_speaker->tx_handle_);
411 const i2s_event_callbacks_t callbacks = {
412 .on_sent = nullptr,
413 };
414
415 i2s_channel_register_event_callback(this_speaker->tx_handle_, &callbacks, this_speaker);
416 i2s_channel_preload_data(this_speaker->tx_handle_, transfer_buffer->get_buffer_start(),
417 transfer_buffer->available(), &bytes_written);
418 } else {
419 // Audio is already playing, use regular I2S write to add to the DMA buffers
420 i2s_channel_write(this_speaker->tx_handle_, transfer_buffer->get_buffer_start(), transfer_buffer->available(),
421 &bytes_written, DMA_BUFFER_DURATION_MS);
422 }
423#endif
424 if (bytes_written > 0) {
425 last_data_received_time = millis();
426 frames_written += this_speaker->current_stream_info_.bytes_to_frames(bytes_written);
427 transfer_buffer->decrease_buffer_length(bytes_written);
428 if (tx_dma_underflow) {
429 tx_dma_underflow = false;
430#ifndef USE_I2S_LEGACY
431 // Reset the event queue timestamps
432 // Enable the on_sent callback to accurately track the timestamps of played audio
433 // Enable the I2S channel to start sending the preloaded audio
434
435 xQueueReset(this_speaker->i2s_event_queue_);
436
437 const i2s_event_callbacks_t callbacks = {
438 .on_sent = i2s_on_sent_cb,
439 };
440 i2s_channel_register_event_callback(this_speaker->tx_handle_, &callbacks, this_speaker);
441
442 i2s_channel_enable(this_speaker->tx_handle_);
443#endif
444 }
445#ifdef USE_I2S_LEGACY
446 // The legacy driver doesn't easily support the callback approach for timestamps, so fall back to a direct but
447 // less accurate approach.
448 this_speaker->audio_output_callback_(this_speaker->current_stream_info_.bytes_to_frames(bytes_written),
449 esp_timer_get_time() + dma_buffers_duration_ms * 1000);
450#endif
451 }
452 }
453 }
454 }
455
456 xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::TASK_STOPPING);
457
458 if (transfer_buffer != nullptr) {
459 transfer_buffer.reset();
460 }
461
462 xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::TASK_STOPPED);
463
464 while (true) {
465 // Continuously delay until the loop method deletes the task
466 vTaskDelay(pdMS_TO_TICKS(10));
467 }
468}
469
471 if (!this->is_ready() || this->is_failed() || this->status_has_error())
472 return;
473 if ((this->state_ == speaker::STATE_STARTING) || (this->state_ == speaker::STATE_RUNNING))
474 return;
475
476 xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_START);
477}
478
479void I2SAudioSpeaker::stop() { this->stop_(false); }
480
481void I2SAudioSpeaker::finish() { this->stop_(true); }
482
483void I2SAudioSpeaker::stop_(bool wait_on_empty) {
484 if (this->is_failed())
485 return;
486 if (this->state_ == speaker::STATE_STOPPED)
487 return;
488
489 if (wait_on_empty) {
490 xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY);
491 } else {
492 xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_STOP);
493 }
494}
495
496esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info) {
497 this->current_stream_info_ = audio_stream_info; // store the stream info settings the driver will use
498
499#ifdef USE_I2S_LEGACY
500 if ((this->i2s_mode_ & I2S_MODE_SLAVE) && (this->sample_rate_ != audio_stream_info.get_sample_rate())) { // NOLINT
501#else
502 if ((this->i2s_role_ & I2S_ROLE_SLAVE) && (this->sample_rate_ != audio_stream_info.get_sample_rate())) { // NOLINT
503#endif
504 // Can't reconfigure I2S bus, so the sample rate must match the configured value
505 ESP_LOGE(TAG, "Audio stream settings are not compatible with this I2S configuration");
506 return ESP_ERR_NOT_SUPPORTED;
507 }
508
509#ifdef USE_I2S_LEGACY
510 if ((i2s_bits_per_sample_t) audio_stream_info.get_bits_per_sample() > this->bits_per_sample_) {
511#else
512 if (this->slot_bit_width_ != I2S_SLOT_BIT_WIDTH_AUTO &&
513 (i2s_slot_bit_width_t) audio_stream_info.get_bits_per_sample() > this->slot_bit_width_) {
514#endif
515 // Currently can't handle the case when the incoming audio has more bits per sample than the configured value
516 ESP_LOGE(TAG, "Audio streams with more bits per sample than the I2S speaker's configuration is not supported");
517 return ESP_ERR_NOT_SUPPORTED;
518 }
519
520 if (!this->parent_->try_lock()) {
521 ESP_LOGE(TAG, "Parent I2S bus not free");
522 return ESP_ERR_INVALID_STATE;
523 }
524
525 uint32_t dma_buffer_length = audio_stream_info.ms_to_frames(DMA_BUFFER_DURATION_MS);
526
527#ifdef USE_I2S_LEGACY
528 i2s_channel_fmt_t channel = this->channel_;
529
530 if (audio_stream_info.get_channels() == 1) {
531 if (this->channel_ == I2S_CHANNEL_FMT_ONLY_LEFT) {
532 channel = I2S_CHANNEL_FMT_ONLY_LEFT;
533 } else {
534 channel = I2S_CHANNEL_FMT_ONLY_RIGHT;
535 }
536 } else if (audio_stream_info.get_channels() == 2) {
537 channel = I2S_CHANNEL_FMT_RIGHT_LEFT;
538 }
539
540 i2s_driver_config_t config = {
541 .mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX),
542 .sample_rate = audio_stream_info.get_sample_rate(),
543 .bits_per_sample = this->bits_per_sample_,
544 .channel_format = channel,
545 .communication_format = this->i2s_comm_fmt_,
546 .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
547 .dma_buf_count = DMA_BUFFERS_COUNT,
548 .dma_buf_len = (int) dma_buffer_length,
549 .use_apll = this->use_apll_,
550 .tx_desc_auto_clear = true,
551 .fixed_mclk = I2S_PIN_NO_CHANGE,
552 .mclk_multiple = this->mclk_multiple_,
553 .bits_per_chan = this->bits_per_channel_,
554#if SOC_I2S_SUPPORTS_TDM
555 .chan_mask = (i2s_channel_t) (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1),
556 .total_chan = 2,
557 .left_align = false,
558 .big_edin = false,
559 .bit_order_msb = false,
560 .skip_msk = false,
561#endif
562 };
563#if SOC_I2S_SUPPORTS_DAC
564 if (this->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) {
565 config.mode = (i2s_mode_t) (config.mode | I2S_MODE_DAC_BUILT_IN);
566 }
567#endif
568
569 esp_err_t err =
570 i2s_driver_install(this->parent_->get_port(), &config, I2S_EVENT_QUEUE_COUNT, &this->i2s_event_queue_);
571 if (err != ESP_OK) {
572 ESP_LOGE(TAG, "Failed to install I2S legacy driver");
573 // Failed to install the driver, so unlock the I2S port
574 this->parent_->unlock();
575 return err;
576 }
577
578#if SOC_I2S_SUPPORTS_DAC
579 if (this->internal_dac_mode_ == I2S_DAC_CHANNEL_DISABLE) {
580#endif
581 i2s_pin_config_t pin_config = this->parent_->get_pin_config();
582 pin_config.data_out_num = this->dout_pin_;
583
584 err = i2s_set_pin(this->parent_->get_port(), &pin_config);
585#if SOC_I2S_SUPPORTS_DAC
586 } else {
587 i2s_set_dac_mode(this->internal_dac_mode_);
588 }
589#endif
590
591 if (err != ESP_OK) {
592 // Failed to set the data out pin, so uninstall the driver and unlock the I2S port
593 ESP_LOGE(TAG, "Failed to set the data out pin");
594 i2s_driver_uninstall(this->parent_->get_port());
595 this->parent_->unlock();
596 }
597#else
598 i2s_chan_config_t chan_cfg = {
599 .id = this->parent_->get_port(),
600 .role = this->i2s_role_,
601 .dma_desc_num = DMA_BUFFERS_COUNT,
602 .dma_frame_num = dma_buffer_length,
603 .auto_clear = true,
604 .intr_priority = 3,
605 };
606 /* Allocate a new TX channel and get the handle of this channel */
607 esp_err_t err = i2s_new_channel(&chan_cfg, &this->tx_handle_, NULL);
608 if (err != ESP_OK) {
609 ESP_LOGE(TAG, "Failed to allocate new I2S channel");
610 this->parent_->unlock();
611 return err;
612 }
613
614 i2s_clock_src_t clk_src = I2S_CLK_SRC_DEFAULT;
615#ifdef I2S_CLK_SRC_APLL
616 if (this->use_apll_) {
617 clk_src = I2S_CLK_SRC_APLL;
618 }
619#endif
620 i2s_std_gpio_config_t pin_config = this->parent_->get_pin_config();
621
622 i2s_std_clk_config_t clk_cfg = {
623 .sample_rate_hz = audio_stream_info.get_sample_rate(),
624 .clk_src = clk_src,
625 .mclk_multiple = this->mclk_multiple_,
626 };
627
628 i2s_slot_mode_t slot_mode = this->slot_mode_;
629 i2s_std_slot_mask_t slot_mask = this->std_slot_mask_;
630 if (audio_stream_info.get_channels() == 1) {
631 slot_mode = I2S_SLOT_MODE_MONO;
632 } else if (audio_stream_info.get_channels() == 2) {
633 slot_mode = I2S_SLOT_MODE_STEREO;
634 slot_mask = I2S_STD_SLOT_BOTH;
635 }
636
637 i2s_std_slot_config_t std_slot_cfg;
638 if (this->i2s_comm_fmt_ == "std") {
639 std_slot_cfg =
640 I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.get_bits_per_sample(), slot_mode);
641 } else if (this->i2s_comm_fmt_ == "pcm") {
642 std_slot_cfg =
643 I2S_STD_PCM_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.get_bits_per_sample(), slot_mode);
644 } else {
645 std_slot_cfg =
646 I2S_STD_MSB_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.get_bits_per_sample(), slot_mode);
647 }
648#ifdef USE_ESP32_VARIANT_ESP32
649 // There seems to be a bug on the ESP32 (non-variant) platform where setting the slot bit width higher then the bits
650 // per sample causes the audio to play too fast. Setting the ws_width to the configured slot bit width seems to
651 // make it play at the correct speed while sending more bits per slot.
652 if (this->slot_bit_width_ != I2S_SLOT_BIT_WIDTH_AUTO) {
653 uint32_t configured_bit_width = static_cast<uint32_t>(this->slot_bit_width_);
654 std_slot_cfg.ws_width = configured_bit_width;
655 if (configured_bit_width > 16) {
656 std_slot_cfg.msb_right = false;
657 }
658 }
659#else
660 std_slot_cfg.slot_bit_width = this->slot_bit_width_;
661#endif
662 std_slot_cfg.slot_mask = slot_mask;
663
664 pin_config.dout = this->dout_pin_;
665
666 i2s_std_config_t std_cfg = {
667 .clk_cfg = clk_cfg,
668 .slot_cfg = std_slot_cfg,
669 .gpio_cfg = pin_config,
670 };
671 /* Initialize the channel */
672 err = i2s_channel_init_std_mode(this->tx_handle_, &std_cfg);
673
674 if (err != ESP_OK) {
675 ESP_LOGE(TAG, "Failed to initialize channel");
676 i2s_del_channel(this->tx_handle_);
677 this->tx_handle_ = nullptr;
678 this->parent_->unlock();
679 return err;
680 }
681 if (this->i2s_event_queue_ == nullptr) {
682 this->i2s_event_queue_ = xQueueCreate(I2S_EVENT_QUEUE_COUNT, sizeof(int64_t));
683 }
684
685 i2s_channel_enable(this->tx_handle_);
686#endif
687
688 return err;
689}
690
691#ifndef USE_I2S_LEGACY
692bool IRAM_ATTR I2SAudioSpeaker::i2s_on_sent_cb(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx) {
693 int64_t now = esp_timer_get_time();
694
695 BaseType_t need_yield1 = pdFALSE;
696 BaseType_t need_yield2 = pdFALSE;
697 BaseType_t need_yield3 = pdFALSE;
698
699 I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) user_ctx;
700
701 if (xQueueIsQueueFullFromISR(this_speaker->i2s_event_queue_)) {
702 // Queue is full, so discard the oldest event and set the warning flag to inform the user
703 int64_t dummy;
704 xQueueReceiveFromISR(this_speaker->i2s_event_queue_, &dummy, &need_yield1);
705 xEventGroupSetBitsFromISR(this_speaker->event_group_, SpeakerEventGroupBits::WARN_DROPPED_EVENT, &need_yield2);
706 }
707
708 xQueueSendToBackFromISR(this_speaker->i2s_event_queue_, &now, &need_yield3);
709
710 return need_yield1 | need_yield2 | need_yield3;
711}
712#endif
713
715#ifdef USE_I2S_LEGACY
716 i2s_driver_uninstall(this->parent_->get_port());
717#else
718 i2s_channel_disable(this->tx_handle_);
719 i2s_del_channel(this->tx_handle_);
720 this->tx_handle_ = nullptr;
721#endif
722 this->parent_->unlock();
723}
724
725} // namespace i2s_audio
726} // namespace esphome
727
728#endif // USE_ESP32
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
void status_momentary_error(const std::string &name, uint32_t length=5000)
bool is_ready() const
bool status_has_error() const
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.
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_
Definition i2s_audio.h:45
i2s_slot_bit_width_t slot_bit_width_
Definition i2s_audio.h:46
i2s_bits_per_chan_t bits_per_channel_
Definition i2s_audio.h:41
i2s_mclk_multiple_t mclk_multiple_
Definition i2s_audio.h:50
i2s_bits_per_sample_t bits_per_sample_
Definition i2s_audio.h:40
esp_err_t start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info)
Starts the ESP32 I2S driver.
void stop_(bool wait_on_empty)
Plays the provided audio data.
void stop_i2s_driver_()
Stops the I2S driver and unlocks the I2S port.
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.
std::weak_ptr< RingBuffer > audio_ring_buffer_
audio::AudioStreamInfo current_stream_info_
bool has_value() const
Definition optional.h:92
value_type const & value() const
Definition optional.h:94
virtual size_t play(const uint8_t *data, size_t length)=0
Plays the provided audio data.
virtual void set_volume(float volume)
Definition speaker.h:71
audio_dac::AudioDac * audio_dac_
Definition speaker.h:120
virtual void set_mute_state(bool mute_state)
Definition speaker.h:81
virtual bool has_buffered_data() const =0
audio::AudioStreamInfo audio_stream_info_
Definition speaker.h:115
__int64 ssize_t
Definition httplib.h:175
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.
Definition audio.h:142
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.
Definition audio.h:168
const char *const TAG
Definition spi.cpp:8
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:279
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:28
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).
Definition helpers.h:144
uint16_t length
Definition tt21100.cpp:0