5 #include <driver/i2s.h> 14 static const size_t BUFFER_COUNT = 20;
16 static const char *
const TAG =
"i2s_audio.speaker";
19 ESP_LOGCONFIG(TAG,
"Setting up I2S Audio Speaker...");
23 ESP_LOGE(TAG,
"Failed to create buffer queue");
30 ESP_LOGE(TAG,
"Failed to create event queue");
38 ESP_LOGE(TAG,
"Cannot start audio, speaker failed to setup");
42 ESP_LOGW(TAG,
"Called start while task has been already created.");
51 if (!this->
parent_->try_lock()) {
64 xQueueSend(this_speaker->
event_queue_, &event, portMAX_DELAY);
66 i2s_driver_config_t config = {
67 .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX),
69 .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
70 .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
71 .communication_format = I2S_COMM_FORMAT_STAND_I2S,
72 .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
76 .tx_desc_auto_clear =
true,
77 .fixed_mclk = I2S_PIN_NO_CHANGE,
78 .mclk_multiple = I2S_MCLK_MULTIPLE_256,
79 .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
81 #if SOC_I2S_SUPPORTS_DAC 83 config.mode = (i2s_mode_t) (config.mode | I2S_MODE_DAC_BUILT_IN);
87 esp_err_t err = i2s_driver_install(this_speaker->
parent_->get_port(), &config, 0,
nullptr);
99 #if SOC_I2S_SUPPORTS_DAC 102 i2s_pin_config_t pin_config = this_speaker->
parent_->get_pin_config();
103 pin_config.data_out_num = this_speaker->
dout_pin_;
105 i2s_set_pin(this_speaker->
parent_->get_port(), &pin_config);
106 #if SOC_I2S_SUPPORTS_DAC 115 xQueueSend(this_speaker->
event_queue_, &event, portMAX_DELAY);
117 int16_t buffer[BUFFER_SIZE / 2];
120 if (xQueueReceive(this_speaker->
buffer_queue_, &data_event, 100 / portTICK_PERIOD_MS) != pdTRUE) {
123 if (data_event.
stop) {
128 size_t bytes_written;
130 memmove(buffer, data_event.
data, data_event.
len);
131 size_t remaining = data_event.
len / 2;
134 while (remaining > 0) {
135 uint32_t sample = (buffer[current] << 16) | (buffer[current] & 0xFFFF);
137 esp_err_t err = i2s_write(this_speaker->
parent_->get_port(), &sample,
sizeof(sample), &bytes_written,
138 (10 / portTICK_PERIOD_MS));
141 if (xQueueSend(this_speaker->
event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) {
142 ESP_LOGW(TAG,
"Failed to send WARNING event");
146 if (bytes_written !=
sizeof(sample)) {
148 if (xQueueSend(this_speaker->
event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) {
149 ESP_LOGW(TAG,
"Failed to send WARNING event");
159 if (xQueueSend(this_speaker->
event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) {
160 ESP_LOGW(TAG,
"Failed to send PLAYING event");
165 if (xQueueSend(this_speaker->
event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) {
166 ESP_LOGW(TAG,
"Failed to send STOPPING event");
169 i2s_zero_dma_buffer(this_speaker->
parent_->get_port());
171 i2s_driver_uninstall(this_speaker->
parent_->get_port());
174 if (xQueueSend(this_speaker->
event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) {
175 ESP_LOGW(TAG,
"Failed to send STOPPED event");
195 xQueueSendToFront(this->
buffer_queue_, &data, portMAX_DELAY);
200 if (xQueueReceive(this->
event_queue_, &event, 0) == pdTRUE) {
201 switch (event.
type) {
203 ESP_LOGD(TAG,
"Starting I2S Audio Speaker");
206 ESP_LOGD(TAG,
"Started I2S Audio Speaker");
210 ESP_LOGD(TAG,
"Stopping I2S Audio Speaker");
222 ESP_LOGD(TAG,
"Stopped I2S Audio Speaker");
225 ESP_LOGW(TAG,
"Error writing to I2S: %s", esp_err_to_name(event.
err));
247 ESP_LOGE(TAG,
"Cannot play audio, speaker failed to setup");
253 size_t remaining =
length;
255 while (remaining > 0) {
258 size_t to_send_length = std::min(remaining, BUFFER_SIZE);
259 event.len = to_send_length;
260 memcpy(event.
data, data + index, to_send_length);
264 remaining -= to_send_length;
265 index += to_send_length;
void status_set_warning(const char *message="unspecified")
i2s_dac_mode_t internal_dac_mode_
TaskHandle_t player_task_handle_
static void player_task(void *params)
QueueHandle_t buffer_queue_
I2SAudioComponent * parent_
void status_clear_warning()
QueueHandle_t event_queue_
size_t play(const uint8_t *data, size_t length) override
virtual void mark_failed()
Mark this component as failed.
Implementation of SPI Controller mode.
bool has_buffered_data() const override
uint8_t data[BUFFER_SIZE]
void IRAM_ATTR HOT delay(uint32_t ms)