You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

368 lines
15 KiB

#include "main_control_service.hpp"
#include "iflytopcpp/core/components/stringutils.hpp"
#include "version.hpp"
using namespace iflytop;
using namespace core;
using namespace std;
/***********************************************************************************************************************
* ======================================================宏定义======================================================= *
***********************************************************************************************************************/
#define SET_DEVICE_STATE(id, value, uint) \
receipt["deviceState"][index]["id"] = id; \
receipt["deviceState"][index]["value"] = fmt::format("{}", value); \
receipt["deviceState"][index]["unit"] = uint; \
index++;
/*********************************************************************************************************************
* ======================================================代码======================================================= *
*********************************************************************************************************************/
void MainControlService::initializeVoiceProcess() {
m_beforeWakeupVoiceProcesser->setAmplifyDB(20);
m_beforeasrVoiceProcesser->setAmplifyDB(24);
logger->info("MainControlService::start.....");
/**
* @brief 声卡录音回调
* 1路,交给唤醒词预处理算法
* 1路,在唤醒的时候交给ASR预处理算法
*/
m_audioRecoderService->onRecordData.connect([this](shared_ptr<AudioClip> audioClip) {
if (!audioClip) {
logger->error("onRecordData audioClip is null");
return;
}
m_audioLoggingService->loggerMICVoice(audioClip); // 录音
m_commonVoiceProcesser->writeVoice(audioClip); // 交给通用预处理逻辑
});
m_commonVoiceProcesser->onAfterProcessVoice.connect([this](shared_ptr<AudioClip> audioClip) {
if (!audioClip) {
logger->error("onAfterProcessVoice audioClip is null");
return;
}
m_beforeWakeupVoiceProcesser->writeVoice(audioClip); // 交给唤醒词预处理逻辑
if (m_conversationSession) m_beforeasrVoiceProcesser->writeVoice(audioClip); // 交给asr预处理逻辑
});
/**
* @brief 唤醒词预处理算法回调
* 1路交给唤醒词算法
*/
m_beforeWakeupVoiceProcesser->onAfterProcessVoice.connect([this](shared_ptr<AudioClip> audioClip) {
if (!audioClip) {
logger->error("onAfterProcessVoice audioClip is null");
return;
}
m_audioLoggingService->loggerBeforeWakeupVoice(audioClip);
m_wakeupProcesser->processVoice(audioClip->data(), audioClip->size());
});
/**
* @brief 唤醒词触发回调
*/
m_wakeupProcesser->onWakeupSignal.connect([this](float wakeup_score) {
logger->info("onWakeupSignal wakeup_score {}", wakeup_score);
/**
* @brief 触发唤醒,构造session
*/
m_workQueue->enQueue([this]() { constructSession(); });
});
/**
* @brief asr预处理算法回调
*/
m_beforeasrVoiceProcesser->onAfterProcessVoice.connect([this](shared_ptr<AudioClip> audioClip) {
if (!audioClip) {
logger->error("onAfterProcessVoice audioClip is null");
return;
}
auto session = m_conversationSession;
if (!session) return;
if (zsteady_clock().elapsedTimeMs(session->getBuildtp()) < 1000) return;
m_audioLoggingService->loggerASRVoice(audioClip);
m_aiuiService->aiuiWrite((const char*)audioClip->data(), audioClip->size());
});
m_aiuiService->onMessage.connect([&](json& rxjson) {
lock_guard<recursive_mutex> lock(m_voiceprocessmutex);
json msg = rxjson;
m_workQueue->enQueue([this, msg]() {
try {
processasrResult(msg);
} catch (const std::exception& e) {
logger->error("processasrResult error:{}", e.what());
}
});
});
m_audioRecoderService->startRecord();
}
void MainControlService::triggerProcessConversationSession() {
m_smartSoundboxPlayer->playConversationTTS(m_conversationSession->getAsrTTSLocalURL(), nullptr);
json nlpResult = m_conversationSession->getNlpResult();
if (nlpResult["data"]["intent"]["shouldEndSession"] == "true") {
logger->info("endSession");
if (m_endsessionTimer->isRunning()) m_endsessionTimer->stop();
endSession();
return;
}
}
void MainControlService::processasrResult_nlp(json& rxjson) {
logger->info("rx nlp:{}", rxjson.dump());
m_conversationSession->setNlpResult(rxjson);
m_smartSoundboxPlayer->playConversationTTS(m_conversationSession->getAsrTTSLocalURL(), nullptr);
}
void MainControlService::processasrResult_tts(json& rxjson) {
/**
* @brief 接收从云端发过来的tts数据,并保存成文件
*/
logger->debug("rx tts:frame {}", rxjson["data"]["json_args"]["frame_id"].get<int>());
bool isendFrame = false;
string ttsurl;
m_aiuiService->parseTTSContent(rxjson, isendFrame, ttsurl);
if (isendFrame) {
logger->info("rx tts end,url={}", ttsurl);
m_conversationSession->setAsrTTSLocalURL(ttsurl);
triggerProcessConversationSession();
}
}
void MainControlService::processasrResult(json rxjson) {
lock_guard<recursive_mutex> lock(m_voiceprocessmutex);
string action = rxjson["action"];
if (action == "started") {
logger->info("processasr: rx started:{}", rxjson.dump());
} else if (action == "error") {
logger->info("processasr: rx error:{}", rxjson.dump());
} else if (action == "vad") {
logger->info("processasr: rx vad:{}", rxjson.dump());
} else if (action == "result") {
string sub = rxjson["data"]["sub"];
if (sub == "nlp") {
/**
* @brief 解析nlp数据
*/
processasrResult_nlp(rxjson);
} else if (sub == "tts") {
/**
* @brief 解析tts数据
*/
processasrResult_tts(rxjson);
} else if (sub == "iat") {
logger->info("rx iat:{}", rxjson.dump());
} else if (sub == "vad") {
logger->info("rx vad:{}", rxjson.dump());
} else {
logger->info("rx {}:{}", sub, rxjson.dump());
}
} else {
logger->info("rx unkown:{}", rxjson.dump());
}
}
void MainControlService::constructSession() {
/**
* @brief
* 1. 触发唤醒词语
* 2. 如果上一次session还没有结束,则结束上一次session
* 3. 初始化asr
* 4. 构建新的session
* 5. 启动定时器,如果10s内无人应答,则结束session
*/
lock_guard<recursive_mutex> lock(m_voiceprocessmutex);
m_smartSoundboxPlayer->triggerWakeup();
if (m_conversationSession) {
if (m_endsessionTimer->isRunning()) m_endsessionTimer->stop();
endSession();
}
m_conversationSession = make_shared<ConversationSession>();
logger->info("constructSession:============ {} ===========", m_conversationSession->getSessionId());
m_audioLoggingService->triggerWakeup(m_conversationSession->getSessionId());
m_aiuiService->aiuiInit();
if (m_endsessionTimer->isRunning()) m_endsessionTimer->stop();
m_endsessionTimer->setTimeout(
[this]() {
logger->info("no hum voice detected, end session");
endSession();
},
10000);
}
void MainControlService::endSession() {
lock_guard<recursive_mutex> lock(m_voiceprocessmutex);
if (m_conversationSession) {
m_conversationSession = nullptr;
m_aiuiService->aiuiFinished();
m_aiuiService->aiuiDestroy();
}
m_audioLoggingService->endwakeup();
}
void MainControlService::initialize() {
GET_TO_SERVICE(m_zwebService);
GET_TO_SERVICE(m_deviceIOService);
GET_TO_SERVICE(m_beforeWakeupVoiceProcesser);
GET_TO_SERVICE(m_beforeasrVoiceProcesser);
GET_TO_SERVICE(m_wakeupProcesser);
GET_TO_SERVICE(m_audioRecoderService);
GET_TO_SERVICE(m_audioLoggingService);
GET_TO_SERVICE(m_smartSoundboxPlayer);
GET_TO_SERVICE(m_aiuiService);
GET_TO_SERVICE(m_commonVoiceProcesser);
m_endsessionTimer.reset(new SimpleTimer("endSessionTimer"));
m_workQueue.reset(new WorkQueue("mainControlServiceVoiceProcessCtrlWQ"));
// 监听从webservice来的websocket消息
m_zwebService->startWork([this](const json& command, json& receipt) {
try {
processReceiveMessage(kzwebService, command, receipt);
} catch (const std::exception& e) {
logger->error("process message fail {}", string(e.what()));
} catch (...) {
logger->error("process message fail {}", "catch unknown exception");
}
});
/**
* @brief 初始化语音处理流程
*/
initializeVoiceProcess();
};
void MainControlService::processReceiveMessage(fromwhere_t fromwhere, const json& in, json& receipt) {
logger->info("process receive message from {},{}", fromwhere2str(fromwhere), in.dump());
if (in["command"] == "getVersion") {
receipt["version"] = VERSION;
}
/*********************************************************************************************************************
* ================================================日志动态配置接口================================================= *
*********************************************************************************************************************/
else if (in["command"] == "loggerSetLevel") {
int loggerLevel = in["loggerLevel"];
string loggerName = in["loggerName"];
logger->info("loggerSetLevel {} {}", loggerName, loggerLevel);
SpdLoggerFactory::Instance().createLogger(loggerName)->set_level((level::level_enum)loggerLevel);
} else if (in["command"] == "loggerGetAllLoggers") {
receipt["loggers"] = SpdLoggerFactory::Instance().loggerNames();
}
/*********************************************************************************************************************
* ================================================硬件测试=============================================================*
*********************************************************************************************************************/
else if (in["command"] == "getDeviceState") {
#if 0
{
"deviceState":[
{
"id":"wind_speed",
"value":"12",
"unit":"m/s"
}
]
}
#endif
int index = 0;
DeviceIOService::env_sensor_state_t env = m_deviceIOService->getEnvSensorState();
SET_DEVICE_STATE("wind_speed", env.wind_speed, "m/s");
SET_DEVICE_STATE("wind_direction", env.wind_direction, "m/s");
SET_DEVICE_STATE("temperature", env.temperature, "");
SET_DEVICE_STATE("humidity", env.humidity, "%");
SET_DEVICE_STATE("noise", env.noise, "dB");
SET_DEVICE_STATE("pm2_5", env.pm2_5, "ug/m³");
SET_DEVICE_STATE("pm10", env.pm10, "ug/m³");
SET_DEVICE_STATE("co2", env.co2, "ppm");
SET_DEVICE_STATE("atmospheric_pressure", env.atmospheric_pressure, "hPa");
SET_DEVICE_STATE("tvoc", env.tvoc, "ppm");
SET_DEVICE_STATE("hcho", env.hcho, "mg/m³");
SET_DEVICE_STATE("light_intensity", env.atmospheric_pressure, "lux");
SET_DEVICE_STATE("InterTemperature", m_deviceIOService->getInterTemperature(), "");
SET_DEVICE_STATE("fan1powerRate", m_deviceIOService->fanGetState(0), "%");
SET_DEVICE_STATE("fan2powerRate", m_deviceIOService->fanGetState(1), "%");
auto relaystate = m_deviceIOService->relayStateGet();
SET_DEVICE_STATE("routerPower", relaystate.getState(DeviceIOService::kRouterPower), "-");
SET_DEVICE_STATE("touchScreenPower", relaystate.getState(DeviceIOService::kTouchScreenPower), "-");
SET_DEVICE_STATE("usbChargerPower", relaystate.getState(DeviceIOService::kUsbChargerPower), "-");
SET_DEVICE_STATE("cameraPower", relaystate.getState(DeviceIOService::kCameraPower), "-");
SET_DEVICE_STATE("lightPower", relaystate.getState(DeviceIOService::kLightPower), "-");
auto inputdeviceState = m_deviceIOService->getinputState();
SET_DEVICE_STATE("emergency", inputdeviceState.getState(DeviceIOService::kEmergency), "-");
SET_DEVICE_STATE("waterImmersionSensor", inputdeviceState.getState(DeviceIOService::kWaterImmersionSensor), "-");
SET_DEVICE_STATE("humanProximitySensor", inputdeviceState.getState(DeviceIOService::kHumanProximitySensor), "-");
} else if (in["command"] == "relayControl") {
uint32_t type = in["type"];
bool value = in["value"];
m_deviceIOService->relayControl(type, value);
} else if (in["command"] == "fanSetState") {
int id = in["id"];
float power = in["power"];
m_deviceIOService->fanSetState(id, power);
} else if (in["command"] == "relayStateGet") {
auto relaystate = m_deviceIOService->relayStateGet();
receipt["state"]["rawState"] = StringUtils().bytet2Binary(relaystate.state, 32, false);
receipt["state"]["routerPower"] = relaystate.getState(DeviceIOService::kRouterPower);
receipt["state"]["touchScreenPower"] = relaystate.getState(DeviceIOService::kTouchScreenPower);
receipt["state"]["usbChargerPower"] = relaystate.getState(DeviceIOService::kUsbChargerPower);
receipt["state"]["cameraPower"] = relaystate.getState(DeviceIOService::kCameraPower);
receipt["state"]["lightPower"] = relaystate.getState(DeviceIOService::kLightPower);
} else if (in["command"] == "inputStateGet") {
auto inputdeviceState = m_deviceIOService->getinputState();
// logger->info("{}", inputdeviceState.state);
receipt["state"]["rawState"] = StringUtils().bytet2Binary(inputdeviceState.state, 32, false);
receipt["state"]["emergency"] = inputdeviceState.getState(DeviceIOService::kEmergency);
receipt["state"]["waterImmersionSensor"] = inputdeviceState.getState(DeviceIOService::kWaterImmersionSensor);
receipt["state"]["humanProximitySensor"] = inputdeviceState.getState(DeviceIOService::kHumanProximitySensor);
} else if (in["command"] == "idcardread") {
bool state = false;
string info;
m_deviceIOService->idcardread(state, info);
receipt["state"] = state;
receipt["info"] = info;
} else if (in["command"] == "getInterTemperature") {
receipt["temperature"] = m_deviceIOService->getInterTemperature();
} else if (in["command"] == "getEnvSensorState") {
DeviceIOService::env_sensor_state_t env = m_deviceIOService->getEnvSensorState();
receipt["wind_speed"] = env.wind_speed;
receipt["wind_direction"] = env.wind_direction;
receipt["temperature"] = env.temperature;
receipt["humidity"] = env.humidity;
receipt["noise"] = env.noise;
receipt["pm2_5"] = env.pm2_5;
receipt["pm10"] = env.pm10;
receipt["co2"] = env.co2;
receipt["atmospheric_pressure"] = env.atmospheric_pressure;
receipt["tvoc"] = env.tvoc;
receipt["hcho"] = env.hcho;
receipt["light_intensity"] = env.light_intensity;
} else if (in["command"] == "fanGetState") {
// int id = in["id"];
receipt["power"][0] = m_deviceIOService->fanGetState(0);
receipt["power"][1] = m_deviceIOService->fanGetState(0);
}
}