CreateLongFileThread.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. #include "CreateLongFileThread.h"
  2. #include "AudioData.h"
  3. #include "GlobalInfo.h"
  4. #include "spdlog.h"
  5. #include <cstring>
  6. #include <qt5/QtCore/qchar.h>
  7. CreateLongFileThread::CreateLongFileThread(RecordThreadInfo_t& threadInfo)
  8. : BaseRecordThread(threadInfo)
  9. {
  10. m_logger = spdlog::get("RecordAudio");
  11. if(m_logger == nullptr)
  12. {
  13. fmt::print("RecordThread: RecordAudio Logger not found.\n");
  14. return;
  15. }
  16. /* 初始化数据 */
  17. initData();
  18. }
  19. CreateLongFileThread::~CreateLongFileThread()
  20. {
  21. }
  22. /* 设置数据 */
  23. bool CreateLongFileThread::setData(const AudioSrcData& srcData)
  24. {
  25. if(srcData.pData == nullptr || srcData.dataSize == 0)
  26. {
  27. SPDLOG_LOGGER_ERROR(m_logger, "{} 设置数据失败,srcData为空或dataSize为0", m_logBase);
  28. return false;
  29. }
  30. /* ------------------------------------------------------------------------------- */
  31. /* 先写入记录报警文件的环形缓冲区 */
  32. auto oldData = m_ringQueue.push_pop(new AudioSrcData(srcData));
  33. if(oldData != nullptr)
  34. {
  35. delete oldData;
  36. oldData = nullptr;
  37. }
  38. /* ------------------------------------------------------------------------------- */
  39. /* 锁定缓冲区 */
  40. std::lock_guard<std::mutex> lock(m_mutexBuffer);
  41. /* 如果缓冲区没有分配内存,先分配 */
  42. if(m_bufferData.pData == nullptr)
  43. {
  44. if(!m_bufferData.allocateMemory(m_writeCriticalSize * 3))
  45. {
  46. SPDLOG_LOGGER_ERROR(m_logger, "{} 分配缓冲区内存失败", m_logBase);
  47. return false;
  48. }
  49. }
  50. /* 添加数据到缓冲区 */
  51. int32_t writtenSize = m_bufferData.appendData(srcData.pData, srcData.dataSize);
  52. if(writtenSize == 0)
  53. {
  54. SPDLOG_LOGGER_ERROR(m_logger, "{} 添加数据到缓冲区失败", m_logBase);
  55. return false;
  56. }
  57. /* 记录日期 */
  58. if(m_bufferData.startTime.isNull() || m_bufferData.startTime.isValid())
  59. {
  60. m_bufferData.startTime = srcData.startTime;
  61. }
  62. m_bufferData.endTime = srcData.endTime;
  63. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 设置数据,dataSize: {}, startTime: {}, endTime: {}",
  64. // m_logBase, m_bufferData.dataSize, m_bufferData.startTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), m_bufferData.endTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
  65. return true;
  66. }
  67. /* 开启录制 */
  68. bool CreateLongFileThread::startRecordAlarmFile(const AlarmInfo_t& alarmInfo)
  69. {
  70. std::lock_guard<std::mutex> lock(m_mutexBuffer);
  71. /* 先检查是否已经在队列中了 */
  72. AlarmKey_t key = {alarmInfo.CompareItemID, alarmInfo.RoadInfo.nCompareRoadNum,
  73. alarmInfo.AlarmType, alarmInfo.StartTime};
  74. if(m_mapAlarmFile.find(key) != m_mapAlarmFile.end())
  75. {
  76. SPDLOG_LOGGER_WARN(m_logger, "{} 已经在报警录制队列中,无法重复添加", m_logBase);
  77. return true;
  78. }
  79. /* 添加一个新的报警文件路径 */
  80. QString fileName = generateFileName(alarmInfo.StartTime, alarmInfo.EndTime);
  81. return true;
  82. }
  83. /* 停止录制,alarmInfo既是传入参数,也是传出参数,传出文件路径和开始位置 */
  84. bool CreateLongFileThread::stopRecordAlarmFile(AlarmInfo_t& alarmInfo)
  85. {
  86. return true;
  87. }
  88. /**
  89. * @brief 生成长文件的线程函数,文件生成逻辑如下
  90. * 1、这里有一个缓冲区,存储音频数据,缓冲区大小是2分钟的数据
  91. * 2、每分钟写入一次文件,文件名格式为:ChannelX_yyyyMMdd_hhmmss-yyyyMMdd_hhmmss.wav
  92. * 3、文件总长度是1小时的数据,超过1小时则重新开始记录一个新的文件
  93. *
  94. */
  95. void CreateLongFileThread::task()
  96. {
  97. SPDLOG_LOGGER_INFO(m_logger, "➢ {} 开启记录文件线程 ", m_logBase);
  98. /* 计算一小时的文件大小 */
  99. while(m_isRunning)
  100. {
  101. /* 线程休眠100ms */
  102. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  103. /*--------------------------------------------------------------
  104. * 写入报警文件
  105. *--------------------------------------------------------------*/
  106. /*--------------------------------------------------------------
  107. * 写入长记录文件
  108. *--------------------------------------------------------------*/
  109. writeLongRecordFile();
  110. }
  111. SPDLOG_LOGGER_WARN(m_logger, "➢ {} 记录长文件线程结束运行", m_logBase);
  112. }
  113. /* 初始化一些数据 */
  114. bool CreateLongFileThread::initData()
  115. {
  116. m_logBase = fmt::format("录音通道 {}:{} - 记录长文件线程",
  117. m_threadInfo.cardRoadInfo.strSoundCardName.toStdString(),
  118. m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
  119. /* 获取全局数据 */
  120. m_sampleRate = GInfo.sampleRate(); /* 采样率 */
  121. m_numChannels = GInfo.numChannels(); /* 声道数 */
  122. m_bitsPerSample = GInfo.bitsPerSample(); /* 每个采样点的位数 */
  123. /* 一秒的数据大小 */
  124. m_oneSecondSize = m_sampleRate * m_numChannels * (m_bitsPerSample / 8);
  125. /* 一分钟数据大小 */
  126. m_writeCriticalSize = m_oneSecondSize * 60;
  127. /* 一小时数据大小 */
  128. m_oneHourSize = m_writeCriticalSize * 60;
  129. /* 给缓存分配空间 */
  130. m_bufferData.allocateMemory(m_writeCriticalSize * 3);
  131. m_srcData.allocateMemory(m_writeCriticalSize * 3);
  132. /* 设置环形队列大小 */
  133. m_ringQueue.setQueueCapacity(GInfo.queueElementCount());
  134. return true;
  135. }
  136. /* 清理数据 */
  137. void CreateLongFileThread::clearData()
  138. {
  139. /* 清理缓存数据 */
  140. m_bufferData.clear();
  141. }
  142. /* 写入长记录文件 */
  143. bool CreateLongFileThread::writeLongRecordFile()
  144. {
  145. /* 判断缓存是否达到1分钟数据临界值 */
  146. {
  147. std::lock_guard<std::mutex> lock(m_mutexBuffer);
  148. if(m_bufferData.dataSize < m_writeCriticalSize)
  149. {
  150. return true; // 缓存数据不足,继续等待
  151. }
  152. /* 数据足够了将缓冲区数据拷贝出来 */
  153. memcpy(m_srcData.pData, m_bufferData.pData, m_bufferData.dataSize);
  154. m_srcData.dataSize = m_bufferData.dataSize;
  155. m_srcData.startTime = m_bufferData.startTime;
  156. m_srcData.endTime = m_bufferData.endTime;
  157. /* 清空缓冲区数据 */
  158. m_bufferData.clear();
  159. }
  160. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 设置数据,dataSize: {}, startTime: {}, endTime: {}",
  161. // m_logBase, m_srcData.dataSize, m_srcData.startTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), m_srcData.endTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
  162. /*--------------------------------------------------------------
  163. * 打开文件。写入的时候判断是否到达了整点,如果到达了整点,则关闭文件
  164. * 重新创建一个新的文件
  165. *--------------------------------------------------------------*/
  166. bool isNewFile = false;
  167. if(m_writtenSize == 0)
  168. {
  169. /* 如果没有写入过数据,则是新文件 */
  170. isNewFile = true;
  171. m_writtenStartTime = m_srcData.startTime; // 记录开始时间
  172. m_writtenNowTime = m_writtenStartTime; // 记录当前时间
  173. }
  174. /* 设置今日目录 */
  175. if(!setTodayPath(isNewFile))
  176. {
  177. return false;
  178. }
  179. /* 打开文件 */
  180. QFile wavFile;
  181. if(!openFile(wavFile, isNewFile))
  182. {
  183. if(m_openFileErrorSize >= 3)
  184. {
  185. SPDLOG_LOGGER_ERROR(m_logger, "{} 打开文件失败次数过多,重新开始记录", m_logBase);
  186. m_writtenSize = 0;
  187. m_writtenStartTime = QDateTime::currentDateTime(); // 重新开始时间
  188. m_writtenNowTime = m_writtenStartTime; // 重新开始时间
  189. m_wavFileName.clear(); // 清空文件名
  190. m_srcData.clear(); // 清空缓冲区数据
  191. m_openFileErrorSize = 0; // 重置错误次数
  192. return false; // 重新开始记录
  193. }
  194. }
  195. /*--------------------------------------------------------------
  196. * 将数据写入文件,并记录其携带的时间和写入的数据大小
  197. *--------------------------------------------------------------*/
  198. int64_t wSize = 0;
  199. {
  200. std::lock_guard<std::mutex> lock(m_mutexBuffer);
  201. wSize = wavFile.write(m_srcData.pData, m_srcData.dataSize);
  202. /* 更新结束时间 */
  203. m_writtenNowTime = m_srcData.endTime;
  204. /* 清空缓冲区 */
  205. m_srcData.clear();
  206. }
  207. if(wSize < 0)
  208. {
  209. SPDLOG_LOGGER_ERROR(m_logger, "{} 写入WAV文件失败: {}", m_logBase, wavFile.errorString().toStdString());
  210. SPDLOG_LOGGER_WARN(m_logger, "文件路径:{}", m_wavFileName.toStdString());
  211. wavFile.close();
  212. return false;
  213. } else {
  214. SPDLOG_LOGGER_TRACE(m_logger, "{} 写入WAV文件成功: {}, 大小: {} 字节", m_logBase, m_wavFileName.toStdString(), wSize);
  215. }
  216. wavFile.close();
  217. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 写入WAV文件完成: {}, 大小: {} 字节",
  218. // m_logBase, m_wavFileName.toStdString(), wSize);
  219. /*--------------------------------------------------------------
  220. * 对该文件进行其他操作,判断是否已经过了一个整点,修改其文件名称
  221. * 现在这里的时间是这一分钟的开始时间,现在需要根据开始时间求出已写入
  222. * 数据大小对应的结束时间
  223. *--------------------------------------------------------------*/
  224. m_writtenSize += wSize;
  225. /* 修改文件名称 */
  226. QString newFileName = generateFileName(m_writtenStartTime, m_writtenNowTime);
  227. if(modifyFileName(m_wavFileName, newFileName))
  228. {
  229. m_wavFileName = newFileName;
  230. }
  231. /* 判断是否过了整点 */
  232. if(isOneHourPassed())
  233. {
  234. /* 修改文件头中记录的数据大小 */
  235. m_wavHeader.setDataSize(m_writtenSize);
  236. m_wavHeader.calculateDerivedFields();
  237. modifyWavFileHeader(m_wavFileName, m_wavHeader);
  238. SPDLOG_LOGGER_INFO(m_logger, "{} 结束记录一个文件: {}, 已写入大小: {} 字节",
  239. m_logBase, m_wavFileName.toStdString(), m_writtenSize);
  240. /* 重置已写入大小 */
  241. m_writtenSize = 0;
  242. m_writtenStartTime = QDateTime(); // 重新开始时间
  243. m_writtenNowTime = m_writtenStartTime; // 重新开始时间
  244. m_wavFileName.clear(); // 清空文件名
  245. m_openFileErrorSize = 0; // 重置错误次数
  246. }
  247. return true;
  248. }
  249. /* 设置今日目录 */
  250. bool CreateLongFileThread::setTodayPath(bool isNewFile)
  251. {
  252. if(!isNewFile)
  253. {
  254. return true;
  255. }
  256. /* 判断现在日期是否还是当天日期 */
  257. QDate today = QDate::currentDate();
  258. if(m_todayDateRecord == today)
  259. {
  260. return true;
  261. }
  262. m_todayDateRecord = today;
  263. /* 先检查现在的日期文件夹是否存在,因为其他线程可能已经创建了 */
  264. QString todayDirName = QString("%1/%2").arg(GInfo.longWavPath()).arg(today.toString("yyyy-MM-dd"));
  265. m_todayDir.setPath(todayDirName);
  266. if(!m_todayDir.exists())
  267. {
  268. if(!m_todayDir.mkpath(todayDirName))
  269. {
  270. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建今日目录失败: {}", m_logBase, todayDirName.toStdString());
  271. return false; // 创建目录失败
  272. } else {
  273. SPDLOG_LOGGER_INFO(m_logger, "{} 创建今日目录成功: {}", m_logBase, todayDirName.toStdString());
  274. }
  275. }
  276. /* 创建这个通道的文件夹,文件夹格式: AudioPCI-0 */
  277. QString roadDirName = QString("%1/%2-%3")
  278. .arg(todayDirName)
  279. .arg(m_threadInfo.cardRoadInfo.strSoundCardID)
  280. .arg(QString::number(m_threadInfo.cardRoadInfo.roadInfo.nRoadNum));
  281. m_todayDir.setPath(roadDirName);
  282. if(!m_todayDir.exists())
  283. {
  284. if(!m_todayDir.mkpath(todayDirName))
  285. {
  286. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建目录失败: {}", m_logBase, roadDirName.toStdString());
  287. return false;
  288. } else {
  289. SPDLOG_LOGGER_INFO(m_logger, "{} 创建目录成功: {}", m_logBase, roadDirName.toStdString());
  290. }
  291. }
  292. return true;
  293. }
  294. /* 打开文件 */
  295. bool CreateLongFileThread::openFile(QFile& wavFile, bool isNewFile)
  296. {
  297. if(isNewFile)
  298. {
  299. /* 如果没有写入过数据,则生成一个新的文件名 */
  300. m_wavFileName = generateFileName(m_writtenStartTime, m_writtenNowTime);
  301. m_wavHeader.setSampleRate(m_sampleRate);
  302. m_wavHeader.setNumChannels(m_numChannels);
  303. m_wavHeader.setBitsPerSample(m_bitsPerSample);
  304. m_wavHeader.setDataSize(m_writtenSize);
  305. m_wavHeader.calculateDerivedFields();
  306. wavFile.setFileName(m_wavFileName);
  307. if(!wavFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
  308. {
  309. m_openFileErrorSize ++;
  310. SPDLOG_LOGGER_ERROR(m_logger, "{} 打开WAV文件失败: {}", m_logBase, m_wavFileName.toStdString());
  311. SPDLOG_LOGGER_ERROR(m_logger, "错误原因: {}", wavFile.errorString().toStdString());
  312. return false;
  313. }
  314. wavFile.write(reinterpret_cast<const char*>(&m_wavHeader), sizeof(WavHeader));
  315. } else
  316. {
  317. /* 不是新文件 */
  318. wavFile.setFileName(m_wavFileName);
  319. if(!wavFile.open(QIODevice::WriteOnly | QIODevice::Append))
  320. {
  321. m_openFileErrorSize ++;
  322. SPDLOG_LOGGER_ERROR(m_logger, "{} 打开WAV文件失败: {}", m_logBase, m_wavFileName.toStdString());
  323. SPDLOG_LOGGER_ERROR(m_logger, "错误原因: {}", wavFile.errorString().toStdString());
  324. return false;
  325. }
  326. }
  327. m_openFileErrorSize = 0;
  328. return true;
  329. }
  330. /* 写入音频数据到文件 */
  331. bool CreateLongFileThread::writeAudioDataToFile(const AudioSrcData& audioData, const QString& fileName)
  332. {
  333. return true;
  334. }
  335. /* 生成文件名 */
  336. QString CreateLongFileThread::generateFileName(const QDateTime& startTime, const QDateTime& endTime) const
  337. {
  338. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 生成文件名: 开始时间: {}, 结束时间: {}",
  339. // m_logBase, startTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(),
  340. // endTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
  341. QString chnannelStr = QString("%1-%2").arg(m_threadInfo.cardRoadInfo.strSoundCardID)
  342. .arg(QString::number(m_threadInfo.cardRoadInfo.roadInfo.nRoadNum));
  343. QString fileName = QString("%1_%2-%3.wav")
  344. .arg(chnannelStr)
  345. .arg(startTime.toString("yyyyMMdd_hhmmss"))
  346. .arg(endTime.toString("yyyyMMdd_hhmmss"));
  347. /* 通过目录获取文件的全路径,dir不会检查文件是否存在 */
  348. return m_todayDir.filePath(fileName);
  349. }
  350. /* 判断是否过了整点 */
  351. bool CreateLongFileThread::isOneHourPassed()
  352. {
  353. if(m_writtenSize >= m_oneHourSize)
  354. {
  355. return true; // 已经写入的数据大小超过了一小时的大小
  356. }
  357. /* 下面是判断刚启动的时候,到下一个整点不足1小时,也会保存文件 */
  358. int minute = m_writtenNowTime.time().minute();
  359. bool isPassed = false;
  360. /* 如果当前时间的分钟数小于等于2,并且已经写入的大小超过2分钟的大小 */
  361. if(minute <= 2 && m_writtenSize >= m_writeCriticalSize * 2)
  362. {
  363. isPassed = true;
  364. }
  365. /* 或者已经写入的数据大小超过了一小时的大小,则认为过了整点 */
  366. if(m_writtenSize >= m_oneHourSize)
  367. {
  368. isPassed = true;
  369. }
  370. return isPassed;
  371. }
  372. /* 生成报警文件名 */
  373. QString CreateLongFileThread::generateAlarmFileName(const AlarmInfo_t& alarmInfo, bool isNewFile)
  374. {
  375. QString retFileName;
  376. if(isNewFile)
  377. {
  378. /* 先检查是否已经过了一天了,设置日期文件夹 */
  379. setTodayAlarmPath();
  380. /* 检查这个对比项的报警文件夹是否存在 */
  381. QString itemDirName = QString("CompareItemID_%1").arg(QString::number(alarmInfo.CompareItemID));
  382. QDir itemDir = m_todayDirAlarm;
  383. itemDir.cd(itemDirName);
  384. if(!itemDir.exists())
  385. {
  386. if(!itemDir.mkpath(itemDirName))
  387. {
  388. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建报警文件夹失败: {}", m_logBase, itemDirName.toStdString());
  389. return QString(); // 创建目录失败
  390. } else {
  391. SPDLOG_LOGGER_INFO(m_logger, "{} 创建报警文件夹成功: {}", m_logBase, itemDirName.toStdString());
  392. }
  393. }
  394. /* 生成文件名, 格式: Alarm_RoadNum_AlarmType_yyyyMMdd_hhmmss-yyyyMMdd_hhmmss.wav
  395. 这里创建的录音文件只有开始日期,没有结束日期,等报警结束之后才会有结束日期 */
  396. QString fileName = QString("Alarm_%1_%2_%3-.wav")
  397. .arg(QString::number(alarmInfo.RoadInfo.nCompareRoadNum))
  398. .arg(getAlarmTypeString(alarmInfo.AlarmType))
  399. .arg(alarmInfo.StartTime.toString("yyyyMMdd_hhmmss"));
  400. /* 拼接文件夹路径 */
  401. retFileName = itemDir.filePath(fileName);
  402. }else
  403. {
  404. /* 已有的文件,是报警结束的文件名 */
  405. retFileName = QString::fromStdString(alarmInfo.strAlarmFilePath);
  406. /* 这里的文件名格式是:Alarm_CompareItemID_RoadNum_AlarmType_yyyyMMdd_hhmmss-yyyyMMdd_hhmmss.wav,
  407. 这里带上结束时间 */
  408. QString endTimeStr = alarmInfo.EndTime.toString("yyyyMMdd_hhmmss");
  409. /* 替换掉原来的结束时间 */
  410. retFileName.replace("-.wav", QString("-%1.wav").arg(endTimeStr));
  411. }
  412. return retFileName;
  413. }
  414. /* 写入报警文件 */
  415. void CreateLongFileThread::writeAlarmFile()
  416. {
  417. /* 先判断环形队列中数据是否足够的秒数,不一定是每一秒都会写的 */
  418. }
  419. /* 设置今日报警文件夹 */
  420. bool CreateLongFileThread::setTodayAlarmPath()
  421. {
  422. /* 先检查当天日期文件夹是否存在,因为其他线程可能已经创建了 */
  423. QDate today = QDate::currentDate();
  424. if(today == m_todayDateAlarm)
  425. {
  426. return true; // 今天的目录已经存在
  427. }
  428. m_todayDateAlarm = today;
  429. /* 创建今日报警目录 */
  430. /* 格式: Application/2025-07-21 */
  431. QString todayDirName = QString("%1/%2").arg(GInfo.alarmWavPath()).arg(today.toString("yyyy-MM-dd"));
  432. m_todayDirAlarm.setPath(todayDirName);
  433. if(!m_todayDirAlarm.exists())
  434. {
  435. if(!m_todayDirAlarm.mkpath(todayDirName))
  436. {
  437. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建今日报警目录失败: {}", m_logBase, todayDirName.toStdString());
  438. return false; // 创建目录失败
  439. } else {
  440. SPDLOG_LOGGER_INFO(m_logger, "{} 创建今日报警目录成功: {}", m_logBase, todayDirName.toStdString());
  441. }
  442. }
  443. /* 设置目录 */
  444. m_todayDirAlarm.setPath(todayDirName);
  445. QString yesterdayDirName = QString("%1/%2").arg(GInfo.alarmWavPath()).arg(QDate::currentDate().addDays(-1).toString("yyyy-MM-dd"));
  446. m_yesterdayDir.setPath(yesterdayDirName);
  447. return true;
  448. }
  449. /* 根据报警类型的枚举获取字符 */
  450. QString CreateLongFileThread::getAlarmTypeString(EAlarmType type) const
  451. {
  452. switch(type)
  453. {
  454. case EAlarmType::EAT_Silent:
  455. return "Silent";
  456. case EAlarmType::EAT_Overload:
  457. return "Overload";
  458. case EAlarmType::EAT_Reversed:
  459. return "Reversed";
  460. case EAlarmType::EAR_Consistency:
  461. return "Consistency";
  462. case EAlarmType::EAT_Noise:
  463. return "Noise";
  464. default:
  465. return "Unknown";
  466. }
  467. }