mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	[i2s_audio] Add more options to speakers and microphones (#7306)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -30,6 +30,10 @@ CONF_I2S_MODE = "i2s_mode" | ||||
| CONF_PRIMARY = "primary" | ||||
| CONF_SECONDARY = "secondary" | ||||
|  | ||||
| CONF_USE_APLL = "use_apll" | ||||
| CONF_BITS_PER_SAMPLE = "bits_per_sample" | ||||
| CONF_BITS_PER_CHANNEL = "bits_per_channel" | ||||
| CONF_MONO = "mono" | ||||
| CONF_LEFT = "left" | ||||
| CONF_RIGHT = "right" | ||||
| CONF_STEREO = "stereo" | ||||
| @@ -58,6 +62,7 @@ I2S_PORTS = { | ||||
|  | ||||
| i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t") | ||||
| I2S_CHANNELS = { | ||||
|     CONF_MONO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ALL_LEFT, | ||||
|     CONF_LEFT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_LEFT, | ||||
|     CONF_RIGHT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_RIGHT, | ||||
|     CONF_STEREO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_RIGHT_LEFT, | ||||
| @@ -67,17 +72,25 @@ i2s_bits_per_sample_t = cg.global_ns.enum("i2s_bits_per_sample_t") | ||||
| I2S_BITS_PER_SAMPLE = { | ||||
|     8: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_8BIT, | ||||
|     16: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_16BIT, | ||||
|     24: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_24BIT, | ||||
|     32: i2s_bits_per_sample_t.I2S_BITS_PER_SAMPLE_32BIT, | ||||
| } | ||||
|  | ||||
| INTERNAL_ADC_VARIANTS = [VARIANT_ESP32] | ||||
| PDM_VARIANTS = [VARIANT_ESP32, VARIANT_ESP32S3] | ||||
| i2s_bits_per_chan_t = cg.global_ns.enum("i2s_bits_per_chan_t") | ||||
| I2S_BITS_PER_CHANNEL = { | ||||
|     "default": i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_DEFAULT, | ||||
|     8: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_8BIT, | ||||
|     16: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_16BIT, | ||||
|     24: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_24BIT, | ||||
|     32: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_32BIT, | ||||
| } | ||||
|  | ||||
| _validate_bits = cv.float_with_unit("bits", "bit") | ||||
|  | ||||
|  | ||||
| def i2s_audio_component_schema( | ||||
|     class_: MockObjClass, | ||||
|     *, | ||||
|     default_sample_rate: int, | ||||
|     default_channel: str, | ||||
|     default_bits_per_sample: str, | ||||
| @@ -96,6 +109,11 @@ def i2s_audio_component_schema( | ||||
|             cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum( | ||||
|                 I2S_MODE_OPTIONS, lower=True | ||||
|             ), | ||||
|             cv.Optional(CONF_USE_APLL, default=False): cv.boolean, | ||||
|             cv.Optional(CONF_BITS_PER_CHANNEL, default="default"): cv.All( | ||||
|                 cv.Any(cv.float_with_unit("bits", "bit"), "default"), | ||||
|                 cv.enum(I2S_BITS_PER_CHANNEL), | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|  | ||||
| @@ -107,6 +125,8 @@ async def register_i2s_audio_component(var, config): | ||||
|     cg.add(var.set_channel(config[CONF_CHANNEL])) | ||||
|     cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE])) | ||||
|     cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE])) | ||||
|     cg.add(var.set_bits_per_channel(config[CONF_BITS_PER_CHANNEL])) | ||||
|     cg.add(var.set_use_apll(config[CONF_USE_APLL])) | ||||
|  | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|   | ||||
| @@ -17,12 +17,16 @@ class I2SAudioBase : public Parented<I2SAudioComponent> { | ||||
|   void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; } | ||||
|   void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; } | ||||
|   void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; } | ||||
|   void set_bits_per_channel(i2s_bits_per_chan_t bits_per_channel) { this->bits_per_channel_ = bits_per_channel; } | ||||
|   void set_use_apll(uint32_t use_apll) { this->use_apll_ = use_apll; } | ||||
|  | ||||
|  protected: | ||||
|   i2s_mode_t i2s_mode_{}; | ||||
|   i2s_channel_fmt_t channel_; | ||||
|   uint32_t sample_rate_; | ||||
|   i2s_bits_per_sample_t bits_per_sample_; | ||||
|   i2s_bits_per_chan_t bits_per_channel_; | ||||
|   bool use_apll_; | ||||
| }; | ||||
|  | ||||
| class I2SAudioIn : public I2SAudioBase {}; | ||||
|   | ||||
| @@ -12,6 +12,10 @@ from .. import ( | ||||
|     I2SAudioOut, | ||||
|     CONF_I2S_AUDIO_ID, | ||||
|     CONF_I2S_DOUT_PIN, | ||||
|     CONF_LEFT, | ||||
|     CONF_RIGHT, | ||||
|     CONF_MONO, | ||||
|     CONF_STEREO, | ||||
| ) | ||||
|  | ||||
| CODEOWNERS = ["@jesserockz"] | ||||
| @@ -30,12 +34,12 @@ CONF_DAC_TYPE = "dac_type" | ||||
| CONF_I2S_COMM_FMT = "i2s_comm_fmt" | ||||
|  | ||||
| INTERNAL_DAC_OPTIONS = { | ||||
|     "left": i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN, | ||||
|     "right": i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN, | ||||
|     "stereo": i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN, | ||||
|     CONF_LEFT: i2s_dac_mode_t.I2S_DAC_CHANNEL_LEFT_EN, | ||||
|     CONF_RIGHT: i2s_dac_mode_t.I2S_DAC_CHANNEL_RIGHT_EN, | ||||
|     CONF_STEREO: i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN, | ||||
| } | ||||
|  | ||||
| EXTERNAL_DAC_OPTIONS = ["mono", "stereo"] | ||||
| EXTERNAL_DAC_OPTIONS = [CONF_MONO, CONF_STEREO] | ||||
|  | ||||
| NO_INTERNAL_DAC_VARIANTS = [esp32.const.VARIANT_ESP32S2] | ||||
|  | ||||
|   | ||||
| @@ -23,7 +23,7 @@ enum I2SState : uint8_t { | ||||
|   I2S_STATE_STOPPING, | ||||
| }; | ||||
|  | ||||
| class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, public I2SAudioOut { | ||||
| class I2SAudioMediaPlayer : public Component, public Parented<I2SAudioComponent>, public media_player::MediaPlayer { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   float get_setup_priority() const override { return esphome::setup_priority::LATE; } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ from esphome.const import CONF_ID, CONF_NUMBER | ||||
| from .. import ( | ||||
|     CONF_I2S_DIN_PIN, | ||||
|     CONF_RIGHT, | ||||
|     INTERNAL_ADC_VARIANTS, | ||||
|     PDM_VARIANTS, | ||||
|     I2SAudioIn, | ||||
|     i2s_audio_component_schema, | ||||
|     i2s_audio_ns, | ||||
| @@ -23,12 +21,13 @@ CONF_ADC_PIN = "adc_pin" | ||||
| CONF_ADC_TYPE = "adc_type" | ||||
| CONF_PDM = "pdm" | ||||
|  | ||||
| CONF_USE_APLL = "use_apll" | ||||
|  | ||||
| I2SAudioMicrophone = i2s_audio_ns.class_( | ||||
|     "I2SAudioMicrophone", I2SAudioIn, microphone.Microphone, cg.Component | ||||
| ) | ||||
|  | ||||
| INTERNAL_ADC_VARIANTS = [esp32.const.VARIANT_ESP32] | ||||
| PDM_VARIANTS = [esp32.const.VARIANT_ESP32, esp32.const.VARIANT_ESP32S3] | ||||
|  | ||||
|  | ||||
| def validate_esp32_variant(config): | ||||
|     variant = esp32.get_esp32_variant() | ||||
| @@ -45,9 +44,15 @@ def validate_esp32_variant(config): | ||||
|  | ||||
|  | ||||
| BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend( | ||||
|     i2s_audio_component_schema(I2SAudioMicrophone, 16000, CONF_RIGHT, "32bit") | ||||
|     i2s_audio_component_schema( | ||||
|         I2SAudioMicrophone, | ||||
|         default_sample_rate=16000, | ||||
|         default_channel=CONF_RIGHT, | ||||
|         default_bits_per_sample="32bit", | ||||
|     ) | ||||
| ).extend(cv.COMPONENT_SCHEMA) | ||||
|  | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     cv.typed_schema( | ||||
|         { | ||||
| @@ -59,8 +64,7 @@ CONFIG_SCHEMA = cv.All( | ||||
|             "external": BASE_SCHEMA.extend( | ||||
|                 { | ||||
|                     cv.Required(CONF_I2S_DIN_PIN): pins.internal_gpio_input_pin_number, | ||||
|                     cv.Required(CONF_PDM): cv.boolean, | ||||
|                     cv.Optional(CONF_USE_APLL, default=False): cv.boolean, | ||||
|                     cv.Optional(CONF_PDM, default=False): cv.boolean, | ||||
|                 } | ||||
|             ), | ||||
|         }, | ||||
| @@ -84,4 +88,3 @@ async def to_code(config): | ||||
|     else: | ||||
|         cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN])) | ||||
|         cg.add(var.set_pdm(config[CONF_PDM])) | ||||
|         cg.add(var.set_use_apll(config[CONF_USE_APLL])) | ||||
|   | ||||
| @@ -58,7 +58,7 @@ void I2SAudioMicrophone::start_() { | ||||
|       .tx_desc_auto_clear = false, | ||||
|       .fixed_mclk = 0, | ||||
|       .mclk_multiple = I2S_MCLK_MULTIPLE_256, | ||||
|       .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, | ||||
|       .bits_per_chan = this->bits_per_channel_, | ||||
|   }; | ||||
|  | ||||
|   esp_err_t err; | ||||
| @@ -167,21 +167,24 @@ size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { | ||||
|     return 0; | ||||
|   } | ||||
|   this->status_clear_warning(); | ||||
|   if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) { | ||||
|     return bytes_read; | ||||
|   } else if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_32BIT) { | ||||
|     std::vector<int16_t> samples; | ||||
|     size_t samples_read = bytes_read / sizeof(int32_t); | ||||
|     samples.resize(samples_read); | ||||
|     for (size_t i = 0; i < samples_read; i++) { | ||||
|       int32_t temp = reinterpret_cast<int32_t *>(buf)[i] >> 14; | ||||
|       samples[i] = clamp<int16_t>(temp, INT16_MIN, INT16_MAX); | ||||
|   // ESP-IDF I2S implementation right-extends 8-bit data to 16 bits, | ||||
|   // and 24-bit data to 32 bits. | ||||
|   switch (this->bits_per_sample_) { | ||||
|     case I2S_BITS_PER_SAMPLE_8BIT: | ||||
|     case I2S_BITS_PER_SAMPLE_16BIT: | ||||
|       return bytes_read; | ||||
|     case I2S_BITS_PER_SAMPLE_24BIT: | ||||
|     case I2S_BITS_PER_SAMPLE_32BIT: { | ||||
|       size_t samples_read = bytes_read / sizeof(int32_t); | ||||
|       for (size_t i = 0; i < samples_read; i++) { | ||||
|         int32_t temp = reinterpret_cast<int32_t *>(buf)[i] >> 14; | ||||
|         buf[i] = clamp<int16_t>(temp, INT16_MIN, INT16_MAX); | ||||
|       } | ||||
|       return samples_read * sizeof(int16_t); | ||||
|     } | ||||
|     memcpy(buf, samples.data(), samples_read * sizeof(int16_t)); | ||||
|     return samples_read * sizeof(int16_t); | ||||
|   } else { | ||||
|     ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_); | ||||
|     return 0; | ||||
|     default: | ||||
|       ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_); | ||||
|       return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -30,8 +30,6 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   void set_use_apll(uint32_t use_apll) { this->use_apll_ = use_apll; } | ||||
|  | ||||
|  protected: | ||||
|   void start_(); | ||||
|   void stop_(); | ||||
| @@ -44,8 +42,6 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub | ||||
| #endif | ||||
|   bool pdm_{false}; | ||||
|  | ||||
|   bool use_apll_; | ||||
|  | ||||
|   HighFrequencyLoopRequester high_freq_; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -2,11 +2,12 @@ from esphome import pins | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import esp32, speaker | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_CHANNEL, CONF_ID | ||||
| from esphome.const import CONF_CHANNEL, CONF_ID, CONF_MODE, CONF_TIMEOUT | ||||
|  | ||||
| from .. import ( | ||||
|     CONF_I2S_DOUT_PIN, | ||||
|     CONF_LEFT, | ||||
|     CONF_MONO, | ||||
|     CONF_RIGHT, | ||||
|     CONF_STEREO, | ||||
|     I2SAudioOut, | ||||
| @@ -32,7 +33,6 @@ INTERNAL_DAC_OPTIONS = { | ||||
|     CONF_STEREO: i2s_dac_mode_t.I2S_DAC_CHANNEL_BOTH_EN, | ||||
| } | ||||
|  | ||||
|  | ||||
| NO_INTERNAL_DAC_VARIANTS = [esp32.const.VARIANT_ESP32S2] | ||||
|  | ||||
|  | ||||
| @@ -45,14 +45,33 @@ def validate_esp32_variant(config): | ||||
|     return config | ||||
|  | ||||
|  | ||||
| BASE_SCHEMA = speaker.SPEAKER_SCHEMA.extend( | ||||
|     i2s_audio_component_schema(I2SAudioSpeaker, 16000, "stereo", "16bit") | ||||
| ).extend(cv.COMPONENT_SCHEMA) | ||||
| BASE_SCHEMA = ( | ||||
|     speaker.SPEAKER_SCHEMA.extend( | ||||
|         i2s_audio_component_schema( | ||||
|             I2SAudioSpeaker, | ||||
|             default_sample_rate=16000, | ||||
|             default_channel=CONF_MONO, | ||||
|             default_bits_per_sample="16bit", | ||||
|         ) | ||||
|     ) | ||||
|     .extend( | ||||
|         { | ||||
|             cv.Optional( | ||||
|                 CONF_TIMEOUT, default="100ms" | ||||
|             ): cv.positive_time_period_milliseconds, | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.COMPONENT_SCHEMA) | ||||
| ) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     cv.typed_schema( | ||||
|         { | ||||
|             "internal": BASE_SCHEMA, | ||||
|             "internal": BASE_SCHEMA.extend( | ||||
|                 { | ||||
|                     cv.Required(CONF_MODE): cv.enum(INTERNAL_DAC_OPTIONS, lower=True), | ||||
|                 } | ||||
|             ), | ||||
|             "external": BASE_SCHEMA.extend( | ||||
|                 { | ||||
|                     cv.Required( | ||||
| @@ -77,3 +96,4 @@ async def to_code(config): | ||||
|         cg.add(var.set_internal_dac_mode(config[CONF_CHANNEL])) | ||||
|     else: | ||||
|         cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN])) | ||||
|     cg.add(var.set_timeout(config[CONF_TIMEOUT])) | ||||
|   | ||||
| @@ -56,6 +56,21 @@ void I2SAudioSpeaker::start_() { | ||||
|   this->task_created_ = true; | ||||
| } | ||||
|  | ||||
| template<typename a, typename b> const uint8_t *convert_data_format(const a *from, b *to, size_t &bytes, bool repeat) { | ||||
|   if (sizeof(a) == sizeof(b) && !repeat) { | ||||
|     return reinterpret_cast<const uint8_t *>(from); | ||||
|   } | ||||
|   const b *result = to; | ||||
|   for (size_t i = 0; i < bytes; i += sizeof(a)) { | ||||
|     b value = static_cast<b>(*from++) << (sizeof(b) - sizeof(a)) * 8; | ||||
|     *to++ = value; | ||||
|     if (repeat) | ||||
|       *to++ = value; | ||||
|   } | ||||
|   bytes *= (sizeof(b) / sizeof(a)) * (repeat ? 2 : 1);  // NOLINT | ||||
|   return reinterpret_cast<const uint8_t *>(result); | ||||
| } | ||||
|  | ||||
| void I2SAudioSpeaker::player_task(void *params) { | ||||
|   I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params; | ||||
|  | ||||
| @@ -71,12 +86,12 @@ void I2SAudioSpeaker::player_task(void *params) { | ||||
|       .communication_format = I2S_COMM_FORMAT_STAND_I2S, | ||||
|       .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, | ||||
|       .dma_buf_count = 8, | ||||
|       .dma_buf_len = 128, | ||||
|       .use_apll = false, | ||||
|       .dma_buf_len = 256, | ||||
|       .use_apll = this_speaker->use_apll_, | ||||
|       .tx_desc_auto_clear = true, | ||||
|       .fixed_mclk = 0, | ||||
|       .mclk_multiple = I2S_MCLK_MULTIPLE_256, | ||||
|       .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, | ||||
|       .bits_per_chan = this_speaker->bits_per_channel_, | ||||
|   }; | ||||
| #if SOC_I2S_SUPPORTS_DAC | ||||
|   if (this_speaker->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) { | ||||
| @@ -114,10 +129,11 @@ void I2SAudioSpeaker::player_task(void *params) { | ||||
|   event.type = TaskEventType::STARTED; | ||||
|   xQueueSend(this_speaker->event_queue_, &event, portMAX_DELAY); | ||||
|  | ||||
|   int16_t buffer[BUFFER_SIZE / 2]; | ||||
|   int32_t buffer[BUFFER_SIZE]; | ||||
|  | ||||
|   while (true) { | ||||
|     if (xQueueReceive(this_speaker->buffer_queue_, &data_event, 100 / portTICK_PERIOD_MS) != pdTRUE) { | ||||
|     if (xQueueReceive(this_speaker->buffer_queue_, &data_event, this_speaker->timeout_ / portTICK_PERIOD_MS) != | ||||
|         pdTRUE) { | ||||
|       break;  // End of audio from main thread | ||||
|     } | ||||
|     if (data_event.stop) { | ||||
| @@ -125,17 +141,28 @@ void I2SAudioSpeaker::player_task(void *params) { | ||||
|       xQueueReset(this_speaker->buffer_queue_);  // Flush queue | ||||
|       break; | ||||
|     } | ||||
|     size_t bytes_written; | ||||
|  | ||||
|     memmove(buffer, data_event.data, data_event.len); | ||||
|     size_t remaining = data_event.len / 2; | ||||
|     size_t current = 0; | ||||
|     const uint8_t *data = data_event.data; | ||||
|     size_t remaining = data_event.len; | ||||
|     switch (this_speaker->bits_per_sample_) { | ||||
|       case I2S_BITS_PER_SAMPLE_8BIT: | ||||
|       case I2S_BITS_PER_SAMPLE_16BIT: { | ||||
|         data = convert_data_format(reinterpret_cast<const int16_t *>(data), reinterpret_cast<int16_t *>(buffer), | ||||
|                                    remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT); | ||||
|         break; | ||||
|       } | ||||
|       case I2S_BITS_PER_SAMPLE_24BIT: | ||||
|       case I2S_BITS_PER_SAMPLE_32BIT: { | ||||
|         data = convert_data_format(reinterpret_cast<const int16_t *>(data), reinterpret_cast<int32_t *>(buffer), | ||||
|                                    remaining, this_speaker->channel_ == I2S_CHANNEL_FMT_ALL_LEFT); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     while (remaining > 0) { | ||||
|       uint32_t sample = (buffer[current] << 16) | (buffer[current] & 0xFFFF); | ||||
|  | ||||
|       esp_err_t err = i2s_write(this_speaker->parent_->get_port(), &sample, sizeof(sample), &bytes_written, | ||||
|                                 (10 / portTICK_PERIOD_MS)); | ||||
|     while (remaining != 0) { | ||||
|       size_t bytes_written; | ||||
|       esp_err_t err = | ||||
|           i2s_write(this_speaker->parent_->get_port(), data, remaining, &bytes_written, (32 / portTICK_PERIOD_MS)); | ||||
|       if (err != ESP_OK) { | ||||
|         event = {.type = TaskEventType::WARNING, .err = err}; | ||||
|         if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { | ||||
| @@ -143,21 +170,8 @@ void I2SAudioSpeaker::player_task(void *params) { | ||||
|         } | ||||
|         continue; | ||||
|       } | ||||
|       if (bytes_written != sizeof(sample)) { | ||||
|         event = {.type = TaskEventType::WARNING, .err = ESP_FAIL}; | ||||
|         if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { | ||||
|           ESP_LOGW(TAG, "Failed to send WARNING event"); | ||||
|         } | ||||
|         continue; | ||||
|       } | ||||
|       remaining--; | ||||
|       current++; | ||||
|     } | ||||
|  | ||||
|     event.type = TaskEventType::PLAYING; | ||||
|     event.err = current; | ||||
|     if (xQueueSend(this_speaker->event_queue_, &event, 10 / portTICK_PERIOD_MS) != pdTRUE) { | ||||
|       ESP_LOGW(TAG, "Failed to send PLAYING event"); | ||||
|       data += bytes_written; | ||||
|       remaining -= bytes_written; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -213,13 +227,11 @@ void I2SAudioSpeaker::watch_() { | ||||
|       case TaskEventType::STARTED: | ||||
|         ESP_LOGD(TAG, "Started I2S Audio Speaker"); | ||||
|         this->state_ = speaker::STATE_RUNNING; | ||||
|         this->status_clear_warning(); | ||||
|         break; | ||||
|       case TaskEventType::STOPPING: | ||||
|         ESP_LOGD(TAG, "Stopping I2S Audio Speaker"); | ||||
|         break; | ||||
|       case TaskEventType::PLAYING: | ||||
|         this->status_clear_warning(); | ||||
|         break; | ||||
|       case TaskEventType::STOPPED: | ||||
|         this->state_ = speaker::STATE_STOPPED; | ||||
|         vTaskDelete(this->player_task_handle_); | ||||
|   | ||||
| @@ -21,7 +21,6 @@ static const size_t BUFFER_SIZE = 1024; | ||||
| enum class TaskEventType : uint8_t { | ||||
|   STARTING = 0, | ||||
|   STARTED, | ||||
|   PLAYING, | ||||
|   STOPPING, | ||||
|   STOPPED, | ||||
|   WARNING = 255, | ||||
| @@ -45,6 +44,7 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp | ||||
|   void setup() override; | ||||
|   void loop() override; | ||||
|  | ||||
|   void set_timeout(uint32_t ms) { this->timeout_ = ms; } | ||||
|   void set_dout_pin(uint8_t pin) { this->dout_pin_ = pin; } | ||||
| #if SOC_I2S_SUPPORTS_DAC | ||||
|   void set_internal_dac_mode(i2s_dac_mode_t mode) { this->internal_dac_mode_ = mode; } | ||||
| @@ -69,6 +69,7 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp | ||||
|   QueueHandle_t buffer_queue_; | ||||
|   QueueHandle_t event_queue_; | ||||
|  | ||||
|   uint32_t timeout_{0}; | ||||
|   uint8_t dout_pin_{0}; | ||||
|   bool task_created_{false}; | ||||
|  | ||||
|   | ||||
| @@ -21,4 +21,3 @@ speaker: | ||||
|     id: speaker_id | ||||
|     dac_type: external | ||||
|     i2s_dout_pin: 13 | ||||
|     mode: mono | ||||
|   | ||||
| @@ -21,4 +21,3 @@ speaker: | ||||
|     id: speaker_id | ||||
|     dac_type: external | ||||
|     i2s_dout_pin: 3 | ||||
|     mode: mono | ||||
|   | ||||
| @@ -21,4 +21,3 @@ speaker: | ||||
|     id: speaker_id | ||||
|     dac_type: external | ||||
|     i2s_dout_pin: 3 | ||||
|     mode: mono | ||||
|   | ||||
| @@ -21,4 +21,3 @@ speaker: | ||||
|     id: speaker_id | ||||
|     dac_type: external | ||||
|     i2s_dout_pin: 13 | ||||
|     mode: mono | ||||
|   | ||||
| @@ -28,7 +28,6 @@ speaker: | ||||
|     id: speaker_id | ||||
|     dac_type: external | ||||
|     i2s_dout_pin: 12 | ||||
|     mode: mono | ||||
|  | ||||
| voice_assistant: | ||||
|   microphone: mic_id_external | ||||
|   | ||||
| @@ -28,7 +28,6 @@ speaker: | ||||
|     id: speaker_id | ||||
|     dac_type: external | ||||
|     i2s_dout_pin: 2 | ||||
|     mode: mono | ||||
|  | ||||
| voice_assistant: | ||||
|   microphone: mic_id_external | ||||
|   | ||||
| @@ -28,7 +28,6 @@ speaker: | ||||
|     id: speaker_id | ||||
|     dac_type: external | ||||
|     i2s_dout_pin: 2 | ||||
|     mode: mono | ||||
|  | ||||
| voice_assistant: | ||||
|   microphone: mic_id_external | ||||
|   | ||||
| @@ -28,7 +28,6 @@ speaker: | ||||
|     id: speaker_id | ||||
|     dac_type: external | ||||
|     i2s_dout_pin: 12 | ||||
|     mode: mono | ||||
|  | ||||
| voice_assistant: | ||||
|   microphone: mic_id_external | ||||
|   | ||||
		Reference in New Issue
	
	Block a user