diff --git a/esphome/components/speaker/media_player/speaker_media_player.cpp b/esphome/components/speaker/media_player/speaker_media_player.cpp index 94f555c26e..fdf6bf66cd 100644 --- a/esphome/components/speaker/media_player/speaker_media_player.cpp +++ b/esphome/components/speaker/media_player/speaker_media_player.cpp @@ -103,6 +103,20 @@ void SpeakerMediaPlayer::set_playlist_delay_ms(AudioPipelineType pipeline_type, } } +void SpeakerMediaPlayer::stop_and_unpause_media_() { + this->media_pipeline_->stop(); + this->unpause_media_remaining_ = 3; + this->set_interval("unpause_med", 50, [this]() { + if (this->media_pipeline_state_ == AudioPipelineState::STOPPED) { + this->cancel_interval("unpause_med"); + this->media_pipeline_->set_pause_state(false); + this->is_paused_ = false; + } else if (--this->unpause_media_remaining_ == 0) { + this->cancel_interval("unpause_med"); + } + }); +} + void SpeakerMediaPlayer::watch_media_commands_() { if (!this->is_ready()) { return; @@ -144,15 +158,7 @@ void SpeakerMediaPlayer::watch_media_commands_() { if (this->is_paused_) { // If paused, stop the media pipeline and unpause it after confirming its stopped. This avoids playing a // short segment of the paused file before starting the new one. - this->media_pipeline_->stop(); - this->set_retry("unpause_med", 50, 3, [this](const uint8_t remaining_attempts) { - if (this->media_pipeline_state_ == AudioPipelineState::STOPPED) { - this->media_pipeline_->set_pause_state(false); - this->is_paused_ = false; - return RetryResult::DONE; - } - return RetryResult::RETRY; - }); + this->stop_and_unpause_media_(); } else { // Not paused, just directly start the file if (media_command.file.has_value()) { @@ -197,27 +203,21 @@ void SpeakerMediaPlayer::watch_media_commands_() { this->cancel_timeout("next_ann"); this->announcement_playlist_.clear(); this->announcement_pipeline_->stop(); - this->set_retry("unpause_ann", 50, 3, [this](const uint8_t remaining_attempts) { + this->unpause_announcement_remaining_ = 3; + this->set_interval("unpause_ann", 50, [this]() { if (this->announcement_pipeline_state_ == AudioPipelineState::STOPPED) { + this->cancel_interval("unpause_ann"); this->announcement_pipeline_->set_pause_state(false); - return RetryResult::DONE; + } else if (--this->unpause_announcement_remaining_ == 0) { + this->cancel_interval("unpause_ann"); } - return RetryResult::RETRY; }); } } else { if (this->media_pipeline_ != nullptr) { this->cancel_timeout("next_media"); this->media_playlist_.clear(); - this->media_pipeline_->stop(); - this->set_retry("unpause_med", 50, 3, [this](const uint8_t remaining_attempts) { - if (this->media_pipeline_state_ == AudioPipelineState::STOPPED) { - this->media_pipeline_->set_pause_state(false); - this->is_paused_ = false; - return RetryResult::DONE; - } - return RetryResult::RETRY; - }); + this->stop_and_unpause_media_(); } } diff --git a/esphome/components/speaker/media_player/speaker_media_player.h b/esphome/components/speaker/media_player/speaker_media_player.h index 722f98ceea..6796fc9c00 100644 --- a/esphome/components/speaker/media_player/speaker_media_player.h +++ b/esphome/components/speaker/media_player/speaker_media_player.h @@ -112,6 +112,9 @@ class SpeakerMediaPlayer : public Component, /// media pipelines are defined. inline bool single_pipeline_() { return (this->media_speaker_ == nullptr); } + /// Stops the media pipeline and polls until stopped to unpause it, avoiding an audible glitch. + void stop_and_unpause_media_(); + // Processes commands from media_control_command_queue_. void watch_media_commands_(); @@ -141,6 +144,8 @@ class SpeakerMediaPlayer : public Component, bool is_paused_{false}; bool is_muted_{false}; + uint8_t unpause_media_remaining_{0}; + uint8_t unpause_announcement_remaining_{0}; // The amount to change the volume on volume up/down commands float volume_increment_;