mirror of
https://github.com/esphome/esphome.git
synced 2025-04-16 07:40:29 +01:00
[voice_assistant] Add announce support (#8232)
This commit is contained in:
parent
46d19d82c2
commit
33f9d66e81
@ -1,4 +1,5 @@
|
|||||||
#include "voice_assistant.h"
|
#include "voice_assistant.h"
|
||||||
|
#include "esphome/core/defines.h"
|
||||||
|
|
||||||
#ifdef USE_VOICE_ASSISTANT
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
|
|
||||||
@ -127,7 +128,7 @@ void VoiceAssistant::clear_buffers_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_SPEAKER
|
#ifdef USE_SPEAKER
|
||||||
if (this->speaker_buffer_ != nullptr) {
|
if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) {
|
||||||
memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE);
|
memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE);
|
||||||
|
|
||||||
this->speaker_buffer_size_ = 0;
|
this->speaker_buffer_size_ = 0;
|
||||||
@ -159,7 +160,7 @@ void VoiceAssistant::deallocate_buffers_() {
|
|||||||
this->input_buffer_ = nullptr;
|
this->input_buffer_ = nullptr;
|
||||||
|
|
||||||
#ifdef USE_SPEAKER
|
#ifdef USE_SPEAKER
|
||||||
if (this->speaker_buffer_ != nullptr) {
|
if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) {
|
||||||
ExternalRAMAllocator<uint8_t> speaker_deallocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
ExternalRAMAllocator<uint8_t> speaker_deallocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
||||||
speaker_deallocator.deallocate(this->speaker_buffer_, SPEAKER_BUFFER_SIZE);
|
speaker_deallocator.deallocate(this->speaker_buffer_, SPEAKER_BUFFER_SIZE);
|
||||||
this->speaker_buffer_ = nullptr;
|
this->speaker_buffer_ = nullptr;
|
||||||
@ -389,14 +390,7 @@ void VoiceAssistant::loop() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (playing) {
|
if (playing) {
|
||||||
this->set_timeout("playing", 2000, [this]() {
|
this->start_playback_timeout_();
|
||||||
this->cancel_timeout("speaker-timeout");
|
|
||||||
this->set_state_(State::IDLE, State::IDLE);
|
|
||||||
|
|
||||||
api::VoiceAssistantAnnounceFinished msg;
|
|
||||||
msg.success = true;
|
|
||||||
this->api_client_->send_voice_assistant_announce_finished(msg);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -614,6 +608,8 @@ void VoiceAssistant::request_stop() {
|
|||||||
this->desired_state_ = State::IDLE;
|
this->desired_state_ = State::IDLE;
|
||||||
break;
|
break;
|
||||||
case State::AWAITING_RESPONSE:
|
case State::AWAITING_RESPONSE:
|
||||||
|
this->signal_stop_();
|
||||||
|
break;
|
||||||
case State::STREAMING_RESPONSE:
|
case State::STREAMING_RESPONSE:
|
||||||
case State::RESPONSE_FINISHED:
|
case State::RESPONSE_FINISHED:
|
||||||
break; // Let the incoming audio stream finish then it will go to idle.
|
break; // Let the incoming audio stream finish then it will go to idle.
|
||||||
@ -631,6 +627,17 @@ void VoiceAssistant::signal_stop_() {
|
|||||||
this->api_client_->send_voice_assistant_request(msg);
|
this->api_client_->send_voice_assistant_request(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VoiceAssistant::start_playback_timeout_() {
|
||||||
|
this->set_timeout("playing", 100, [this]() {
|
||||||
|
this->cancel_timeout("speaker-timeout");
|
||||||
|
this->set_state_(State::IDLE, State::IDLE);
|
||||||
|
|
||||||
|
api::VoiceAssistantAnnounceFinished msg;
|
||||||
|
msg.success = true;
|
||||||
|
this->api_client_->send_voice_assistant_announce_finished(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||||
ESP_LOGD(TAG, "Event Type: %" PRId32, msg.event_type);
|
ESP_LOGD(TAG, "Event Type: %" PRId32, msg.event_type);
|
||||||
switch (msg.event_type) {
|
switch (msg.event_type) {
|
||||||
@ -715,6 +722,8 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
|||||||
#ifdef USE_MEDIA_PLAYER
|
#ifdef USE_MEDIA_PLAYER
|
||||||
if (this->media_player_ != nullptr) {
|
if (this->media_player_ != nullptr) {
|
||||||
this->media_player_->make_call().set_media_url(url).set_announcement(true).perform();
|
this->media_player_->make_call().set_media_url(url).set_announcement(true).perform();
|
||||||
|
// Start the playback timeout, as the media player state isn't immediately updated
|
||||||
|
this->start_playback_timeout_();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
this->tts_end_trigger_->trigger(url);
|
this->tts_end_trigger_->trigger(url);
|
||||||
@ -725,7 +734,11 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
|||||||
}
|
}
|
||||||
case api::enums::VOICE_ASSISTANT_RUN_END: {
|
case api::enums::VOICE_ASSISTANT_RUN_END: {
|
||||||
ESP_LOGD(TAG, "Assist Pipeline ended");
|
ESP_LOGD(TAG, "Assist Pipeline ended");
|
||||||
if (this->state_ == State::STREAMING_MICROPHONE) {
|
if ((this->state_ == State::STARTING_PIPELINE) || (this->state_ == State::AWAITING_RESPONSE)) {
|
||||||
|
// Pipeline ended before starting microphone
|
||||||
|
// Or there wasn't a TTS start event ("nevermind")
|
||||||
|
this->set_state_(State::IDLE, State::IDLE);
|
||||||
|
} else if (this->state_ == State::STREAMING_MICROPHONE) {
|
||||||
this->ring_buffer_->reset();
|
this->ring_buffer_->reset();
|
||||||
#ifdef USE_ESP_ADF
|
#ifdef USE_ESP_ADF
|
||||||
if (this->use_wake_word_) {
|
if (this->use_wake_word_) {
|
||||||
@ -736,9 +749,6 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
|||||||
{
|
{
|
||||||
this->set_state_(State::IDLE, State::IDLE);
|
this->set_state_(State::IDLE, State::IDLE);
|
||||||
}
|
}
|
||||||
} else if (this->state_ == State::AWAITING_RESPONSE) {
|
|
||||||
// No TTS start event ("nevermind")
|
|
||||||
this->set_state_(State::IDLE, State::IDLE);
|
|
||||||
}
|
}
|
||||||
this->defer([this]() { this->end_trigger_->trigger(); });
|
this->defer([this]() { this->end_trigger_->trigger(); });
|
||||||
break;
|
break;
|
||||||
|
@ -40,6 +40,7 @@ enum VoiceAssistantFeature : uint32_t {
|
|||||||
FEATURE_SPEAKER = 1 << 1,
|
FEATURE_SPEAKER = 1 << 1,
|
||||||
FEATURE_API_AUDIO = 1 << 2,
|
FEATURE_API_AUDIO = 1 << 2,
|
||||||
FEATURE_TIMERS = 1 << 3,
|
FEATURE_TIMERS = 1 << 3,
|
||||||
|
FEATURE_ANNOUNCE = 1 << 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
@ -136,6 +137,12 @@ class VoiceAssistant : public Component {
|
|||||||
flags |= VoiceAssistantFeature::FEATURE_TIMERS;
|
flags |= VoiceAssistantFeature::FEATURE_TIMERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_MEDIA_PLAYER
|
||||||
|
if (this->media_player_ != nullptr) {
|
||||||
|
flags |= VoiceAssistantFeature::FEATURE_ANNOUNCE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,6 +216,7 @@ class VoiceAssistant : public Component {
|
|||||||
void set_state_(State state);
|
void set_state_(State state);
|
||||||
void set_state_(State state, State desired_state);
|
void set_state_(State state, State desired_state);
|
||||||
void signal_stop_();
|
void signal_stop_();
|
||||||
|
void start_playback_timeout_();
|
||||||
|
|
||||||
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
||||||
struct sockaddr_storage dest_addr_;
|
struct sockaddr_storage dest_addr_;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user