70 const uint32_t dma_buffers_duration_ms = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT;
78 const size_t ring_buffer_size =
85 size_t dma_buffer_bytes;
86 i2s_chan_info_t chan_info;
87 if (i2s_channel_get_info(this->
tx_handle_, &chan_info) == ESP_OK && chan_info.total_dma_buf_size > 0) {
89 dma_buffer_bytes = chan_info.total_dma_buf_size / DMA_BUFFERS_COUNT;
96 bool successful_setup =
false;
98 std::unique_ptr<audio::RingBufferAudioSource> audio_source;
102 uint8_t *silence_buffer = silence_allocator.
allocate(dma_buffer_bytes);
104 if (silence_buffer !=
nullptr) {
105 memset(silence_buffer, 0, dma_buffer_bytes);
111 if (audio_source !=
nullptr) {
114 successful_setup =
true;
118 if (successful_setup) {
122 for (
size_t i = 0; i < DMA_BUFFERS_COUNT; i++) {
123 size_t bytes_loaded = 0;
124 esp_err_t err = i2s_channel_preload_data(this->
tx_handle_, silence_buffer, dma_buffer_bytes, &bytes_loaded);
125 if (err != ESP_OK || bytes_loaded != dma_buffer_bytes) {
126 ESP_LOGV(TAG,
"Failed to preload silence into DMA buffer %u (err=%d, loaded=%u)", (
unsigned) i, (
int) err,
127 (
unsigned) bytes_loaded);
128 successful_setup =
false;
134 ESP_LOGV(TAG,
"Failed to push preload write record");
135 successful_setup =
false;
141 if (successful_setup) {
144 const i2s_event_callbacks_t callbacks = {.on_sent =
i2s_on_sent_cb};
145 i2s_channel_register_event_callback(this->
tx_handle_, &callbacks,
this);
147 if (i2s_channel_enable(this->
tx_handle_) != ESP_OK) {
148 ESP_LOGV(TAG,
"Failed to enable I2S channel");
149 successful_setup =
false;
153 if (!successful_setup) {
156 bool stop_gracefully =
false;
183 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::COMMAND_STOP);
184 ESP_LOGV(TAG,
"Exiting: COMMAND_STOP received");
188 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY);
189 stop_gracefully =
true;
194 ESP_LOGV(TAG,
"Exiting: stream info changed");
201 int64_t write_timestamp;
202 bool lockstep_broken =
false;
207 ESP_LOGV(TAG,
"Event without matching write record");
209 lockstep_broken =
true;
212 if (real_frames > 0) {
213 pending_real_buffers--;
217 const uint32_t silence_frames = frames_per_dma_buffer - real_frames;
218 const int64_t adjusted_ts =
223 if (lockstep_broken) {
231 if (stop_gracefully && audio_source->available() == 0 && !this->has_buffered_data() &&
232 pending_real_buffers == 0) {
233 ESP_LOGV(TAG,
"Exiting: graceful stop complete");
241 size_t bytes_written_total = 0;
242 size_t real_bytes_total = 0;
243 bool partial_write_failure =
false;
246 while (bytes_written_total < dma_buffer_bytes) {
247 size_t bytes_read = audio_source->fill(pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS) / 2,
false);
248 if (bytes_read > 0) {
249 uint8_t *
new_data = audio_source->mutable_data() + audio_source->available() - bytes_read;
254 const size_t to_write = std::min(audio_source->available(), dma_buffer_bytes - bytes_written_total);
262 i2s_channel_write(this->
tx_handle_, audio_source->data(), to_write, &bw, WRITE_TIMEOUT_TICKS);
263 if (bw != to_write) {
266 ESP_LOGV(TAG,
"Partial real audio write: %u of %u bytes", (
unsigned) bw, (
unsigned) to_write);
268 partial_write_failure =
true;
271 audio_source->consume(bw);
272 bytes_written_total += bw;
273 real_bytes_total += bw;
275 if (real_bytes_total > 0) {
276 last_data_received_time =
millis();
280 if (partial_write_failure) {
284 const size_t silence_bytes = dma_buffer_bytes - bytes_written_total;
285 if (silence_bytes > 0) {
287 i2s_channel_write(this->
tx_handle_, silence_buffer, silence_bytes, &bw, WRITE_TIMEOUT_TICKS);
288 if (bw != silence_bytes) {
290 ESP_LOGV(TAG,
"Partial silence write: %u of %u bytes", (
unsigned) bw, (
unsigned) silence_bytes);
301 ESP_LOGV(TAG,
"Exiting: write records queue full");
305 if (real_frames_in_buffer > 0) {
306 pending_real_buffers++;
313 audio_source.reset();
315 if (silence_buffer !=
nullptr) {
316 silence_allocator.
deallocate(silence_buffer, dma_buffer_bytes);
317 silence_buffer =
nullptr;
324 vTaskDelay(pdMS_TO_TICKS(10));
333 ESP_LOGE(TAG,
"Incompatible stream settings");
334 return ESP_ERR_NOT_SUPPORTED;
340 ESP_LOGE(TAG,
"Stream bits per sample must be less than or equal to the speaker's configuration");
341 return ESP_ERR_NOT_SUPPORTED;
344#ifdef USE_ESP32_VARIANT_ESP32
350 ESP_LOGE(TAG,
"ESP32 supports only 16- or 32-bit audio, got %u-bit",
352 return ESP_ERR_NOT_SUPPORTED;
356 if (!this->
parent_->try_lock()) {
357 ESP_LOGE(TAG,
"Parent bus is busy");
358 return ESP_ERR_INVALID_STATE;
361 uint32_t dma_buffer_length = dma_buffer_frames(audio_stream_info);
364 i2s_clock_src_t clk_src = I2S_CLK_SRC_DEFAULT;
366#if SOC_CLK_APLL_SUPPORTED
368 clk_src = i2s_clock_src_t::I2S_CLK_SRC_APLL;
373 ESP_LOGV(TAG,
"I2S DMA config: %zu buffers x %lu frames", (
size_t) DMA_BUFFERS_COUNT,
374 (
unsigned long) dma_buffer_length);
376 i2s_chan_config_t chan_cfg = {
377 .id = this->
parent_->get_port(),
379 .dma_desc_num = DMA_BUFFERS_COUNT,
380 .dma_frame_num = dma_buffer_length,
386 i2s_std_clk_config_t clk_cfg = {
395 slot_mode = I2S_SLOT_MODE_MONO;
397 slot_mode = I2S_SLOT_MODE_STEREO;
398 slot_mask = I2S_STD_SLOT_BOTH;
401 i2s_std_slot_config_t slot_cfg;
405 I2S_STD_PCM_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(), slot_mode);
409 I2S_STD_MSB_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(), slot_mode);
412 slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(),
417#ifdef USE_ESP32_VARIANT_ESP32
423 slot_cfg.ws_width = configured_bit_width;
424 if (configured_bit_width > 16) {
425 slot_cfg.msb_right =
false;
434 slot_cfg.slot_mask = slot_mask;
436 i2s_std_gpio_config_t gpio_cfg = this->
parent_->get_pin_config();
439 i2s_std_config_t std_cfg = {
441 .slot_cfg = slot_cfg,
442 .gpio_cfg = gpio_cfg,
445 esp_err_t err = this->
init_i2s_channel_(chan_cfg, std_cfg, I2S_EVENT_QUEUE_COUNT);