ConsistencyCompareThread.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. #include "ConsistencyCompareThread.h"
  2. #include "GlobalVariable.h"
  3. #include "SystemConfig.h"
  4. #include "ThreadManager.h"
  5. #include "CreateRecordFileThread.h"
  6. #include "ThreadWriteDBManager.h"
  7. #include "CreateWAVThread.h"
  8. #include "LHCompareAPI.h"
  9. #include "SystemConfig.h"
  10. ConsistencyCompareThread::ConsistencyCompareThread(CalculateThreadInfo_t& threadInfo)
  11. : BaseCalculateThread(threadInfo)
  12. {
  13. }
  14. ConsistencyCompareThread::~ConsistencyCompareThread()
  15. {
  16. }
  17. /* 判断录音通道是否相等 */
  18. // bool ConsistencyCompareThread::isRoadEqual(const SoundCardRoadInfo_t& roadInfo1, const SoundCardRoadInfo_t& roadInfo2)
  19. // {
  20. // /* r1对比m_r1,r2对比M_r2 */
  21. // if( roadInfo1.nSoundCardNum == m_roadInfo1.nSoundCardNum && roadInfo1.roadInfo.nRoadNum == m_roadInfo1.roadInfo.nRoadNum &&
  22. // roadInfo2.nSoundCardNum == m_roadInfo2.nSoundCardNum && roadInfo2.roadInfo.nRoadNum == m_roadInfo2.roadInfo.nRoadNum )
  23. // {
  24. // return true;
  25. // }
  26. // /* 反过来对比一下 */
  27. // if( roadInfo1.nSoundCardNum == m_roadInfo2.nSoundCardNum && roadInfo1.roadInfo.nRoadNum == m_roadInfo2.roadInfo.nRoadNum &&
  28. // roadInfo2.nSoundCardNum == m_roadInfo1.nSoundCardNum && roadInfo2.roadInfo.nRoadNum == m_roadInfo1.roadInfo.nRoadNum )
  29. // {
  30. // return true;
  31. // }
  32. // return false;
  33. // }
  34. /* 初始化 */
  35. bool ConsistencyCompareThread::initConsistencyCompare()
  36. {
  37. /* 初始化数据 */
  38. if(!initData())
  39. {
  40. SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase);
  41. return false;
  42. }
  43. SPDLOG_LOGGER_INFO(m_logger, " ★ {} 一致性对比功能(调用动态库)初始化完成 ", m_logBase);
  44. return true;
  45. }
  46. /* 比对函数 */
  47. bool ConsistencyCompareThread::compareConsistencyData()
  48. {
  49. /*--------------------------------------------------------------
  50. * 更新最新数据
  51. *--------------------------------------------------------------*/
  52. m_pCreateWAVThread1->getLatestFileName(m_wavFilePath1);
  53. m_pCreateWAVThread2->getLatestFileName(m_wavFilePath2);
  54. /* 检查是否有新的数据 */
  55. if(m_wavFilePath1 == m_prevWavFilePath1 || m_wavFilePath2 == m_prevWavFilePath2)
  56. {
  57. // SPDLOG_LOGGER_INFO(m_logger, "{} 检测到文件路径未变化", m_logBase);
  58. return false;
  59. }
  60. /*--------------------------------------------------------------
  61. * 开始比对计算,并保存计算结果
  62. *--------------------------------------------------------------*/
  63. if(!compareConsistency())
  64. {
  65. return false;
  66. }
  67. /* 计算一致性结果 */
  68. computeResult();
  69. m_prevWavFilePath1 = m_wavFilePath1; // 更新上一个wav文件路径
  70. m_prevWavFilePath2 = m_wavFilePath2; // 更新上一个wav文件路径
  71. return true;
  72. }
  73. /* 清理数据 */
  74. void ConsistencyCompareThread::clearConsistencyCompareData()
  75. {
  76. clearData();
  77. SPDLOG_LOGGER_INFO(m_logger, " ★ {} 一致性对比功能(调用动态库)清理完成 ", m_logBase);
  78. }
  79. /* 线程功能函数 */
  80. void ConsistencyCompareThread::task()
  81. {
  82. m_isRunning = true;
  83. /* 初始化 */
  84. if(!initData())
  85. {
  86. SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase);
  87. return;
  88. }
  89. SPDLOG_LOGGER_INFO(m_logger, " ★ {} 一致性对比线程(调用动态库)开始运行 ", m_logBase);
  90. // std::chrono::system_clock::time_point startTime = std::chrono::system_clock::now();
  91. #if(CONSISTENCY_DEBUG)
  92. int nCompareCount = 0; // 计算次数
  93. bool isConsistency = true;
  94. #endif
  95. while(true)
  96. {
  97. /* 判断是否需要退出线程 */
  98. if(m_isRunning == false)
  99. {
  100. /* 如果此时还在非一致性报警中,结束报警 */
  101. if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm)
  102. {
  103. endAlarm();
  104. }
  105. /* 退出线程 */
  106. break;
  107. }
  108. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  109. /* 判断是否开启不一致检测 */
  110. if(m_isEnableNotConsistencyDetect.load() == false)
  111. {
  112. /* 不开启不一致检测,直接返回一致性结果 */
  113. m_isConsistency = true;
  114. m_isConsistencyWarning = false;
  115. continue; // 跳过后续的计算
  116. }
  117. /* 判断是否在检测时间段内 */
  118. if(m_isInDetectPeriod.load() == false)
  119. {
  120. /* 不在检测时间段内,不需要比对,结果一直为一致性 */
  121. m_isConsistency = true;
  122. m_isConsistencyWarning = false;
  123. /* 如果此时还在非一致性报警中,结束报警 */
  124. if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm)
  125. {
  126. endAlarm();
  127. }
  128. continue;
  129. }
  130. /* 计算一致性 */
  131. if(!compareConsistencyData())
  132. {
  133. /* 没有新数据或者计算失败,继续等待 */
  134. continue;
  135. }
  136. #if(CONSISTENCY_DEBUG)
  137. /* 模拟不一致报警,启动检测五次开始报警,报警5次取消报警,间隔5次继续报警 */
  138. if(isConsistency)
  139. {
  140. if(nCompareCount > 3)
  141. {
  142. isConsistency = false;
  143. m_isConsistency = false;
  144. m_isConsistencyWarning = true;
  145. nCompareCount = 0;
  146. }
  147. }else {
  148. if(nCompareCount > 3)
  149. {
  150. isConsistency = true;
  151. m_isConsistency = true;
  152. m_isConsistencyWarning = false;
  153. nCompareCount = 0;
  154. }
  155. }
  156. nCompareCount++;
  157. #endif
  158. /* 保存结果 */
  159. saveAlarmInfo();
  160. }
  161. clearData();
  162. SPDLOG_LOGGER_WARN(m_logger, " ★ {} 一致性对比线程(调用动态库)已结束运行 ", m_logBase);
  163. }
  164. /* 初始化数据 */
  165. bool ConsistencyCompareThread::initData()
  166. {
  167. if(m_threadInfo.compareItemInfo.mapRoad.size() < 2)
  168. {
  169. SPDLOG_LOGGER_ERROR(m_logger, "{} 录音通道信息不足,至少需要两个通道", m_logBase);
  170. return false;
  171. }
  172. /* 获取一致性检测的参数 */
  173. const auto& compareConfig = SysConfig.getAICompareConfig();
  174. m_numCompareContinue = compareConfig.nAiCompareCount;
  175. m_numFileDuration = compareConfig.nAiComputeDuration;
  176. m_fNotConsistencyThreshold = compareConfig.fNotSimilarThrehold;
  177. m_fConsistencyThreshold = compareConfig.fSimilarThrehold;
  178. /* 获取两个录音通道的信息 */
  179. auto it = m_threadInfo.compareItemInfo.mapRoad.begin();
  180. m_itemRoadInfo1 = it.value(); // 第一个通道
  181. it++;
  182. m_itemRoadInfo2 = it.value(); // 第二个通道
  183. m_logBase = fmt::format("对比通道 {}:{} - {}:{}",
  184. m_itemRoadInfo1.scRoadInfo.strSoundCardName, m_itemRoadInfo1.scRoadInfo.pcmInfo.strPCMName,
  185. m_itemRoadInfo2.scRoadInfo.strSoundCardName, m_itemRoadInfo2.scRoadInfo.pcmInfo.strPCMName);
  186. /* 获取创建wav文件的指针 */
  187. auto startTime = std::chrono::steady_clock::now(); // 记录开始时间
  188. while(true)
  189. {
  190. if(m_pCreateWAVThread1 == nullptr)
  191. {
  192. m_pCreateWAVThread1 = ThreadMan.getCreateWAVThread(m_itemRoadInfo1.scRoadInfo.pcmInfo.strPCMName);
  193. }
  194. if(m_pCreateWAVThread2 == nullptr)
  195. {
  196. m_pCreateWAVThread2 = ThreadMan.getCreateWAVThread(m_itemRoadInfo2.scRoadInfo.pcmInfo.strPCMName);
  197. }
  198. /* 获取生成报警音频文件的线程 */
  199. if(m_threadCreateAlarmFile1 == nullptr)
  200. {
  201. m_threadCreateAlarmFile1 = ThreadMan.getCreateRecordFileThread(m_itemRoadInfo1.scRoadInfo.pcmInfo.strPCMName);
  202. }
  203. if(m_threadCreateAlarmFile2 == nullptr)
  204. {
  205. m_threadCreateAlarmFile2 = ThreadMan.getCreateRecordFileThread(m_itemRoadInfo2.scRoadInfo.pcmInfo.strPCMName);
  206. }
  207. if( m_pCreateWAVThread1 != nullptr && m_pCreateWAVThread2 != nullptr &&
  208. m_threadCreateAlarmFile1 != nullptr && m_threadCreateAlarmFile2 != nullptr )
  209. {
  210. break; // 获取到两个线程,跳出循环
  211. }
  212. /* 超过10秒还没有获取到线程,返回失败 */
  213. if(std::chrono::steady_clock::now() - startTime > std::chrono::seconds(10))
  214. {
  215. SPDLOG_LOGGER_ERROR(m_logger, "{} 获取生成音量的线程超时", m_logBase);
  216. return false;
  217. }
  218. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  219. }
  220. if(m_pCreateWAVThread1 == nullptr || m_pCreateWAVThread2 == nullptr)
  221. {
  222. SPDLOG_LOGGER_ERROR(m_logger, "{} 获取录音线程失败", m_logBase);
  223. return false;
  224. }
  225. if(m_threadCreateAlarmFile1 == nullptr || m_threadCreateAlarmFile2 == nullptr)
  226. {
  227. SPDLOG_LOGGER_ERROR(m_logger, "{} 获取生成报警音频文件的线程失败", m_logBase);
  228. return false;
  229. }
  230. return true;
  231. }
  232. /* 清理数据 */
  233. void ConsistencyCompareThread::clearData()
  234. {
  235. m_isRunning = false;
  236. m_pCreateWAVThread1 = nullptr;
  237. m_pCreateWAVThread2 = nullptr;
  238. }
  239. /* 比对两个wav文件的一致性 */
  240. bool ConsistencyCompareThread::compareConsistency()
  241. {
  242. /* 计算比对需要的时间 */
  243. std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
  244. CompareResult* result = LHCompare(m_wavFilePath1.fileName.c_str(), m_wavFilePath2.fileName.c_str(), m_sensitivity);
  245. if(result == nullptr)
  246. {
  247. SPDLOG_LOGGER_ERROR(m_logger, "{} 一致性比对失败,可能是文件格式不支持或动态库加载失败", m_logBase);
  248. return false;
  249. }
  250. /* 如果高相似度小于1,将两个通道反过来对比一下 */
  251. if(result->highest_similarity < 1)
  252. {
  253. delete result;
  254. result = nullptr;
  255. SPDLOG_LOGGER_WARN(m_logger, "{} 高相似度小于1,尝试反向对比", m_logBase);
  256. result = LHCompare(m_wavFilePath2.fileName.c_str(), m_wavFilePath1.fileName.c_str(), m_sensitivity);
  257. if(result == nullptr)
  258. {
  259. SPDLOG_LOGGER_ERROR(m_logger, "{} 一致性比对失败,可能是文件格式不支持或动态库加载失败", m_logBase);
  260. return false;
  261. }
  262. }
  263. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 一致性比对结果: 源文件: {}, 目标文件: {}, 最高相似度: {:.3f}, 平均相似度: {:.3f}",
  264. // m_logBase, m_wavFilePath1.fileName, m_wavFilePath2.fileName, result->highest_similarity, result->average_similarity);
  265. /* 保存结果 */
  266. double highestSimilarity = result->highest_similarity / 100.0; // 将相似度转换为0-1范围
  267. double averageSimilarity = result->average_similarity / 100.0; // 将相似度转换为0-1范围
  268. m_consistencyResult.AddResult(highestSimilarity);
  269. m_similarity = highestSimilarity;
  270. delete result;
  271. result = nullptr;
  272. /* 计算比对耗时 */
  273. std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
  274. auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
  275. SPDLOG_LOGGER_DEBUG(m_logger, "{} 一致性比对结果: 最高相似度: {:.3f}, 平均相似度: {:.3f}, 耗时: {}ms",
  276. m_logBase, highestSimilarity, averageSimilarity, duration.count());
  277. return true;
  278. }
  279. /* 根据动态库返回的结果计算一致性 */
  280. bool ConsistencyCompareThread::computeResult()
  281. {
  282. std::string strConInfo, strNotConInfo;
  283. auto consistencyState = m_consistencyResult.computeConsistency(m_numCompareContinue, m_fConsistencyThreshold, strConInfo);
  284. auto notConsisencyState = m_consistencyResult.computeNotConsistency(m_numCompareContinue, m_fNotConsistencyThreshold, strNotConInfo);
  285. SPDLOG_LOGGER_DEBUG(m_logger, "{} 此次一致性计算结果: {}, 不一致性计算结果: {}, 一致性说明: {}, 不一致说明: {}",
  286. m_logBase, static_cast<int>(consistencyState), static_cast<int>(notConsisencyState), strConInfo, strNotConInfo);
  287. if (eConsistencyState::eCS_Consistency == consistencyState)
  288. {
  289. /* 计算出的一致性是确定的 */
  290. m_isConsistency.store(true);
  291. m_isConsistencyWarning.store(false);
  292. }
  293. else if(eConsistencyState::eCS_NotConsistency == notConsisencyState)
  294. {
  295. /* 计算出的不一致性是确定的 */
  296. m_isConsistency.store(false);
  297. m_isConsistencyWarning.store(true);
  298. }else
  299. {
  300. /* 都不是确定的一致性和不一致性,使用上次的结果 */
  301. m_isConsistency.store(m_isConsistencyLatest.load());
  302. m_isConsistencyWarning.store(true);
  303. }
  304. return true;
  305. }
  306. /* 保存报警信息 */
  307. void ConsistencyCompareThread::saveAlarmInfo()
  308. {
  309. if(m_isConsistency)
  310. {
  311. /* 这次是一致的,判断之前是否在一致性报警中 */
  312. if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm)
  313. {
  314. /* 之前在一致性报警中,这次一致,结束不一致性报警 */
  315. m_alarmConsistencyMain.isAlarm = false;
  316. m_alarmConsistencySub.isAlarm = false;
  317. /* 结束时间向后推1秒 */
  318. m_alarmConsistencyMain.EndTime = m_wavFilePath1.endDateTime.addSecs(1);
  319. m_alarmConsistencySub.EndTime = m_wavFilePath2.endDateTime.addSecs(1);
  320. /* 结束录制报警音频 */
  321. m_threadCreateAlarmFile1->stopRecordAlarmFile(m_alarmConsistencyMain);
  322. m_threadCreateAlarmFile2->stopRecordAlarmFile(m_alarmConsistencySub);
  323. /* 设置录音状态 */
  324. m_alarmConsistencyMain.fileState = eRecordState::eRS_RecordCompleted;
  325. m_alarmConsistencySub.fileState = eRecordState::eRS_RecordCompleted;
  326. /* 将报警信息写入数据库 */
  327. WriteDB.addAlarmInfo(m_alarmConsistencyMain, m_alarmConsistencySub);
  328. SPDLOG_LOGGER_INFO(m_logger, "{}: 一致性报警结束,结束时间: {}", m_logBase,
  329. m_wavFilePath1.endDateTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
  330. /* 清除报警信息 */
  331. m_alarmConsistencyMain = AlarmInfo_t();
  332. m_alarmConsistencySub = AlarmInfo_t();
  333. }
  334. }else
  335. {
  336. /* 不一致,判断之前的一致性,判断一个就可以了 */
  337. if(!m_alarmConsistencySub.isAlarm)
  338. {
  339. /* 开是不一致报警 */
  340. m_alarmConsistencyMain.isAlarm = true;
  341. m_alarmConsistencySub.isAlarm = true;
  342. m_alarmConsistencyMain.CompareItemID = m_threadInfo.compareItemInfo.nID;
  343. m_alarmConsistencySub.CompareItemID = m_threadInfo.compareItemInfo.nID;
  344. m_alarmConsistencyMain.strCompareItemName = m_threadInfo.compareItemInfo.strName;
  345. m_alarmConsistencySub.strCompareItemName = m_threadInfo.compareItemInfo.strName;
  346. m_alarmConsistencyMain.RoadInfo = m_itemRoadInfo1;
  347. m_alarmConsistencySub.RoadInfo = m_itemRoadInfo2;
  348. m_alarmConsistencyMain.RoadType = ERoadType::RoadType_Main;
  349. m_alarmConsistencySub.RoadType = ERoadType::RoadType_SpaceReceive;
  350. m_alarmConsistencyMain.AlarmType = EAlarmType::EAR_Consistency;
  351. m_alarmConsistencySub.AlarmType = EAlarmType::EAR_Consistency;
  352. /* 计算开始时间,开始时间计算方法:
  353. 单次计算的时间长度是 numFileDuration, 计算 m_numCompareContinue 次才会不一致性报警,因此向前推
  354. m_numFileDuration * m_numCompareContinue 秒
  355. */
  356. int seconds = m_numFileDuration * m_numCompareContinue;
  357. /* 因为 m_numCompareContinue 次计算也包括这次的文件,所以从结束时间开始向前推 */
  358. m_alarmConsistencyMain.StartTime = m_wavFilePath1.endDateTime.addSecs(-seconds);
  359. m_alarmConsistencySub.StartTime = m_wavFilePath2.endDateTime.addSecs(-seconds);
  360. SPDLOG_LOGGER_WARN(m_logger, "{}: 不一致报警开始", m_logBase);
  361. m_threadCreateAlarmFile1->startRecordAlarmFile(m_alarmConsistencyMain);
  362. m_threadCreateAlarmFile2->startRecordAlarmFile(m_alarmConsistencySub);
  363. }
  364. }
  365. }
  366. /* 结束报警 */
  367. void ConsistencyCompareThread::endAlarm()
  368. {
  369. m_isConsistency = true;
  370. /* 这次是一致的,判断之前是否在一致性报警中 */
  371. if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm)
  372. {
  373. /* 之前在一致性报警中,这次一致,结束不一致性报警 */
  374. m_alarmConsistencyMain.isAlarm = false;
  375. m_alarmConsistencySub.isAlarm = false;
  376. /* 结束时间向后推1秒 */
  377. m_alarmConsistencyMain.EndTime = m_wavFilePath1.endDateTime.addSecs(1);
  378. m_alarmConsistencySub.EndTime = m_wavFilePath2.endDateTime.addSecs(1);
  379. /* 结束录制报警音频 */
  380. m_threadCreateAlarmFile1->stopRecordAlarmFile(m_alarmConsistencyMain);
  381. m_threadCreateAlarmFile2->stopRecordAlarmFile(m_alarmConsistencySub);
  382. /* 设置录音状态 */
  383. m_alarmConsistencyMain.fileState = eRecordState::eRS_RecordCompleted;
  384. m_alarmConsistencySub.fileState = eRecordState::eRS_RecordCompleted;
  385. /* 将报警信息写入数据库 */
  386. WriteDB.addAlarmInfo(m_alarmConsistencyMain, m_alarmConsistencySub);
  387. SPDLOG_LOGGER_INFO(m_logger, "{}: 一致性报警结束,结束时间: {}", m_logBase,
  388. m_wavFilePath1.endDateTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
  389. /* 清除报警信息 */
  390. m_alarmConsistencyMain = AlarmInfo_t();
  391. m_alarmConsistencySub = AlarmInfo_t();
  392. }
  393. }