#include "CompareDoubleThread.h" #include "GlobalInfo.h" #include "GlobalVariable.h" #include "GlobalInfo.h" #include "ThreadManager.h" #include "ConsistencyCompareThread.h" #include "CreateLongFileThread.h" #include "ThreadAlarmManager.h" CompareDoubleThread::CompareDoubleThread(CalculateThreadInfo_t& compareItemInfo) : BaseCalculateThread(compareItemInfo) { m_logger = spdlog::get("ACAServer"); if(m_logger == nullptr) { fmt::print("CompareDouble: ACAServer Logger not found.\n"); return; } m_threadInfo = compareItemInfo; } CompareDoubleThread::~CompareDoubleThread() { } /* 获取计算结果 */ OneRoadVolume_t CompareDoubleThread::getVolumeInfo() { std::lock_guard lock(m_mutexVolumeInfo); return m_roadResult; } /** * @brief 获取最新的计算结果,这里目前只有一致性检测的结果,没有噪音检测的结果 * 1、这里目前没有进行时间判断,直接返回最新的结果 * * @param volumeInfo * @return true * @return false */ bool CompareDoubleThread::getlastResult(OneRoadVolume_t& volumeInfo) { std::lock_guard lock(m_mutexVolumeInfo); volumeInfo.isConsistency = m_roadResult.isConsistency; volumeInfo.isNotConsistencyWarning = m_roadResult.isNotConsistencyWarning; return true; } /* 线程功能函数 */ void CompareDoubleThread::task() { /* 初始化数据 */ 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(10)); /* 使用比对动态库比对一致性 */ m_pConsistencyCompareThread->compareConsistencyData(); /* 更新数据 */ if(!updateData()) { continue; // 数据不足,继续等待 } // SPDLOG_LOGGER_INFO(m_logger, "{} 更新数据成功,开始计算音量数据", m_logBase); /* 计算音量数据 */ calculateData(); /* 保存结果,结果已经在上面那个函数中保存了 */ /* 清除标志位 */ m_isUpdated1 = false; m_isUpdated2 = false; } /* 清理数据 */ clearData(); SPDLOG_LOGGER_WARN(m_logger, " ★ {} 计算双通道对比的线程结束 ", m_logBase); m_threadInfo.threadState = EThreadState::State_Stopped; // 更新线程状态 } /* 初始化数据 */ bool CompareDoubleThread::initData() { if(m_threadInfo.compareItemInfo.mapRoad.size() < 2) { SPDLOG_LOGGER_WARN(m_logger, "{} 对比项信息错误,录音通道数量小于2", m_threadInfo.compareItemInfo.strName.toStdString()); return false; } auto it = m_threadInfo.compareItemInfo.mapRoad.begin(); m_itemRoadInfo1 = it.value(); m_roadInfo1 = it->scRoadInfo; it++; // 移动到下一个元素 m_roadInfo2 = it->scRoadInfo; // 录音通道2信息 m_itemRoadInfo2 = it.value(); m_logBase = fmt::format("{} 对比项: {}:{} - {}:{}", m_threadInfo.compareItemInfo.strName.toStdString(), m_roadInfo1.strSoundCardName.toStdString(), m_roadInfo1.roadInfo.nRoadNum, m_roadInfo2.strSoundCardName.toStdString(), m_roadInfo2.roadInfo.nRoadNum); m_offsetMSeconds = GInfo.offsetMSeconds(); // 获取偏移量 // m_calculateSeconds = GInfo.calculateDataSeconds(); // 获取计算需要的秒数 m_avgDBCalculateSeconds = GInfo.avgDBCalculateSeconds(); // 获取计算平均音量所需要的时长 m_silentThreshold = GInfo.silentThreshold(); // 获取静音阈值 m_sinSeconds = GInfo.sinSeconds(); // 获取正弦波计算所需要的时长 m_isAINotConsistencyAlone = GInfo.isAINotConsistencyAlone(); // 获取杭州台是否按上面的逻辑来 m_nIsSameBothMinDBWaitNum = GInfo.nIsSameBothMinDBWaitNum(); // 获取是否需要等待静音状态 m_nCompareTimeSpan = GInfo.compareTimeSpan(); // 获取比对时间间隔 /* 获取生成音量的线程,循环等待获取 */ auto startTime = std::chrono::steady_clock::now(); // 记录开始时间 while(true) { /* 获取创建音量包的线程 */ if(m_threadCreateDB1 == nullptr) { m_threadCreateDB1 = ThreadMan.getCreateDBThread(m_roadInfo1.nSoundCardNum, m_roadInfo1.roadInfo.nRoadNum); } if(m_threadCreateDB2 == nullptr) { m_threadCreateDB2 = ThreadMan.getCreateDBThread(m_roadInfo2.nSoundCardNum, m_roadInfo2.roadInfo.nRoadNum); } /* 获取生成报警音频文件的线程 */ if(m_threadCreateAlarmFile1 == nullptr) { m_threadCreateAlarmFile1 = ThreadMan.getCreateLongFileThread(m_roadInfo1.nSoundCardNum, m_roadInfo1.roadInfo.nRoadNum); } if(m_threadCreateAlarmFile2 == nullptr) { m_threadCreateAlarmFile2 = ThreadMan.getCreateLongFileThread(m_roadInfo2.nSoundCardNum, m_roadInfo2.roadInfo.nRoadNum); } if( m_threadCreateDB1 != nullptr && m_threadCreateDB2 != nullptr && m_threadCreateAlarmFile1 != nullptr && m_threadCreateAlarmFile2 != nullptr ) { break; // 获取到两个线程,跳出循环 } /* 超过10秒还没有获取到线程,返回失败 */ if(std::chrono::steady_clock::now() - startTime > std::chrono::seconds(10)) { return false; } std::this_thread::sleep_for(std::chrono::milliseconds(10)); } if(m_threadCreateDB1 == nullptr || m_threadCreateDB2 == 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; } /* 创建一致性比较的线程,这里不再单独开线程了,合并到这个线程中执行 */ m_pConsistencyCompareThread = new ConsistencyCompareThread(m_threadInfo); // if(m_pConsistencyCompareThread == nullptr) // { // SPDLOG_LOGGER_ERROR(m_logger, "{} 创建一致性比较线程失败", m_logBase); // return false; // } // CPPTP.add_task(&ConsistencyCompareThread::threadTask, m_pConsistencyCompareThread); /* 初始化对比功能 */ m_pConsistencyCompareThread->initConsistencyCompare(); return true; } /* 清理数据 */ void CompareDoubleThread::clearData() { // if(m_pConsistencyCompareThread != nullptr) // { // m_pConsistencyCompareThread->stopThreadBlock(); // 停止线程 // delete m_pConsistencyCompareThread; // m_pConsistencyCompareThread = nullptr; // } if(m_pConsistencyCompareThread != nullptr) { m_pConsistencyCompareThread->clearConsistencyCompareData(); delete m_pConsistencyCompareThread; m_pConsistencyCompareThread = nullptr; } } /* 更新数据 */ bool CompareDoubleThread::updateData() { /* 获取原始的音量值 */ if(m_isUpdated1 == false) { if(m_threadCreateDB1->getLatestResult(m_localData1.ringQueue) == false) { // SPDLOG_LOGGER_TRACE(m_logger, "{} 未获取通道1最新数据", m_logBase); return false; // 没有获取到最新数据,继续等待 } m_isUpdated1 = true; } if(m_isUpdated2 == false) { if(m_threadCreateDB2->getLatestResult(m_localData2.ringQueue) == false) { // SPDLOG_LOGGER_DEBUG(m_logger, "{} 未获取通道2最新数据", m_logBase); return false; // 没有获取到最新数据,继续等待 } m_isUpdated2 = true; } if(m_isUpdated1 == false || m_isUpdated2 == false) { // SPDLOG_LOGGER_TRACE(m_logger, "{} 队列数据未更新,等待数据更新", m_logBase); return false; } if(m_localData1.isEmpty() || m_localData2.isEmpty()) { SPDLOG_LOGGER_TRACE(m_logger, "{} 队列数据不足,等待数据更新", m_logBase); return false; } /* 获取一致性线程计算的结果 */ m_consistencyResult = m_pConsistencyCompareThread->getConsistencyResult(); return true; } /** * 再次判断噪音和不一致 * */ void CompareDoubleThread::calculateData() { // 2、用最新数据计算音频状态:静音、过载、反相 bool isAvgDBLessMin = false; /* 平均音量是否最小 */ bool isSin1 = false; /* 通道1是否正弦波 */ bool isSin2 = false; /* 通道2是否正弦波 */ bool isSinDBEqual = false; /* 通道1和通道2的正弦波音量是否相等 */ bool isOffsetSilence1 = false; /* 通道1偏移之后是否静音 */ bool isOffsetSilence2 = false; /* 通道2偏移之后是否静音 */ OneRoadVolume_t oneRoadVolume; /* 一个录音通道的音量信息,临时结果 */ /* 保存通道2的时间 */ oneRoadVolume.dateTime = m_localData2.ringQueue.back()->startTime; /* --------------------------------------------------------------- * 这一段计算音量偏移后的静音和正弦波(正弦波也是一种噪音,防止动态库检测不出来) * (正弦波结果貌似并没有用到) * ---------------------------------------------------------------*/ { /* 获取偏移值 */ long chn1Offset = 0; long chn2Offset = 0; calculateOffset(chn1Offset, chn2Offset); // 设置音频偏移 m_localData1.setOffset(chn1Offset); m_localData2.setOffset(chn2Offset); // 计算偏移之后的静音 int nSilentEndPos = 0, nSilentEndPos2 = 0; int nSilentStartPos = 0, nSilentStartPos2 = 0; isOffsetSilence1 = m_localData1.calculateSilent(m_volumeParam, m_avgDBCalculateSeconds, nSilentStartPos, nSilentEndPos); isOffsetSilence2 = m_localData2.calculateSilent(m_volumeParam, m_avgDBCalculateSeconds, nSilentStartPos2, nSilentEndPos2); isAvgDBLessMin = m_localData1.isAvgDBLessThan(m_avgDBCalculateSeconds, m_silentThreshold) && m_localData2.isAvgDBLessThan(m_avgDBCalculateSeconds, m_silentThreshold); // 音量小时不用判定正弦波 if (!isAvgDBLessMin) { // 正弦波处理:正弦波就是一个固定的音量值,这时不做判定,直接比较音量值 // (主次通道的音量值相同,并且是一个固定的音量值时,直接判定为一致) int nLeftDB1, nRightDB1; isSin1 = m_localData1.isSinDB(m_sinSeconds, m_avgDBCalculateSeconds, nLeftDB1, nRightDB1); int nLeftDB2, nRightDB2; isSin2 = m_localData2.isSinDB(m_sinSeconds, m_avgDBCalculateSeconds, nLeftDB2, nRightDB2); if (nLeftDB1 == nLeftDB2 && nRightDB1 == nRightDB2) { isSinDBEqual = true; } } /* 恢复音频偏移,下面也没有用到这两个环形队列的地方了,所以提到前面恢复 */ m_localData1.setOffset(0); m_localData2.setOffset(0); /* 这里貌似也没用到 */ // m_data1 = m_localData1; // m_data2 = m_localData2; } /* --------------------------------------------------------------- * 和动态库检测的一致性结果进行对比 * ---------------------------------------------------------------*/ { getLatestConsistencyStatus(oneRoadVolume); } if (isOffsetSilence1 && isOffsetSilence2) { m_bBothMinDB = ESW_BothMute_TRUE; } else { if (isAvgDBLessMin) { m_bBothMinDB = ESW_BothMinDB_TRUE; } else { if (isOffsetSilence1 || isOffsetSilence2) { m_bBothMinDB = ESW_OneMinDB_FALSE; } else { m_bBothMinDB = ESW_ALL_NOT; } } m_isSin1 = isSin1; m_isSin2 = isSin2; m_isSinDBEqual = isSinDBEqual; } /* --------------------------------------------------------------- * 保存计算信息,目前只保存了一致性结果和报警 * ---------------------------------------------------------------*/ { std::lock_guard lock(m_mutexVolumeInfo); /* 保存一致性结果 */ m_roadResult.isConsistency = oneRoadVolume.isConsistency; m_roadResult.isNotConsistencyWarning = oneRoadVolume.isNotConsistencyWarning; m_roadResult.dateTime = oneRoadVolume.dateTime; /* 保存报警信息 */ saveAlarmInfo(); } } /* 计算偏移值 */ void CompareDoubleThread::calculateOffset(long chn1Offset, long chn2Offset) { chn1Offset = 0; chn2Offset = 0; if(m_offsetMSeconds > 0) { chn1Offset = m_offsetMSeconds; } else if(m_offsetMSeconds < 0) { chn2Offset = std::abs(m_offsetMSeconds); } } /** * @brief 获取最新的一致性状态 * 1、先使用音量进行静音比对,都不是静音时,使用AI对比 * 2、是否使用AI对比由外部传入的配置决定 * * @param sendInfo * @return true * @return false */ bool CompareDoubleThread::getLatestConsistencyStatus(OneRoadVolume_t& oneRoad) { // 非对比时间时,默认为一致 if (!m_isCompareTime) { initMiniArray(); // SPDLOG_LOGGER_DEBUG(m_logger, "{}: 非对比时间时,默认为一致", m_chnName); oneRoad.isConsistency = true; return true; } /* 使用Python对比的结果,这里没有这个功能 */ /* 如果没有开启比较线程,默认为一致 */ if (!m_isRunCompareThread) { oneRoad.isConsistency = true; SPDLOG_LOGGER_INFO(m_logger, "{}: 没有开启比较线程,默认为一致", m_chnName); return true; } /* 不做一致性检测,返回一致性 */ if (!m_consistencyParam.GetConsistencySwitch()) { SPDLOG_LOGGER_INFO(m_logger, "{}: 一致性检测关闭,不做一致性检测,返回一致性", m_chnName); oneRoad.isConsistency = true; return true; } /* 判断是否开启计算这两个通道音量值的线程 * 如果两个线程都在不在运行,无法判断,则设置成一致,一个在运行一个不在运行,则不一致 * */ if(!m_isRunCalDB1Thread && !m_isRunCalDB2Thread) { oneRoad.isConsistency = true; SPDLOG_LOGGER_INFO(m_logger, "{}: 通道指针为空,默认为一致", m_chnName); return true; } // 一个为空,一个不空判定为不一致 if (m_isRunCalDB1Thread != m_isRunCalDB2Thread) { oneRoad.isConsistency = false; SPDLOG_LOGGER_INFO(m_logger, "{}: 一个通道正在运行计算音量的线程,一个通道未在运行,判定为不一致", m_chnName); return false; } /* 上一次的一致性标记 */ m_mutexVolumeInfo.lock(); const bool lastConsistency = m_roadResult.isConsistency; m_mutexVolumeInfo.unlock(); bool bConsistency = lastConsistency; if (!m_isRunCompareThread) { /* 没有开启比对线程 */ bConsistency = false; if(m_recordDev1ID == m_recordDev2ID) { // 同一个通道肯定是一致的 bConsistency = true; SPDLOG_LOGGER_INFO(m_logger, "同一个通道肯定是一致的"); } } else if(!m_isRunCalDB1Thread && !m_isRunCalDB2Thread) { // 都没有开启,表示两者是静音 bConsistency = true; SPDLOG_LOGGER_INFO(m_logger, "都没有开启,表示两者是静音"); } else if(m_isRunCalDB1Thread != m_isRunCalDB2Thread) { // 一个开启了,一个没有开启,表示不一致 bConsistency = false; SPDLOG_LOGGER_INFO(m_logger, "一个开启了,一个没有开启,表示不一致"); }else { /* 都开启了计算音量的线程 */ /* 获取上一次的低音量信息 */ int bBothMinDB = m_bBothMinDB; addBothMiniDB(bBothMinDB); /************************************************************* * 金海林加入 * 时间: 2023年8月30日 16:09:25 * 描述: 杭州台:在其它报警时,不一致不报警且后台不进行不一致比对,在其它报警恢复后,不一致重新计时比对 if (ESW_ALL_NOT != bBothMinDB) *************************************************************/ /* m_isAINotConsistencyAlone 是外部的配置选项 */ if (ESW_ALL_NOT != bBothMinDB && !m_isAINotConsistencyAlone) /**********金海林加入结束*************/ { if (ESW_BothMinDB_TRUE == bBothMinDB) { SPDLOG_LOGGER_INFO(m_logger, "{}: 平均音量比较小时,维持当前状态不变!", m_chnName); } else if (ESW_BothMute_TRUE == bBothMinDB) { /************************************************************* * 金海林加入 * 时间: 2022年4月6日 10:58:19 * 描述: 静音判断可能存在时间偏移,所有要多等待一次对比 *************************************************************/ if (isSameBothMinDB(ESW_BothMute_TRUE)) { SPDLOG_LOGGER_INFO(m_logger, "{}: 两个都是静音,判定为一致!", m_chnName); bConsistency = true; } else { SPDLOG_LOGGER_INFO(m_logger, "{}: 两个都是静音,前3次维持当前状态不变!", m_chnName); //bConsistency = FALSE; } /**********金海林加入结束*************/ } else { /* 一个静音,一个非静音 */ /************************************************************* * 金海林修改 * 时间: 2018年11月2日 14:31:34 * 描述: 一个静音一个非静音,第一次维持不一致状态不变;第二次直接判定位不一致 *************************************************************/ if (isSameBothMinDB(ESW_OneMinDB_FALSE)) { SPDLOG_LOGGER_INFO(m_logger, "{}: 一个静音一个非静音,上次也是这样,直接判定为不一致!", m_chnName); bConsistency = false; } else { SPDLOG_LOGGER_INFO(m_logger, "{}: 一个静音一个非静音,前3次维持当前状态不变!", m_chnName); //bConsistency = false; } /**********金海林修改结束*************/ } } else { /* 两个都是静音,进一步进行一致性比较 */ /************************************************************* * 金海林加入 * 时间: 2022年3月31日 16:04:30 * 描述: 开启基础(静音正弦波判断)和AI对比 *************************************************************/ compareConsistencyBaseOnAI(bConsistency, lastConsistency); /**********金海林加入结束*************/ std::string strMsgLog; if (bConsistency) { if (oneRoad.isNotConsistencyWarning == true) { strMsgLog = fmt::format("{}:预警【一致】:{}", m_logBase, m_chnName); } else { strMsgLog = fmt::format("{}:是一致:{}", m_logBase, m_chnName); } } else { strMsgLog = fmt::format("{}:不一致:{}", m_logBase, m_chnName); } SPDLOG_LOGGER_DEBUG(m_logger, strMsgLog); } } return true; } /* 基础静音判断和AI(这里是调用的动态库)判断进行对比 */ bool CompareDoubleThread::compareConsistencyBaseOnAI(bool& bConsistency, const bool lastConsistency) { /************************************************************* * 金海林加入 * 时间: 2023年8月30日 16:09:25 * 描述: 杭州台:在其它报警时,不一致不报警且后台不进行不一致比对,在其它报警恢复后,不一致重新计时比对 *************************************************************/ if (m_isHasAlarmExecpt) { bConsistency = true; return false; } /**********金海林加入结束*************/ /* 更新动态库的一致性比对结果 */ std::string strAIValue, strAIValueNot; bool bAICon = m_consistencyResult.IsAIConsistency(GInfo.AICMPThresholdNum(), GInfo.AICMPThreshold(), strAIValue); bool bAINot = m_consistencyResult.IsAINotConsistency(GInfo.AICMPThresholdNum(), GInfo.AICMPThresholdNot(), strAIValueNot); if (false == bAICon || false == bAINot) { bConsistency = true; return false; } if (bAICon) { bConsistency = true; if (!lastConsistency) { SPDLOG_LOGGER_INFO(m_logger, "当前AI判定为一致,上次是不一致,确认为一致(第{}次),{}", ++m_arryAIChangeRetNum[1], strAIValue); } return true; } if (bAINot) { bConsistency = false; if (lastConsistency) { SPDLOG_LOGGER_INFO(m_logger, "当前AI判定为不一致,上次是一致,确认为不一致(第{}次),{}", ++m_arryAIChangeRetNum[3], strAIValueNot); } return true; } bConsistency = lastConsistency; // 如果都不是一致和不一致,则使用上一次的一致性结果 return true; } /* 初始化低音量数组 */ void CompareDoubleThread::initMiniArray() { for(auto& data : m_arrayMiniDB) { data = -1; } } /* 向低音量数组添加数字 */ int CompareDoubleThread::addBothMiniDB(int db) { for(int i = 8; i >= 0; --i) { m_arrayMiniDB[i+1] = m_arrayMiniDB[i]; } m_arrayMiniDB[0] = db; if (ESW_ALL_NOT == db) { } if (ESW_BothMinDB_TRUE == db) { SPDLOG_LOGGER_DEBUG(m_logger, "{}: 两个都是声音小,连续{}秒平均音量小于[{}]", m_chnName, m_avgDBCalculateSeconds, m_silentThreshold); SPDLOG_LOGGER_DEBUG(m_logger, "{}: 记录当前状态:两个都是声音小,连续{}秒平均音量小于[{}]", m_chnName, m_avgDBCalculateSeconds, m_silentThreshold); } if (ESW_BothMute_TRUE == db) { SPDLOG_LOGGER_DEBUG(m_logger, "{}: 两个静音({})", m_chnName, db); } if (ESW_OneMinDB_FALSE == db) { SPDLOG_LOGGER_DEBUG(m_logger, "{}: 一个静音一个非静音({})", m_chnName, db); } return 10; } /** * @brief 两个低音量是否相似 * * @param db * @return true * @return false */ bool CompareDoubleThread::isSameBothMinDB(int db) { bool bSame = true; int nThresholdNum = m_nIsSameBothMinDBWaitNum; //是否静音要等待3秒,因为音频有延时 if (nThresholdNum < 0) nThresholdNum = 1; if (nThresholdNum > 10) nThresholdNum = 10; for(int i = 0; i < nThresholdNum; ++i) { if (db != m_arrayMiniDB[i]) { bSame = false; break; } } return bSame; } /* 保存报警信息 */ void CompareDoubleThread::saveAlarmInfo() { if(m_roadResult.isConsistency) { /* 这次是一致的,判断之前是否在一致性报警中 */ if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm) { /* 之前在一致性报警中,这次一致,结束不一致性报警 */ m_alarmConsistencyMain.isAlarm = false; m_alarmConsistencySub.isAlarm = false; /* 结束时间向前推1秒 */ m_alarmConsistencyMain.EndTime = m_localData1.ringQueue.back()->endTime.addSecs(1); m_alarmConsistencySub.EndTime = m_localData2.ringQueue.back()->endTime.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; /* 计算开始时间 */ int seconds = m_consistencyParam.GetConsistencyThresholdNotNum() * (m_nCompareTimeSpan / 1000); int pos1 = m_localData1.ringQueue.QueueSize() - seconds - 1; int pos2 = m_localData2.ringQueue.QueueSize() - seconds - 1; m_alarmConsistencyMain.StartTime = m_localData1.ringQueue[pos1]->startTime; m_alarmConsistencySub.StartTime = m_localData2.ringQueue[pos2]->startTime; SPDLOG_LOGGER_WARN(m_logger, "{}: 不一致报警开始", m_logBase); m_threadCreateAlarmFile1->startRecordAlarmFile(m_alarmConsistencyMain); m_threadCreateAlarmFile2->startRecordAlarmFile(m_alarmConsistencySub); } } }