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",
|
||||
"upgrading",
|
||||
"activating",
|
||||
"audio_testing",
|
||||
"fatal_error",
|
||||
"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() {
|
||||
if (device_state_ == kDeviceStateActivating) {
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
return;
|
||||
} else if (device_state_ == kDeviceStateWifiConfiguring) {
|
||||
EnterAudioTestingMode();
|
||||
return;
|
||||
} else if (device_state_ == kDeviceStateAudioTesting) {
|
||||
ExitAudioTestingMode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!protocol_) {
|
||||
@@ -327,6 +349,9 @@ void Application::StartListening() {
|
||||
if (device_state_ == kDeviceStateActivating) {
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
return;
|
||||
} else if (device_state_ == kDeviceStateWifiConfiguring) {
|
||||
EnterAudioTestingMode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!protocol_) {
|
||||
@@ -354,6 +379,11 @@ void Application::StartListening() {
|
||||
}
|
||||
|
||||
void Application::StopListening() {
|
||||
if (device_state_ == kDeviceStateAudioTesting) {
|
||||
ExitAudioTestingMode();
|
||||
return;
|
||||
}
|
||||
|
||||
const std::array<int, 3> valid_states = {
|
||||
kDeviceStateListening,
|
||||
kDeviceStateSpeaking,
|
||||
@@ -824,6 +854,28 @@ void Application::OnAudioOutput() {
|
||||
}
|
||||
|
||||
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()) {
|
||||
std::vector<int16_t> data;
|
||||
int samples = wake_word_->GetFeedSize();
|
||||
@@ -834,6 +886,7 @@ void Application::OnAudioInput() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_processor_->IsRunning()) {
|
||||
std::vector<int16_t> data;
|
||||
int samples = audio_processor_->GetFeedSize();
|
||||
|
||||
@@ -44,11 +44,13 @@ enum DeviceState {
|
||||
kDeviceStateSpeaking,
|
||||
kDeviceStateUpgrading,
|
||||
kDeviceStateActivating,
|
||||
kDeviceStateAudioTesting,
|
||||
kDeviceStateFatalError
|
||||
};
|
||||
|
||||
#define OPUS_FRAME_DURATION_MS 60
|
||||
#define MAX_AUDIO_PACKETS_IN_QUEUE (2400 / OPUS_FRAME_DURATION_MS)
|
||||
#define AUDIO_TESTING_MAX_DURATION_MS 10000
|
||||
|
||||
class Application {
|
||||
public:
|
||||
@@ -111,6 +113,7 @@ private:
|
||||
std::list<AudioStreamPacket> audio_send_queue_;
|
||||
std::list<AudioStreamPacket> audio_decode_queue_;
|
||||
std::condition_variable audio_decode_cv_;
|
||||
std::list<AudioStreamPacket> audio_testing_queue_;
|
||||
|
||||
// 新增:用于维护音频包的timestamp队列
|
||||
std::list<uint32_t> timestamp_queue_;
|
||||
@@ -134,6 +137,8 @@ private:
|
||||
void OnClockTimer();
|
||||
void SetListeningMode(ListeningMode mode);
|
||||
void AudioLoop();
|
||||
void EnterAudioTestingMode();
|
||||
void ExitAudioTestingMode();
|
||||
};
|
||||
|
||||
#endif // _APPLICATION_H_
|
||||
|
||||
@@ -205,7 +205,8 @@ void CircularStrip::OnStateChanged() {
|
||||
SetAllColor(color);
|
||||
break;
|
||||
}
|
||||
case kDeviceStateListening: {
|
||||
case kDeviceStateListening:
|
||||
case kDeviceStateAudioTesting: {
|
||||
StripColor color = { default_brightness_, low_brightness_, low_brightness_ };
|
||||
SetAllColor(color);
|
||||
break;
|
||||
|
||||
@@ -220,6 +220,7 @@ void GpioLed::OnStateChanged() {
|
||||
TurnOn();
|
||||
break;
|
||||
case kDeviceStateListening:
|
||||
case kDeviceStateAudioTesting:
|
||||
if (app.IsVoiceDetected()) {
|
||||
SetBrightness(HIGH_BRIGHTNESS);
|
||||
} else {
|
||||
|
||||
@@ -136,6 +136,7 @@ void SingleLed::OnStateChanged() {
|
||||
TurnOn();
|
||||
break;
|
||||
case kDeviceStateListening:
|
||||
case kDeviceStateAudioTesting:
|
||||
if (app.IsVoiceDetected()) {
|
||||
SetColor(HIGH_BRIGHTNESS, 0, 0);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user