50 const uint32_t dma_buffers_duration_ms = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT;
58 const size_t ring_buffer_size =
63 bool successful_setup =
false;
65 std::unique_ptr<audio::RingBufferAudioSource> audio_source;
69 uint8_t *silence_buffer = silence_allocator.
allocate(dma_buffer_bytes);
71 if (silence_buffer !=
nullptr) {
72 memset(silence_buffer, 0, dma_buffer_bytes);
78 if (audio_source !=
nullptr) {
81 successful_setup =
true;
85 if (successful_setup) {
89 for (
size_t i = 0; i < DMA_BUFFERS_COUNT; i++) {
90 size_t bytes_loaded = 0;
91 esp_err_t err = i2s_channel_preload_data(this->
tx_handle_, silence_buffer, dma_buffer_bytes, &bytes_loaded);
92 if (err != ESP_OK || bytes_loaded != dma_buffer_bytes) {
93 ESP_LOGV(TAG,
"Failed to preload silence into DMA buffer %u (err=%d, loaded=%u)", (
unsigned) i, (
int) err,
94 (
unsigned) bytes_loaded);
95 successful_setup =
false;
101 ESP_LOGV(TAG,
"Failed to push preload write record");
102 successful_setup =
false;
108 if (successful_setup) {
111 const i2s_event_callbacks_t callbacks = {.on_sent =
i2s_on_sent_cb};
112 i2s_channel_register_event_callback(this->
tx_handle_, &callbacks,
this);
114 if (i2s_channel_enable(this->
tx_handle_) != ESP_OK) {
115 ESP_LOGV(TAG,
"Failed to enable I2S channel");
116 successful_setup =
false;
120 if (!successful_setup) {
123 bool stop_gracefully =
false;
150 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::COMMAND_STOP);
151 ESP_LOGV(TAG,
"Exiting: COMMAND_STOP received");
155 xEventGroupClearBits(this->
event_group_, SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY);
156 stop_gracefully =
true;
161 ESP_LOGV(TAG,
"Exiting: stream info changed");
168 int64_t write_timestamp;
169 bool lockstep_broken =
false;
174 ESP_LOGV(TAG,
"Event without matching write record");
176 lockstep_broken =
true;
179 if (real_frames > 0) {
180 pending_real_buffers--;
184 const uint32_t silence_frames = frames_per_dma_buffer - real_frames;
185 const int64_t adjusted_ts =
190 if (lockstep_broken) {
198 if (stop_gracefully && audio_source->available() == 0 && !this->has_buffered_data() &&
199 pending_real_buffers == 0) {
200 ESP_LOGV(TAG,
"Exiting: graceful stop complete");
208 size_t bytes_written_total = 0;
209 size_t real_bytes_total = 0;
210 bool partial_write_failure =
false;
213 while (bytes_written_total < dma_buffer_bytes) {
214 size_t bytes_read = audio_source->fill(pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS) / 2,
false);
215 if (bytes_read > 0) {
216 uint8_t *
new_data = audio_source->mutable_data() + audio_source->available() - bytes_read;
221 const size_t to_write = std::min(audio_source->available(), dma_buffer_bytes - bytes_written_total);
229 i2s_channel_write(this->
tx_handle_, audio_source->data(), to_write, &bw, WRITE_TIMEOUT_TICKS);
230 if (bw != to_write) {
233 ESP_LOGV(TAG,
"Partial real audio write: %u of %u bytes", (
unsigned) bw, (
unsigned) to_write);
235 partial_write_failure =
true;
238 audio_source->consume(bw);
239 bytes_written_total += bw;
240 real_bytes_total += bw;
242 if (real_bytes_total > 0) {
243 last_data_received_time =
millis();
247 if (partial_write_failure) {
251 const size_t silence_bytes = dma_buffer_bytes - bytes_written_total;
252 if (silence_bytes > 0) {
254 i2s_channel_write(this->
tx_handle_, silence_buffer, silence_bytes, &bw, WRITE_TIMEOUT_TICKS);
255 if (bw != silence_bytes) {
257 ESP_LOGV(TAG,
"Partial silence write: %u of %u bytes", (
unsigned) bw, (
unsigned) silence_bytes);
268 ESP_LOGV(TAG,
"Exiting: write records queue full");
272 if (real_frames_in_buffer > 0) {
273 pending_real_buffers++;
280 audio_source.reset();
282 if (silence_buffer !=
nullptr) {
283 silence_allocator.
deallocate(silence_buffer, dma_buffer_bytes);
284 silence_buffer =
nullptr;
291 vTaskDelay(pdMS_TO_TICKS(10));
300 ESP_LOGE(TAG,
"Incompatible stream settings");
301 return ESP_ERR_NOT_SUPPORTED;
307 ESP_LOGE(TAG,
"Stream bits per sample must be less than or equal to the speaker's configuration");
308 return ESP_ERR_NOT_SUPPORTED;
311 if (!this->
parent_->try_lock()) {
312 ESP_LOGE(TAG,
"Parent bus is busy");
313 return ESP_ERR_INVALID_STATE;
319 i2s_clock_src_t clk_src = I2S_CLK_SRC_DEFAULT;
321#if SOC_CLK_APLL_SUPPORTED
323 clk_src = i2s_clock_src_t::I2S_CLK_SRC_APLL;
328 ESP_LOGV(TAG,
"I2S DMA config: %zu buffers x %lu frames", (
size_t) DMA_BUFFERS_COUNT,
329 (
unsigned long) dma_buffer_length);
331 i2s_chan_config_t chan_cfg = {
332 .id = this->
parent_->get_port(),
334 .dma_desc_num = DMA_BUFFERS_COUNT,
335 .dma_frame_num = dma_buffer_length,
341 i2s_std_clk_config_t clk_cfg = {
350 slot_mode = I2S_SLOT_MODE_MONO;
352 slot_mode = I2S_SLOT_MODE_STEREO;
353 slot_mask = I2S_STD_SLOT_BOTH;
356 i2s_std_slot_config_t slot_cfg;
360 I2S_STD_PCM_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(), slot_mode);
364 I2S_STD_MSB_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(), slot_mode);
367 slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.
get_bits_per_sample(),
372#ifdef USE_ESP32_VARIANT_ESP32
378 slot_cfg.ws_width = configured_bit_width;
379 if (configured_bit_width > 16) {
380 slot_cfg.msb_right =
false;
389 slot_cfg.slot_mask = slot_mask;
391 i2s_std_gpio_config_t gpio_cfg = this->
parent_->get_pin_config();
394 i2s_std_config_t std_cfg = {
396 .slot_cfg = slot_cfg,
397 .gpio_cfg = gpio_cfg,
400 esp_err_t err = this->
init_i2s_channel_(chan_cfg, std_cfg, I2S_EVENT_QUEUE_COUNT);