From 0b1b25191dea6f7a145170d8db26691b668f1326 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 8 Aug 2023 09:45:56 +1200 Subject: [PATCH] Add read interface to microphone (#5131) --- .../microphone/i2s_audio_microphone.cpp | 49 +++++++++---------- .../microphone/i2s_audio_microphone.h | 3 +- esphome/components/microphone/microphone.h | 1 + 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp index 9c661c3ac2..cf0628d638 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp @@ -16,14 +16,6 @@ static const char *const TAG = "i2s_audio.microphone"; void I2SAudioMicrophone::setup() { ESP_LOGCONFIG(TAG, "Setting up I2S Audio Microphone..."); - ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); - this->buffer_ = allocator.allocate(BUFFER_SIZE); - if (this->buffer_ == nullptr) { - ESP_LOGE(TAG, "Failed to allocate buffer!"); - this->mark_failed(); - return; - } - #if SOC_I2S_SUPPORTS_ADC if (this->adc_) { if (this->parent_->get_port() != I2S_NUM_0) { @@ -110,37 +102,38 @@ void I2SAudioMicrophone::stop_() { this->high_freq_.stop(); } -void I2SAudioMicrophone::read_() { +size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) { size_t bytes_read = 0; - esp_err_t err = - i2s_read(this->parent_->get_port(), this->buffer_, BUFFER_SIZE, &bytes_read, (100 / portTICK_PERIOD_MS)); + esp_err_t err = i2s_read(this->parent_->get_port(), buf, len, &bytes_read, (100 / portTICK_PERIOD_MS)); if (err != ESP_OK) { ESP_LOGW(TAG, "Error reading from I2S microphone: %s", esp_err_to_name(err)); this->status_set_warning(); - return; + return 0; } this->status_clear_warning(); - - std::vector samples; - size_t samples_read = 0; if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) { - samples_read = bytes_read / sizeof(int16_t); - } else if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_32BIT) { - samples_read = bytes_read / sizeof(int32_t); - } else { - ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_); - return; - } - samples.resize(samples_read); - if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_16BIT) { - memcpy(samples.data(), this->buffer_, bytes_read); + return bytes_read; } else if (this->bits_per_sample_ == I2S_BITS_PER_SAMPLE_32BIT) { + std::vector 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(this->buffer_)[i] >> 14; + int32_t temp = reinterpret_cast(buf)[i] >> 14; samples[i] = clamp(temp, INT16_MIN, INT16_MAX); } + 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; } +} +void I2SAudioMicrophone::read_() { + std::vector samples; + samples.resize(BUFFER_SIZE); + size_t bytes_read = this->read(samples.data(), BUFFER_SIZE / sizeof(int16_t)); + samples.resize(bytes_read / sizeof(int16_t)); this->data_callbacks_.call(samples); } @@ -152,7 +145,9 @@ void I2SAudioMicrophone::loop() { this->start_(); break; case microphone::STATE_RUNNING: - this->read_(); + if (this->data_callbacks_.size() > 0) { + this->read_(); + } break; case microphone::STATE_STOPPING: this->stop_(); diff --git a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h index 0cb87d42fd..dc6b70047a 100644 --- a/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +++ b/esphome/components/i2s_audio/microphone/i2s_audio_microphone.h @@ -21,6 +21,8 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub void set_din_pin(int8_t pin) { this->din_pin_ = pin; } void set_pdm(bool pdm) { this->pdm_ = pdm; } + size_t read(int16_t *buf, size_t len) override; + #if SOC_I2S_SUPPORTS_ADC void set_adc_channel(adc1_channel_t channel) { this->adc_channel_ = channel; @@ -42,7 +44,6 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub bool adc_{false}; #endif bool pdm_{false}; - uint8_t *buffer_; i2s_channel_fmt_t channel_; i2s_bits_per_sample_t bits_per_sample_; diff --git a/esphome/components/microphone/microphone.h b/esphome/components/microphone/microphone.h index ac3db3ec0f..e01a10e15c 100644 --- a/esphome/components/microphone/microphone.h +++ b/esphome/components/microphone/microphone.h @@ -20,6 +20,7 @@ class Microphone { void add_data_callback(std::function &)> &&data_callback) { this->data_callbacks_.add(std::move(data_callback)); } + virtual size_t read(int16_t *buf, size_t len) = 0; bool is_running() const { return this->state_ == STATE_RUNNING; } bool is_stopped() const { return this->state_ == STATE_STOPPED; }