ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
i2s_audio.cpp
Go to the documentation of this file.
1#include "i2s_audio.h"
2
3#if defined(USE_ESP32) && defined(USE_I2S_AUDIO_FULL_DUPLEX)
4
5#include "esphome/core/log.h"
6
8
9ESPHOME_LOG_TAG(TAG, "i2s_audio");
10
12 if (!this->is_full_duplex())
13 return;
14
15 // ESP-IDF only shares the bit and word clocks between channels allocated in the same call, and deleting either
16 // channel ends the pairing. Allocate both once here and keep them for the lifetime of the device.
17 i2s_chan_config_t chan_cfg{};
18 i2s_std_config_t tx_cfg{};
19 i2s_std_config_t rx_cfg{};
20 this->audio_out_->build_full_duplex_config(chan_cfg, tx_cfg);
22
23 esp_err_t err = i2s_new_channel(&chan_cfg, &this->tx_handle_, &this->rx_handle_);
24 if (err == ESP_OK) {
25 // The first initialized channel drives the shared clocks. Use RX so the microphone runs on its own.
26 err = i2s_channel_init_std_mode(this->rx_handle_, &rx_cfg);
27 }
28 if (err == ESP_OK) {
29 err = i2s_channel_init_std_mode(this->tx_handle_, &tx_cfg);
30 }
31 if (err != ESP_OK) {
32 ESP_LOGE(TAG, "Full duplex channel setup failed: %s", esp_err_to_name(err));
33 if (this->tx_handle_ != nullptr) {
34 i2s_del_channel(this->tx_handle_);
35 this->tx_handle_ = nullptr;
36 }
37 if (this->rx_handle_ != nullptr) {
38 i2s_del_channel(this->rx_handle_);
39 this->rx_handle_ = nullptr;
40 }
41 this->mark_failed();
42 }
43}
44
45i2s_chan_handle_t I2SAudioComponent::acquire_(bool &in_use, i2s_chan_handle_t handle) {
46 if (handle == nullptr)
47 return nullptr;
48 in_use = true;
49 if (!this->update_rx_channel_()) {
50 in_use = false;
51 return nullptr;
52 }
53 return handle;
54}
55
56i2s_chan_handle_t I2SAudioComponent::acquire_rx_channel() { return this->acquire_(this->rx_in_use_, this->rx_handle_); }
57
59 this->rx_in_use_ = false;
60 this->update_rx_channel_();
61}
62
64 // Speakers sharing the bus take turns; a second one must not get the channel while the first is playing
65 if (this->tx_in_use_)
66 return nullptr;
67 return this->acquire_(this->tx_in_use_, this->tx_handle_);
68}
69
71 // The speaker task may have left the channel disabled already, so an invalid state error is expected here
72 i2s_channel_disable(this->tx_handle_);
73 this->tx_in_use_ = false;
74 this->update_rx_channel_();
75}
76
78 const bool needed = this->rx_in_use_ || this->tx_in_use_;
79 if (needed == this->rx_enabled_)
80 return true;
81
82 esp_err_t err = needed ? i2s_channel_enable(this->rx_handle_) : i2s_channel_disable(this->rx_handle_);
83 if (err != ESP_OK) {
84 ESP_LOGE(TAG, "Failed to %s RX channel: %s", needed ? LOG_STR_LITERAL("enable") : LOG_STR_LITERAL("disable"),
85 esp_err_to_name(err));
86 return false;
87 }
88 this->rx_enabled_ = needed;
89 return true;
90}
91
92} // namespace esphome::i2s_audio
93
94#endif // USE_ESP32 && USE_I2S_AUDIO_FULL_DUPLEX
void mark_failed()
Mark this component as failed.
i2s_chan_handle_t acquire_rx_channel()
Enables the full duplex RX channel.
Definition i2s_audio.cpp:56
bool is_full_duplex() const
True when a microphone and a speaker share this bus at the same time.
Definition i2s_audio.h:71
i2s_chan_handle_t acquire_(bool &in_use, i2s_chan_handle_t handle)
Marks one side active and brings the shared clocks up; undoes the mark if that fails.
Definition i2s_audio.cpp:45
bool update_rx_channel_()
Enables the RX channel while either side is active, since it drives the shared clocks.
Definition i2s_audio.cpp:77
void release_rx_channel()
Releases the RX channel; it keeps running while the TX side needs its clocks. Main loop only.
Definition i2s_audio.cpp:58
i2s_chan_handle_t acquire_tx_channel()
Starts the shared clocks and hands over the full duplex TX channel, still disabled,...
Definition i2s_audio.cpp:63
void release_tx_channel()
Disables the TX channel and stops the shared clocks if the RX side is idle.
Definition i2s_audio.cpp:70
virtual void build_full_duplex_config(i2s_std_config_t &std_cfg)=0
Builds the RX configuration the parent uses to set up a full duplex channel pair.
virtual void build_full_duplex_config(i2s_chan_config_t &chan_cfg, i2s_std_config_t &std_cfg)
Builds the TX configuration the parent uses to set up a full duplex channel pair.
Definition i2s_audio.h:58
ESPHOME_LOG_TAG(TAG, "i2s_audio")
spi_device_handle_t handle