mirror of
https://github.com/esphome/esphome.git
synced 2026-09-18 10:38:38 +00:00
[speaker][speaker_source] Make a volume of zero silent with an audio DAC (#19305)
This commit is contained in:
@@ -177,7 +177,7 @@ void I2SAudioSpeakerBase::post_software_gain_(uint32_t rate_samples) {
|
||||
#endif // USE_AUDIO_DAC
|
||||
// Software volume control. The ramp treats 0 dB as unity and skips processing there.
|
||||
float target_db;
|
||||
if (this->mute_state_ || this->volume_ <= 0.0f) {
|
||||
if (this->is_silent_()) {
|
||||
target_db = -INFINITY;
|
||||
} else if (this->volume_ >= 1.0f) {
|
||||
target_db = 0.0f;
|
||||
|
||||
@@ -612,7 +612,7 @@ void SpeakerMediaPlayer::set_volume_(float volume, bool publish) {
|
||||
}
|
||||
|
||||
// Turn on the mute state if the volume is effectively zero, off otherwise
|
||||
if (volume < 0.001f) {
|
||||
if (volume < speaker::SILENT_VOLUME_THRESHOLD) {
|
||||
this->set_mute_state_(true);
|
||||
} else {
|
||||
this->set_mute_state_(false);
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
namespace esphome::speaker {
|
||||
|
||||
/// Volumes below this are treated as zero
|
||||
static constexpr float SILENT_VOLUME_THRESHOLD = 0.001f;
|
||||
|
||||
enum State : uint8_t {
|
||||
STATE_STOPPED = 0,
|
||||
STATE_STARTING,
|
||||
@@ -65,13 +68,15 @@ class Speaker {
|
||||
bool is_running() const { return this->state_ == STATE_RUNNING; }
|
||||
bool is_stopped() const { return this->state_ == STATE_STOPPED; }
|
||||
|
||||
// Volume control is handled by a configured audio dac component. Individual speaker components can
|
||||
// override and implement in software if an audio dac isn't available.
|
||||
// Volume and mute are independent: changing one never alters the other's stored state. Volume control is
|
||||
// handled by a configured audio dac component. Individual speaker components can override and implement in
|
||||
// software if an audio dac isn't available.
|
||||
virtual void set_volume(float volume) {
|
||||
this->volume_ = volume;
|
||||
#ifdef USE_AUDIO_DAC
|
||||
if (this->audio_dac_ != nullptr) {
|
||||
this->audio_dac_->set_volume(volume);
|
||||
this->apply_audio_dac_mute_();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -80,13 +85,7 @@ class Speaker {
|
||||
virtual void set_mute_state(bool mute_state) {
|
||||
this->mute_state_ = mute_state;
|
||||
#ifdef USE_AUDIO_DAC
|
||||
if (this->audio_dac_) {
|
||||
if (mute_state) {
|
||||
this->audio_dac_->set_mute_on();
|
||||
} else {
|
||||
this->audio_dac_->set_mute_off();
|
||||
}
|
||||
}
|
||||
this->apply_audio_dac_mute_();
|
||||
#endif
|
||||
}
|
||||
virtual bool get_mute_state() { return this->mute_state_; }
|
||||
@@ -110,6 +109,23 @@ class Speaker {
|
||||
}
|
||||
|
||||
protected:
|
||||
/// @brief Whether the output should be silent: muted, or the volume is effectively zero.
|
||||
/// Volume steps from media players can leave a positive value near float epsilon instead of exactly zero.
|
||||
bool is_silent_() const { return this->mute_state_ || this->volume_ < SILENT_VOLUME_THRESHOLD; }
|
||||
|
||||
#ifdef USE_AUDIO_DAC
|
||||
/// @brief Uses the audio dac's mute as the silence mechanism, since a dac's minimum volume is often audible.
|
||||
void apply_audio_dac_mute_() {
|
||||
if (this->audio_dac_ == nullptr)
|
||||
return;
|
||||
if (this->is_silent_()) {
|
||||
this->audio_dac_->set_mute_on();
|
||||
} else {
|
||||
this->audio_dac_->set_mute_off();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
State state_{STATE_STOPPED};
|
||||
audio::AudioStreamInfo audio_stream_info_;
|
||||
float volume_{1.0f};
|
||||
|
||||
@@ -831,7 +831,7 @@ void SpeakerSourceMediaPlayer::set_volume_(float volume, bool publish) {
|
||||
|
||||
// Turn on the mute state if the volume is effectively zero, off otherwise.
|
||||
// Pass publish=false to avoid saving twice.
|
||||
if (volume < 0.001f) {
|
||||
if (volume < speaker::SILENT_VOLUME_THRESHOLD) {
|
||||
this->set_mute_state_(true, false);
|
||||
} else {
|
||||
this->set_mute_state_(false, false);
|
||||
|
||||
Reference in New Issue
Block a user