forked from xiaozhi/xiaozhi-esp32
feat: Use BOOT button to enter audio testing state when Wi-Fi configuring
This commit is contained in:
@@ -45,6 +45,7 @@ static const char* const STATE_STRINGS[] = {
|
|||||||
"speaking",
|
"speaking",
|
||||||
"upgrading",
|
"upgrading",
|
||||||
"activating",
|
"activating",
|
||||||
|
"audio_testing",
|
||||||
"fatal_error",
|
"fatal_error",
|
||||||
"invalid_state"
|
"invalid_state"
|
||||||
};
|
};
|
||||||
@@ -290,10 +291,31 @@ void Application::PlaySound(const std::string_view& sound) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::EnterAudioTestingMode() {
|
||||||
|
ESP_LOGI(TAG, "Entering audio testing mode");
|
||||||
|
ResetDecoder();
|
||||||
|
SetDeviceState(kDeviceStateAudioTesting);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::ExitAudioTestingMode() {
|
||||||
|
ESP_LOGI(TAG, "Exiting audio testing mode");
|
||||||
|
SetDeviceState(kDeviceStateWifiConfiguring);
|
||||||
|
// Copy audio_testing_queue_ to audio_decode_queue_
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
audio_decode_queue_ = std::move(audio_testing_queue_);
|
||||||
|
audio_decode_cv_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
void Application::ToggleChatState() {
|
void Application::ToggleChatState() {
|
||||||
if (device_state_ == kDeviceStateActivating) {
|
if (device_state_ == kDeviceStateActivating) {
|
||||||
SetDeviceState(kDeviceStateIdle);
|
SetDeviceState(kDeviceStateIdle);
|
||||||
return;
|
return;
|
||||||
|
} else if (device_state_ == kDeviceStateWifiConfiguring) {
|
||||||
|
EnterAudioTestingMode();
|
||||||
|
return;
|
||||||
|
} else if (device_state_ == kDeviceStateAudioTesting) {
|
||||||
|
ExitAudioTestingMode();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!protocol_) {
|
if (!protocol_) {
|
||||||
@@ -327,6 +349,9 @@ void Application::StartListening() {
|
|||||||
if (device_state_ == kDeviceStateActivating) {
|
if (device_state_ == kDeviceStateActivating) {
|
||||||
SetDeviceState(kDeviceStateIdle);
|
SetDeviceState(kDeviceStateIdle);
|
||||||
return;
|
return;
|
||||||
|
} else if (device_state_ == kDeviceStateWifiConfiguring) {
|
||||||
|
EnterAudioTestingMode();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!protocol_) {
|
if (!protocol_) {
|
||||||
@@ -354,6 +379,11 @@ void Application::StartListening() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Application::StopListening() {
|
void Application::StopListening() {
|
||||||
|
if (device_state_ == kDeviceStateAudioTesting) {
|
||||||
|
ExitAudioTestingMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const std::array<int, 3> valid_states = {
|
const std::array<int, 3> valid_states = {
|
||||||
kDeviceStateListening,
|
kDeviceStateListening,
|
||||||
kDeviceStateSpeaking,
|
kDeviceStateSpeaking,
|
||||||
@@ -824,6 +854,28 @@ void Application::OnAudioOutput() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Application::OnAudioInput() {
|
void Application::OnAudioInput() {
|
||||||
|
if (device_state_ == kDeviceStateAudioTesting) {
|
||||||
|
if (audio_testing_queue_.size() >= AUDIO_TESTING_MAX_DURATION_MS / OPUS_FRAME_DURATION_MS) {
|
||||||
|
ExitAudioTestingMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<int16_t> data;
|
||||||
|
int samples = OPUS_FRAME_DURATION_MS * 16000 / 1000;
|
||||||
|
if (ReadAudio(data, 16000, samples)) {
|
||||||
|
background_task_->Schedule([this, data = std::move(data)]() mutable {
|
||||||
|
opus_encoder_->Encode(std::move(data), [this](std::vector<uint8_t>&& opus) {
|
||||||
|
AudioStreamPacket packet;
|
||||||
|
packet.payload = std::move(opus);
|
||||||
|
packet.frame_duration = OPUS_FRAME_DURATION_MS;
|
||||||
|
packet.sample_rate = 16000;
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
audio_testing_queue_.push_back(std::move(packet));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (wake_word_->IsDetectionRunning()) {
|
if (wake_word_->IsDetectionRunning()) {
|
||||||
std::vector<int16_t> data;
|
std::vector<int16_t> data;
|
||||||
int samples = wake_word_->GetFeedSize();
|
int samples = wake_word_->GetFeedSize();
|
||||||
@@ -834,6 +886,7 @@ void Application::OnAudioInput() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_processor_->IsRunning()) {
|
if (audio_processor_->IsRunning()) {
|
||||||
std::vector<int16_t> data;
|
std::vector<int16_t> data;
|
||||||
int samples = audio_processor_->GetFeedSize();
|
int samples = audio_processor_->GetFeedSize();
|
||||||
|
|||||||
@@ -44,11 +44,13 @@ enum DeviceState {
|
|||||||
kDeviceStateSpeaking,
|
kDeviceStateSpeaking,
|
||||||
kDeviceStateUpgrading,
|
kDeviceStateUpgrading,
|
||||||
kDeviceStateActivating,
|
kDeviceStateActivating,
|
||||||
|
kDeviceStateAudioTesting,
|
||||||
kDeviceStateFatalError
|
kDeviceStateFatalError
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OPUS_FRAME_DURATION_MS 60
|
#define OPUS_FRAME_DURATION_MS 60
|
||||||
#define MAX_AUDIO_PACKETS_IN_QUEUE (2400 / OPUS_FRAME_DURATION_MS)
|
#define MAX_AUDIO_PACKETS_IN_QUEUE (2400 / OPUS_FRAME_DURATION_MS)
|
||||||
|
#define AUDIO_TESTING_MAX_DURATION_MS 10000
|
||||||
|
|
||||||
class Application {
|
class Application {
|
||||||
public:
|
public:
|
||||||
@@ -111,6 +113,7 @@ private:
|
|||||||
std::list<AudioStreamPacket> audio_send_queue_;
|
std::list<AudioStreamPacket> audio_send_queue_;
|
||||||
std::list<AudioStreamPacket> audio_decode_queue_;
|
std::list<AudioStreamPacket> audio_decode_queue_;
|
||||||
std::condition_variable audio_decode_cv_;
|
std::condition_variable audio_decode_cv_;
|
||||||
|
std::list<AudioStreamPacket> audio_testing_queue_;
|
||||||
|
|
||||||
// 新增:用于维护音频包的timestamp队列
|
// 新增:用于维护音频包的timestamp队列
|
||||||
std::list<uint32_t> timestamp_queue_;
|
std::list<uint32_t> timestamp_queue_;
|
||||||
@@ -134,6 +137,8 @@ private:
|
|||||||
void OnClockTimer();
|
void OnClockTimer();
|
||||||
void SetListeningMode(ListeningMode mode);
|
void SetListeningMode(ListeningMode mode);
|
||||||
void AudioLoop();
|
void AudioLoop();
|
||||||
|
void EnterAudioTestingMode();
|
||||||
|
void ExitAudioTestingMode();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _APPLICATION_H_
|
#endif // _APPLICATION_H_
|
||||||
|
|||||||
@@ -205,7 +205,8 @@ void CircularStrip::OnStateChanged() {
|
|||||||
SetAllColor(color);
|
SetAllColor(color);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeviceStateListening: {
|
case kDeviceStateListening:
|
||||||
|
case kDeviceStateAudioTesting: {
|
||||||
StripColor color = { default_brightness_, low_brightness_, low_brightness_ };
|
StripColor color = { default_brightness_, low_brightness_, low_brightness_ };
|
||||||
SetAllColor(color);
|
SetAllColor(color);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ void GpioLed::OnStateChanged() {
|
|||||||
TurnOn();
|
TurnOn();
|
||||||
break;
|
break;
|
||||||
case kDeviceStateListening:
|
case kDeviceStateListening:
|
||||||
|
case kDeviceStateAudioTesting:
|
||||||
if (app.IsVoiceDetected()) {
|
if (app.IsVoiceDetected()) {
|
||||||
SetBrightness(HIGH_BRIGHTNESS);
|
SetBrightness(HIGH_BRIGHTNESS);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ void SingleLed::OnStateChanged() {
|
|||||||
TurnOn();
|
TurnOn();
|
||||||
break;
|
break;
|
||||||
case kDeviceStateListening:
|
case kDeviceStateListening:
|
||||||
|
case kDeviceStateAudioTesting:
|
||||||
if (app.IsVoiceDetected()) {
|
if (app.IsVoiceDetected()) {
|
||||||
SetColor(HIGH_BRIGHTNESS, 0, 0);
|
SetColor(HIGH_BRIGHTNESS, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user