#include "ConsistencyCompareThread.h" #include "GlobalVariable.h" #include "ThreadManager.h" #include "CreateRecordFileThread.h" #include "ThreadAlarmManager.h" #include "CreateWAVThread.h" #include "LHCompareAPI.h" ConsistencyCompareThread::ConsistencyCompareThread(CalculateThreadInfo_t& threadInfo) : BaseCalculateThread(threadInfo) { } ConsistencyCompareThread::~ConsistencyCompareThread() { } /* 判断录音通道是否相等 */ // bool ConsistencyCompareThread::isRoadEqual(const SoundCardRoadInfo_t& roadInfo1, const SoundCardRoadInfo_t& roadInfo2) // { // /* r1对比m_r1,r2对比M_r2 */ // if( roadInfo1.nSoundCardNum == m_roadInfo1.nSoundCardNum && roadInfo1.roadInfo.nRoadNum == m_roadInfo1.roadInfo.nRoadNum && // roadInfo2.nSoundCardNum == m_roadInfo2.nSoundCardNum && roadInfo2.roadInfo.nRoadNum == m_roadInfo2.roadInfo.nRoadNum ) // { // return true; // } // /* 反过来对比一下 */ // if( roadInfo1.nSoundCardNum == m_roadInfo2.nSoundCardNum && roadInfo1.roadInfo.nRoadNum == m_roadInfo2.roadInfo.nRoadNum && // roadInfo2.nSoundCardNum == m_roadInfo1.nSoundCardNum && roadInfo2.roadInfo.nRoadNum == m_roadInfo1.roadInfo.nRoadNum ) // { // return true; // } // return false; // } /* 初始化 */ bool ConsistencyCompareThread::initConsistencyCompare() { /* 初始化数据 */ if(!initData()) { SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase); return false; } SPDLOG_LOGGER_INFO(m_logger, " ★ {} 一致性对比功能(调用动态库)初始化完成 ", m_logBase); return true; } /* 比对函数 */ bool ConsistencyCompareThread::compareConsistencyData() { /*-------------------------------------------------------------- * 更新最新数据 *--------------------------------------------------------------*/ m_pCreateWAVThread1->getLatestFileName(m_wavFilePath1); m_pCreateWAVThread2->getLatestFileName(m_wavFilePath2); /* 检查是否有新的数据 */ if(m_wavFilePath1 == m_prevWavFilePath1 || m_wavFilePath2 == m_prevWavFilePath2) { // SPDLOG_LOGGER_INFO(m_logger, "{} 检测到文件路径未变化", m_logBase); return true; } /*-------------------------------------------------------------- * 开始比对计算,并保存计算结果 *--------------------------------------------------------------*/ if(!compareConsistency()) { return false; } /* 计算一致性结果 */ computeResult(); m_prevWavFilePath1 = m_wavFilePath1; // 更新上一个wav文件路径 m_prevWavFilePath2 = m_wavFilePath2; // 更新上一个wav文件路径 return true; } /* 清理数据 */ void ConsistencyCompareThread::clearConsistencyCompareData() { clearData(); SPDLOG_LOGGER_INFO(m_logger, " ★ {} 一致性对比功能(调用动态库)清理完成 ", m_logBase); } /* 线程功能函数 */ void ConsistencyCompareThread::task() { m_isRunning = true; /* 初始化 */ if(!initData()) { SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase); return; } SPDLOG_LOGGER_INFO(m_logger, " ★ {} 一致性对比线程(调用动态库)开始运行 ", m_logBase); while(m_isRunning) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); /* 判断是否开启不一致检测 */ if(m_isEnableNotConsistencyDetect.load() == false) { /* 不开启不一致检测,直接返回一致性结果 */ m_isConsistency = true; m_isConsistencyWarning = false; continue; // 跳过后续的计算 } /* 判断是否在检测时间段内 */ if(m_isInDetectPeriod.load() == false) { /* 不在检测时间段内,不需要比对,结果一直为一致性 */ m_isConsistency = true; m_isConsistencyWarning = false; /* 如果此时还在非一致性报警中,结束报警 */ if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm) { saveAlarmInfo(); } continue; } compareConsistencyData(); } clearData(); SPDLOG_LOGGER_WARN(m_logger, " ★ {} 一致性对比线程(调用动态库)已结束运行 ", m_logBase); } /* 初始化数据 */ bool ConsistencyCompareThread::initData() { if(m_threadInfo.compareItemInfo.mapRoad.size() < 2) { SPDLOG_LOGGER_ERROR(m_logger, "{} 录音通道信息不足,至少需要两个通道", m_logBase); return false; } /* 获取两个录音通道的信息 */ auto it = m_threadInfo.compareItemInfo.mapRoad.begin(); m_itemRoadInfo1 = it.value(); // 第一个通道 it++; m_itemRoadInfo2 = it.value(); // 第二个通道 m_logBase = fmt::format("对比通道 {}:{} - {}:{}", m_itemRoadInfo1.scRoadInfo.strSoundCardName.toStdString(), m_itemRoadInfo1.scRoadInfo.roadInfo.nRoadNum, m_itemRoadInfo2.scRoadInfo.strSoundCardName.toStdString(), m_itemRoadInfo2.scRoadInfo.roadInfo.nRoadNum); /* 获取创建wav文件的指针 */ auto startTime = std::chrono::steady_clock::now(); // 记录开始时间 while(true) { if(m_pCreateWAVThread1 == nullptr) { m_pCreateWAVThread1 = ThreadMan.getCreateWAVThread(m_itemRoadInfo1.scRoadInfo.nSoundCardNum, m_itemRoadInfo1.scRoadInfo.roadInfo.nRoadNum); } if(m_pCreateWAVThread2 == nullptr) { m_pCreateWAVThread2 = ThreadMan.getCreateWAVThread(m_itemRoadInfo2.scRoadInfo.nSoundCardNum, m_itemRoadInfo2.scRoadInfo.roadInfo.nRoadNum); } /* 获取生成报警音频文件的线程 */ if(m_threadCreateAlarmFile1 == nullptr) { m_threadCreateAlarmFile1 = ThreadMan.getCreateRecordFileThread(m_itemRoadInfo1.scRoadInfo.nSoundCardNum, m_itemRoadInfo1.scRoadInfo.roadInfo.nRoadNum); } if(m_threadCreateAlarmFile2 == nullptr) { m_threadCreateAlarmFile2 = ThreadMan.getCreateRecordFileThread(m_itemRoadInfo2.scRoadInfo.nSoundCardNum, m_itemRoadInfo2.scRoadInfo.roadInfo.nRoadNum); } if( m_pCreateWAVThread1 != nullptr && m_pCreateWAVThread2 != nullptr && m_threadCreateAlarmFile1 != nullptr && m_threadCreateAlarmFile2 != nullptr ) { break; // 获取到两个线程,跳出循环 } /* 超过10秒还没有获取到线程,返回失败 */ if(std::chrono::steady_clock::now() - startTime > std::chrono::seconds(10)) { SPDLOG_LOGGER_ERROR(m_logger, "{} 获取生成音量的线程超时", m_logBase); return false; } std::this_thread::sleep_for(std::chrono::milliseconds(10)); } if(m_pCreateWAVThread1 == nullptr || m_pCreateWAVThread2 == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 获取录音线程失败", m_logBase); return false; } if(m_threadCreateAlarmFile1 == nullptr || m_threadCreateAlarmFile2 == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 获取生成报警音频文件的线程失败", m_logBase); return false; } return true; } /* 清理数据 */ void ConsistencyCompareThread::clearData() { m_isRunning = false; m_pCreateWAVThread1 = nullptr; m_pCreateWAVThread2 = nullptr; /* 设置标志位 */ m_isRunning = false; m_isStop.store(true); m_threadInfo.threadState = EThreadState::State_Stopped; } /* 比对两个wav文件的一致性 */ bool ConsistencyCompareThread::compareConsistency() { /* 计算比对需要的时间 */ std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now(); CompareResult* result = LHCompare(m_wavFilePath1.fileName.c_str(), m_wavFilePath2.fileName.c_str(), m_sensitivity); if(result == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 一致性比对失败,可能是文件格式不支持或动态库加载失败", m_logBase); return false; } /* 计算比对耗时 */ std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now(); std::chrono::duration duration = endTime - startTime; SPDLOG_LOGGER_DEBUG(m_logger, "{} 一致性比对耗时: {}ms", m_logBase, std::chrono::duration_cast(duration).count()); /* 如果高相似度小于1,将两个通道反过来对比一下 */ if(result->highest_similarity < 1) { delete result; result = nullptr; SPDLOG_LOGGER_WARN(m_logger, "{} 高相似度小于1,尝试反向对比", m_logBase); result = LHCompare(m_wavFilePath2.fileName.c_str(), m_wavFilePath1.fileName.c_str(), m_sensitivity); if(result == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 一致性比对失败,可能是文件格式不支持或动态库加载失败", m_logBase); return false; } } // SPDLOG_LOGGER_DEBUG(m_logger, "{} 一致性比对结果: 源文件: {}, 目标文件: {}, 最高相似度: {:.3f}, 平均相似度: {:.3f}", // m_logBase, m_wavFilePath1.fileName, m_wavFilePath2.fileName, result->highest_similarity, result->average_similarity); /* 保存结果 */ m_consistencyResult.AddResult(result->highest_similarity / 100.0); delete result; result = nullptr; return true; } /* 根据动态库返回的结果计算一致性 */ bool ConsistencyCompareThread::computeResult() { std::string strAIValue, strAIValueNot; auto consistencyState = m_consistencyResult.computeConsistency(m_numCompareContinue, m_fConsistencyThreshold, strAIValue); auto notConsisencyState = m_consistencyResult.computeNotConsistency(m_numCompareContinue, m_fNotConsistencyThreshold, strAIValueNot); if (eConsistencyState::eCS_Consistency == consistencyState) { /* 计算出的一致性是确定的 */ m_isConsistency.store(true); m_isConsistencyWarning.store(false); } else if(eConsistencyState::eCS_Consistency == notConsisencyState) { /* 计算出的不一致性是确定的 */ m_isConsistency.store(false); m_isConsistencyWarning.store(true); }else { /* 都不是确定的一致性和不一致性,使用上次的结果 */ m_isConsistency.store(m_isConsistencyLatest.load()); m_isConsistencyWarning.store(true); } return true; } /* 保存报警信息 */ void ConsistencyCompareThread::saveAlarmInfo() { if(m_isConsistency) { /* 这次是一致的,判断之前是否在一致性报警中 */ if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm) { /* 之前在一致性报警中,这次一致,结束不一致性报警 */ m_alarmConsistencyMain.isAlarm = false; m_alarmConsistencySub.isAlarm = false; /* 结束时间向前推1秒 */ m_alarmConsistencyMain.EndTime = m_wavFilePath1.endDateTime.addSecs(1); m_alarmConsistencySub.EndTime = m_wavFilePath2.endDateTime.addSecs(1); /* 结束录制报警音频 */ m_threadCreateAlarmFile1->stopRecordAlarmFile(m_alarmConsistencyMain); m_threadCreateAlarmFile2->stopRecordAlarmFile(m_alarmConsistencySub); /* 将报警信息写入数据库 */ AlarmManager.addAlarmInfo(m_alarmConsistencyMain); AlarmManager.addAlarmInfo(m_alarmConsistencySub); SPDLOG_LOGGER_INFO(m_logger, "{}: 一致性报警结束", m_logBase); /* 清除报警信息 */ m_alarmConsistencyMain = AlarmInfo_t(); m_alarmConsistencySub = AlarmInfo_t(); } }else { /* 不一致,判断之前的一致性,判断一个就可以了 */ if(!m_alarmConsistencySub.isAlarm) { /* 开是不一致报警 */ m_alarmConsistencyMain.isAlarm = true; m_alarmConsistencySub.isAlarm = true; m_alarmConsistencyMain.CompareItemID = m_threadInfo.compareItemInfo.nID; m_alarmConsistencySub.CompareItemID = m_threadInfo.compareItemInfo.nID; m_alarmConsistencyMain.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString(); m_alarmConsistencySub.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString(); m_alarmConsistencyMain.RoadInfo = m_itemRoadInfo1; m_alarmConsistencySub.RoadInfo = m_itemRoadInfo2; m_alarmConsistencyMain.AlarmType = EAlarmType::EAR_Consistency; m_alarmConsistencySub.AlarmType = EAlarmType::EAR_Consistency; /* 计算开始时间,开始时间计算方法: 单次计算的时间长度是 numFileDuration, 计算 m_numCompareContinue 次才会不一致性报警,因此向前推 m_numFileDuration * m_numCompareContinue 秒 */ int seconds = m_numFileDuration * m_numCompareContinue; /* 因为 m_numCompareContinue 次计算也包括这次的文件,所以从结束时间开始向前推 */ m_alarmConsistencyMain.StartTime = m_wavFilePath1.endDateTime.addSecs(-seconds); m_alarmConsistencySub.StartTime = m_wavFilePath2.endDateTime.addSecs(-seconds); SPDLOG_LOGGER_WARN(m_logger, "{}: 不一致报警开始", m_logBase); m_threadCreateAlarmFile1->startRecordAlarmFile(m_alarmConsistencyMain); m_threadCreateAlarmFile2->startRecordAlarmFile(m_alarmConsistencySub); } } } /* 结束报警 */ void ConsistencyCompareThread::endAlarm() { m_isConsistency = true; /* 这次是一致的,判断之前是否在一致性报警中 */ if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm) { /* 之前在一致性报警中,这次一致,结束不一致性报警 */ m_alarmConsistencyMain.isAlarm = false; m_alarmConsistencySub.isAlarm = false; /* 结束时间向前推1秒 */ m_alarmConsistencyMain.EndTime = m_wavFilePath1.endDateTime.addSecs(1); m_alarmConsistencySub.EndTime = m_wavFilePath2.endDateTime.addSecs(1); /* 结束录制报警音频 */ m_threadCreateAlarmFile1->stopRecordAlarmFile(m_alarmConsistencyMain); m_threadCreateAlarmFile2->stopRecordAlarmFile(m_alarmConsistencySub); /* 将报警信息写入数据库 */ AlarmManager.addAlarmInfo(m_alarmConsistencyMain); AlarmManager.addAlarmInfo(m_alarmConsistencySub); SPDLOG_LOGGER_INFO(m_logger, "{}: 一致性报警结束", m_logBase); /* 清除报警信息 */ m_alarmConsistencyMain = AlarmInfo_t(); m_alarmConsistencySub = AlarmInfo_t(); } }