49 const uint32_t dma_buffers_duration_ms = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT;
57 const size_t ring_buffer_size =
62 bool successful_setup =
false;
64 std::unique_ptr<audio::RingBufferAudioSource> audio_source;
68 uint8_t *silence_buffer = silence_allocator.
allocate(dma_buffer_bytes);
70 if (silence_buffer !=
nullptr) {
71 memset(silence_buffer, 0, dma_buffer_bytes);
77 if (audio_source !=
nullptr) {
80 successful_setup =
true;
84 if (successful_setup) {
88 for (
size_t i = 0; i < DMA_BUFFERS_COUNT; i++) {
89 size_t bytes_loaded = 0;
90 esp_err_t err = i2s_channel_preload_data(this->
tx_handle_, silence_buffer, dma_buffer_bytes, &bytes_loaded);
91 if (err != ESP_OK || bytes_loaded != dma_buffer_bytes) {
92 ESP_LOGV(TAG,
"Failed to preload silence into DMA buffer %u (err=%d, loaded=%u)", (
unsigned) i, (
int) err,
93 (
unsigned) bytes_loaded);
94 successful_setup =
false;
100 ESP_LOGV(TAG,
"Failed to push preload write record");
101 successful_setup =
false;
107 if (successful_setup) {
110 const i2s_event_callbacks_t callbacks = {.on_sent =
i2s_on_sent_cb};
111 i2s_channel_register_event_callback(this->
tx_handle_, &callbacks,
this);
113 if (i2s_channel_enable(this->
tx_handle_) != ESP_OK) {
114 ESP_LOGV(TAG,
"Failed to enable I2S channel");
115 successful_setup =
false;
119 if (!successful_setup) {
122 bool stop_gracefully =
false;
149 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::COMMAND_STOP);
150 ESP_LOGV(TAG,
"Exiting: COMMAND_STOP received");
154 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY);
155 stop_gracefully =
true;
160 ESP_LOGV(TAG,
"Exiting: stream info changed");
167 int64_t write_timestamp;
168 bool lockstep_broken =
false;
173 ESP_LOGV(TAG,
"Event without matching write record");
175 lockstep_broken =
true;
178 if (real_frames > 0) {
179 pending_real_buffers--;
183 const uint32_t silence_frames = frames_per_dma_buffer - real_frames;
184 const int64_t adjusted_ts =
189 if (lockstep_broken) {
197 if (stop_gracefully && audio_source->available() == 0 && !this->has_buffered_data() &&
198 pending_real_buffers == 0) {
199 ESP_LOGV(TAG,
"Exiting: graceful stop complete");
207 size_t bytes_written_total = 0;
208 size_t real_bytes_total = 0;
209 bool partial_write_failure =
false;
212 while (bytes_written_total < dma_buffer_bytes) {
213 size_t bytes_read = audio_source->fill(pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS) / 2,
false);
214 if (bytes_read > 0) {
215 uint8_t *
new_data = audio_source->mutable_data() + audio_source->available() - bytes_read;
220 const size_t to_write = std::min(audio_source->available(), dma_buffer_bytes - bytes_written_total);
228 i2s_channel_write(this->
tx_handle_, audio_source->data(), to_write, &bw, WRITE_TIMEOUT_TICKS);
229 if (bw != to_write) {
232 ESP_LOGV(TAG,
"Partial real audio write: %u of %u bytes", (
unsigned) bw, (
unsigned) to_write);
234 partial_write_failure =
true;
237 audio_source->consume(bw);
238 bytes_written_total += bw;
239 real_bytes_total += bw;
241 if (real_bytes_total > 0) {
242 last_data_received_time =
millis();
246 if (partial_write_failure) {
250 const size_t silence_bytes = dma_buffer_bytes - bytes_written_total;
251 if (silence_bytes > 0) {
253 i2s_channel_write(this->
tx_handle_, silence_buffer, silence_bytes, &bw, WRITE_TIMEOUT_TICKS);
254 if (bw != silence_bytes) {
256 ESP_LOGV(TAG,
"Partial silence write: %u of %u bytes", (
unsigned) bw, (
unsigned) silence_bytes);
267 ESP_LOGV(TAG,
"Exiting: write records queue full");
271 if (real_frames_in_buffer > 0) {
272 pending_real_buffers++;
279 audio_source.reset();
281 if (silence_buffer !=
nullptr) {
282 silence_allocator.
deallocate(silence_buffer, dma_buffer_bytes);
283 silence_buffer =
nullptr;
290 vTaskDelay(pdMS_TO_TICKS(10));
299 ESP_LOGE(TAG,
"Incompatible stream settings");
300 return ESP_ERR_NOT_SUPPORTED;
306 ESP_LOGE(TAG,
"Stream bits per sample must be less than or equal to the speaker's configuration");
307 return ESP_ERR_NOT_SUPPORTED;
310 if (!this->
parent_->try_lock()) {
311 ESP_LOGE(TAG,
"Parent bus is busy");
312 return ESP_ERR_INVALID_STATE;
318 i2s_clock_src_t clk_src = I2S_CLK_SRC_DEFAULT;
320#if SOC_CLK_APLL_SUPPORTED
322 clk_src = i2s_clock_src_t::I2S_CLK_SRC_APLL;
327 ESP_LOGV(TAG,
"I2S DMA config: %zu buffers x %lu frames", (
size_t) DMA_BUFFERS_COUNT,
328 (
unsigned long) dma_buffer_length);
330 i2s_chan_config_t chan_cfg = {
331 .id = this->
parent_->get_port(),
333 .dma_desc_num = DMA_BUFFERS_COUNT,
334 .dma_frame_num = dma_buffer_length,
340 i2s_std_clk_config_t clk_cfg = {
349 slot_mode = I2S_SLOT_MODE_MONO;
351 slot_mode = I2S_SLOT_MODE_STEREO;
352 slot_mask = I2S_STD_SLOT_BOTH;
355 i2s_std_slot_config_t slot_cfg;
359 I2S_STD_PCM_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(), slot_mode);
363 I2S_STD_MSB_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(), slot_mode);
366 slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(),
371#ifdef USE_ESP32_VARIANT_ESP32
377 slot_cfg.ws_width = configured_bit_width;
378 if (configured_bit_width > 16) {
379 slot_cfg.msb_right =
false;
388 slot_cfg.slot_mask = slot_mask;
390 i2s_std_gpio_config_t gpio_cfg = this->
parent_->get_pin_config();
393 i2s_std_config_t std_cfg = {
395 .slot_cfg = slot_cfg,
396 .gpio_cfg = gpio_cfg,
399 esp_err_t err = this->
init_i2s_channel_(chan_cfg, std_cfg, I2S_EVENT_QUEUE_COUNT);