From db97440b0471508ed1be07c2abb09c9c38292694 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Thu, 1 May 2025 14:02:33 -0500 Subject: [PATCH] [microphone] Add software mute and fix wrong type for automations (#8667) --- esphome/components/microphone/__init__.py | 20 +++++++++++++++++-- esphome/components/microphone/automation.h | 12 +++++++++++ esphome/components/microphone/microphone.cpp | 21 ++++++++++++++++++++ esphome/components/microphone/microphone.h | 10 +++++++--- tests/components/microphone/common.yaml | 8 ++++++++ 5 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 esphome/components/microphone/microphone.cpp diff --git a/esphome/components/microphone/__init__.py b/esphome/components/microphone/__init__.py index dcae513578..f85f0b76f3 100644 --- a/esphome/components/microphone/__init__.py +++ b/esphome/components/microphone/__init__.py @@ -32,6 +32,12 @@ CaptureAction = microphone_ns.class_( StopCaptureAction = microphone_ns.class_( "StopCaptureAction", automation.Action, cg.Parented.template(Microphone) ) +MuteAction = microphone_ns.class_( + "MuteAction", automation.Action, cg.Parented.template(Microphone) +) +UnmuteAction = microphone_ns.class_( + "UnmuteAction", automation.Action, cg.Parented.template(Microphone) +) DataTrigger = microphone_ns.class_( @@ -42,15 +48,15 @@ DataTrigger = microphone_ns.class_( IsCapturingCondition = microphone_ns.class_( "IsCapturingCondition", automation.Condition ) +IsMutedCondition = microphone_ns.class_("IsMutedCondition", automation.Condition) async def setup_microphone_core_(var, config): for conf in config.get(CONF_ON_DATA, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) - # Future PR will change the vector type to uint8 await automation.build_automation( trigger, - [(cg.std_vector.template(cg.int16).operator("ref").operator("const"), "x")], + [(cg.std_vector.template(cg.uint8).operator("ref").operator("const"), "x")], conf, ) @@ -186,9 +192,19 @@ automation.register_action( "microphone.stop_capture", StopCaptureAction, MICROPHONE_ACTION_SCHEMA )(microphone_action) +automation.register_action("microphone.mute", MuteAction, MICROPHONE_ACTION_SCHEMA)( + microphone_action +) +automation.register_action("microphone.unmute", UnmuteAction, MICROPHONE_ACTION_SCHEMA)( + microphone_action +) + automation.register_condition( "microphone.is_capturing", IsCapturingCondition, MICROPHONE_ACTION_SCHEMA )(microphone_action) +automation.register_condition( + "microphone.is_muted", IsMutedCondition, MICROPHONE_ACTION_SCHEMA +)(microphone_action) @coroutine_with_priority(100.0) diff --git a/esphome/components/microphone/automation.h b/esphome/components/microphone/automation.h index 324699c0af..5745909c46 100644 --- a/esphome/components/microphone/automation.h +++ b/esphome/components/microphone/automation.h @@ -16,6 +16,13 @@ template class StopCaptureAction : public Action, public void play(Ts... x) override { this->parent_->stop(); } }; +template class MuteAction : public Action, public Parented { + void play(Ts... x) override { this->parent_->set_mute_state(true); } +}; +template class UnmuteAction : public Action, public Parented { + void play(Ts... x) override { this->parent_->set_mute_state(false); } +}; + class DataTrigger : public Trigger &> { public: explicit DataTrigger(Microphone *mic) { @@ -28,5 +35,10 @@ template class IsCapturingCondition : public Condition, p bool check(Ts... x) override { return this->parent_->is_running(); } }; +template class IsMutedCondition : public Condition, public Parented { + public: + bool check(Ts... x) override { return this->parent_->get_mute_state(); } +}; + } // namespace microphone } // namespace esphome diff --git a/esphome/components/microphone/microphone.cpp b/esphome/components/microphone/microphone.cpp new file mode 100644 index 0000000000..b1289f3791 --- /dev/null +++ b/esphome/components/microphone/microphone.cpp @@ -0,0 +1,21 @@ +#include "microphone.h" + +namespace esphome { +namespace microphone { + +void Microphone::add_data_callback(std::function &)> &&data_callback) { + std::function &)> mute_handled_callback = + [this, data_callback](const std::vector &data) { data_callback(this->silence_audio_(data)); }; + this->data_callbacks_.add(std::move(mute_handled_callback)); +} + +std::vector Microphone::silence_audio_(std::vector data) { + if (this->mute_state_) { + std::memset((void *) data.data(), 0, data.size()); + } + + return data; +} + +} // namespace microphone +} // namespace esphome diff --git a/esphome/components/microphone/microphone.h b/esphome/components/microphone/microphone.h index cef8d0f4c3..ea4e979e20 100644 --- a/esphome/components/microphone/microphone.h +++ b/esphome/components/microphone/microphone.h @@ -22,17 +22,21 @@ class Microphone { public: virtual void start() = 0; virtual void stop() = 0; - void add_data_callback(std::function &)> &&data_callback) { - this->data_callbacks_.add(std::move(data_callback)); - } + void add_data_callback(std::function &)> &&data_callback); bool is_running() const { return this->state_ == STATE_RUNNING; } bool is_stopped() const { return this->state_ == STATE_STOPPED; } + void set_mute_state(bool is_muted) { this->mute_state_ = is_muted; } + bool get_mute_state() { return this->mute_state_; } + audio::AudioStreamInfo get_audio_stream_info() { return this->audio_stream_info_; } protected: + std::vector silence_audio_(std::vector data); + State state_{STATE_STOPPED}; + bool mute_state_{false}; audio::AudioStreamInfo audio_stream_info_; diff --git a/tests/components/microphone/common.yaml b/tests/components/microphone/common.yaml index ccadc7aee5..d8e4abd12a 100644 --- a/tests/components/microphone/common.yaml +++ b/tests/components/microphone/common.yaml @@ -10,3 +10,11 @@ microphone: adc_type: external pdm: false mclk_multiple: 384 + on_data: + - if: + condition: + - microphone.is_muted: + then: + - microphone.unmute: + else: + - microphone.mute: