1
0

2 Commits c4a1f1158b ... c31e9a1ad1

Autor SHA1 Mensagem Data
  Apple c31e9a1ad1 V0.3.1 há 1 semana atrás
  Apple 388ce4c8d6 V0.3 há 1 semana atrás
100 ficheiros alterados com 961 adições e 380 exclusões
  1. 3 2
      Server/GlobalInfo/GlobalInfo.h
  2. 64 0
      Server/LHLibraryAPI/signalstats.h
  3. 0 0
      Server/LHLibraryAPI/signalstats_wrapper.h_
  4. 172 107
      Server/ThreadCalculate/CalculateDBThread.cpp
  5. 9 5
      Server/ThreadCalculate/CalculateDBThread.h
  6. 95 9
      Server/ThreadCalculate/CompareDoubleThread.cpp
  7. 17 1
      Server/ThreadCalculate/CompareDoubleThread.h
  8. 89 89
      Server/ThreadCalculate/CompareItemThread.cpp
  9. 8 8
      Server/ThreadCalculate/CompareItemThread.h
  10. 16 10
      Server/ThreadCalculate/NoiseDetectThread.cpp
  11. 25 10
      Server/ThreadManager/ThreadManager.cpp
  12. 5 1
      Server/ThreadManager/ThreadManager.h
  13. 295 126
      Server/ThreadRecord/CreateLongFileThread.cpp
  14. 95 4
      Server/ThreadRecord/CreateLongFileThread.h
  15. 2 0
      Server/ThreadRecord/CreateWAVThread.cpp
  16. 1 1
      Server/main.cpp
  17. 1 1
      ThreeLib/demo/noiseTest.cpp
  18. BIN
      ThreeLib/signalstats-uos-v1.tar.gz
  19. 64 0
      ThreeLib/signalstats/include/signalstats.h
  20. 0 0
      ThreeLib/signalstats/include/signalstats_wrapper.h_
  21. 0 1
      ThreeLib/signalstats/lib/libffi.7.so
  22. 0 1
      ThreeLib/signalstats/lib/libffi.8.so
  23. 0 1
      ThreeLib/signalstats/lib/libffi.so
  24. 0 1
      ThreeLib/signalstats/lib/libffi.so.7
  25. 0 1
      ThreeLib/signalstats/lib/libffi.so.8
  26. BIN
      ThreeLib/signalstats/lib/libffi.so.8.1.2
  27. 0 1
      ThreeLib/signalstats/lib/libpython3.12.so
  28. BIN
      ThreeLib/signalstats/lib/libpython3.12.so.1.0
  29. BIN
      ThreeLib/signalstats/lib/libpython3.so
  30. BIN
      ThreeLib/signalstats/lib/libsignalstats.so
  31. BIN
      ThreeLib/signalstats/lib/libsignalstats.so.1
  32. BIN
      ThreeLib/signalstats/lib/libsignalstats.so.1.0
  33. BIN
      ThreeLib/signalstats/lib/python3.12/__future__.pyc
  34. BIN
      ThreeLib/signalstats/lib/python3.12/_compat_pickle.pyc
  35. BIN
      ThreeLib/signalstats/lib/python3.12/_compression.pyc
  36. BIN
      ThreeLib/signalstats/lib/python3.12/_sysconfigdata__linux_x86_64-linux-gnu.pyc
  37. BIN
      ThreeLib/signalstats/lib/python3.12/_weakrefset.pyc
  38. BIN
      ThreeLib/signalstats/lib/python3.12/argparse.pyc
  39. BIN
      ThreeLib/signalstats/lib/python3.12/ast.pyc
  40. BIN
      ThreeLib/signalstats/lib/python3.12/base64.pyc
  41. BIN
      ThreeLib/signalstats/lib/python3.12/bisect.pyc
  42. BIN
      ThreeLib/signalstats/lib/python3.12/calendar.pyc
  43. BIN
      ThreeLib/signalstats/lib/python3.12/collections/__init__.pyc
  44. BIN
      ThreeLib/signalstats/lib/python3.12/collections/abc.pyc
  45. BIN
      ThreeLib/signalstats/lib/python3.12/concurrent/__init__.pyc
  46. BIN
      ThreeLib/signalstats/lib/python3.12/concurrent/futures/__init__.pyc
  47. BIN
      ThreeLib/signalstats/lib/python3.12/concurrent/futures/_base.pyc
  48. BIN
      ThreeLib/signalstats/lib/python3.12/concurrent/futures/process.pyc
  49. BIN
      ThreeLib/signalstats/lib/python3.12/concurrent/futures/thread.pyc
  50. BIN
      ThreeLib/signalstats/lib/python3.12/contextlib.pyc
  51. BIN
      ThreeLib/signalstats/lib/python3.12/contextvars.pyc
  52. BIN
      ThreeLib/signalstats/lib/python3.12/copy.pyc
  53. BIN
      ThreeLib/signalstats/lib/python3.12/copyreg.pyc
  54. BIN
      ThreeLib/signalstats/lib/python3.12/csv.pyc
  55. BIN
      ThreeLib/signalstats/lib/python3.12/ctypes/__init__.pyc
  56. BIN
      ThreeLib/signalstats/lib/python3.12/ctypes/_aix.pyc
  57. BIN
      ThreeLib/signalstats/lib/python3.12/ctypes/_endian.pyc
  58. BIN
      ThreeLib/signalstats/lib/python3.12/ctypes/macholib/__init__.pyc
  59. BIN
      ThreeLib/signalstats/lib/python3.12/ctypes/macholib/dyld.pyc
  60. BIN
      ThreeLib/signalstats/lib/python3.12/ctypes/macholib/dylib.pyc
  61. BIN
      ThreeLib/signalstats/lib/python3.12/ctypes/macholib/framework.pyc
  62. BIN
      ThreeLib/signalstats/lib/python3.12/ctypes/util.pyc
  63. BIN
      ThreeLib/signalstats/lib/python3.12/ctypes/wintypes.pyc
  64. BIN
      ThreeLib/signalstats/lib/python3.12/dataclasses.pyc
  65. BIN
      ThreeLib/signalstats/lib/python3.12/datetime.pyc
  66. BIN
      ThreeLib/signalstats/lib/python3.12/decimal.pyc
  67. BIN
      ThreeLib/signalstats/lib/python3.12/difflib.pyc
  68. BIN
      ThreeLib/signalstats/lib/python3.12/dis.pyc
  69. BIN
      ThreeLib/signalstats/lib/python3.12/email/__init__.pyc
  70. BIN
      ThreeLib/signalstats/lib/python3.12/email/_encoded_words.pyc
  71. BIN
      ThreeLib/signalstats/lib/python3.12/email/_header_value_parser.pyc
  72. BIN
      ThreeLib/signalstats/lib/python3.12/email/_parseaddr.pyc
  73. BIN
      ThreeLib/signalstats/lib/python3.12/email/_policybase.pyc
  74. BIN
      ThreeLib/signalstats/lib/python3.12/email/base64mime.pyc
  75. BIN
      ThreeLib/signalstats/lib/python3.12/email/charset.pyc
  76. BIN
      ThreeLib/signalstats/lib/python3.12/email/contentmanager.pyc
  77. BIN
      ThreeLib/signalstats/lib/python3.12/email/encoders.pyc
  78. BIN
      ThreeLib/signalstats/lib/python3.12/email/errors.pyc
  79. BIN
      ThreeLib/signalstats/lib/python3.12/email/feedparser.pyc
  80. BIN
      ThreeLib/signalstats/lib/python3.12/email/generator.pyc
  81. BIN
      ThreeLib/signalstats/lib/python3.12/email/header.pyc
  82. BIN
      ThreeLib/signalstats/lib/python3.12/email/headerregistry.pyc
  83. BIN
      ThreeLib/signalstats/lib/python3.12/email/iterators.pyc
  84. BIN
      ThreeLib/signalstats/lib/python3.12/email/message.pyc
  85. BIN
      ThreeLib/signalstats/lib/python3.12/email/mime/__init__.pyc
  86. BIN
      ThreeLib/signalstats/lib/python3.12/email/mime/application.pyc
  87. BIN
      ThreeLib/signalstats/lib/python3.12/email/mime/audio.pyc
  88. BIN
      ThreeLib/signalstats/lib/python3.12/email/mime/base.pyc
  89. BIN
      ThreeLib/signalstats/lib/python3.12/email/mime/image.pyc
  90. BIN
      ThreeLib/signalstats/lib/python3.12/email/mime/message.pyc
  91. BIN
      ThreeLib/signalstats/lib/python3.12/email/mime/multipart.pyc
  92. BIN
      ThreeLib/signalstats/lib/python3.12/email/mime/nonmultipart.pyc
  93. BIN
      ThreeLib/signalstats/lib/python3.12/email/mime/text.pyc
  94. BIN
      ThreeLib/signalstats/lib/python3.12/email/parser.pyc
  95. BIN
      ThreeLib/signalstats/lib/python3.12/email/policy.pyc
  96. BIN
      ThreeLib/signalstats/lib/python3.12/email/quoprimime.pyc
  97. BIN
      ThreeLib/signalstats/lib/python3.12/email/utils.pyc
  98. BIN
      ThreeLib/signalstats/lib/python3.12/encodings/__init__.pyc
  99. BIN
      ThreeLib/signalstats/lib/python3.12/encodings/aliases.pyc
  100. BIN
      ThreeLib/signalstats/lib/python3.12/encodings/ascii.pyc

+ 3 - 2
Server/GlobalInfo/GlobalInfo.h

@@ -211,8 +211,7 @@ private:
      * 需要有延时时间(次数),CalcRefreshDataThread线程一秒一次 */
     int m_nIsSameBothMinDBWaitNum = 3;
 
-    // 一致性对比时间间隔(单位毫秒);8000采样时建议1000毫秒,48000采样时建议3000;DoubleCompare比较时时间会自动翻倍
-    int m_nCompareTimeSpan = 2000;
+    
 
     /******************** AI比对参数(动态库比对参数) *********************/
     // AI对比持续次数
@@ -224,6 +223,8 @@ private:
     // AI对比相似度阀值,比这个阀值大,就表示一致性
     float m_fAICMPThreshold = 0.7;
 
+    // 一致性对比时间间隔(单位毫秒);8000采样时建议1000毫秒,48000采样时建议3000;DoubleCompare比较时时间会自动翻倍
+    int m_nCompareTimeSpan = 3000;
     
 };
 

+ 64 - 0
Server/LHLibraryAPI/signalstats.h

@@ -0,0 +1,64 @@
+#ifndef SIGNALSTATS_H
+#define SIGNALSTATS_H
+
+#include <nlohmann/json.hpp>
+
+// 定义导出宏
+#ifdef _WIN32
+#ifdef BUILDING_DLL
+#define EXPORT_API __declspec(dllexport)
+#else
+#define EXPORT_API __declspec(dllimport)
+#endif
+#else
+#define EXPORT_API __attribute__((visibility("default")))
+#endif
+
+namespace signalstats
+{
+    /**
+     * @brief 初始化
+     * 必须在使用前调用此函数。
+     *
+     * @param debug 是否输出调试信息
+     */
+    EXPORT_API void initialize(bool debug=false);
+
+    /**
+     * @brief 释放资源
+     *
+     * 应在程序结束时调用此函数。
+     */
+    EXPORT_API void finalize();
+
+    /**
+     * @brief 信号检测
+     *
+     * @param output 输出结果容器
+     * @param audio_signal 音频信号数据(vector)
+     * @param audio_samplerate 采样率(Hz)
+     * @param silence_threshold 静音检测阈值
+     * @param db_threshold 分贝阈值
+     * @param cv_threshold 变异系数阈值
+     * @param window_params 窗函数参数
+     * @param nperseg 每段样本数
+     * @param noverlap 重叠样本数
+     * @param nfft FFT点数
+     * @param debug 是否输出调试信息
+     * @return nlohmann::json& 输出结果容器
+     */
+    EXPORT_API nlohmann::json& detect_signal(
+        nlohmann::json &output,
+        const std::vector<double> &audio_signal,
+        double audio_samplerate,
+        double silence_threshold = 3e-3,
+        double db_threshold = -70.0,
+        double cv_threshold = -70.0,
+        const std::vector<std::string> &window_params = {"tukey", "0.25"},
+        int nperseg = 256,
+        int noverlap = 32,
+        int nfft = 256,
+        bool debug = false);
+}
+
+#endif // SIGNALSTATS_H

+ 0 - 0
Server/LHLibraryAPI/signalstats_wrapper.h → Server/LHLibraryAPI/signalstats_wrapper.h_


+ 172 - 107
Server/ThreadCalculate/CalculateDBThread.cpp

@@ -4,6 +4,7 @@
 
 #include "ThreadManager.h"
 #include "GlobalInfo.h"
+#include "ThreadAlarmManager.h"
 
 
 CalculateDBThread::CalculateDBThread(CalculateThreadInfo_t& threadInfo)
@@ -58,49 +59,49 @@ bool CalculateDBThread::getlastVolumeInfo(OneRoadVolume_t& volumeInfo)
 }
 
 /* 获取报警数据 */
-AlarmInfo_t CalculateDBThread::getAlarm(EAlarmType alarmType)
-{
-    std::lock_guard<std::mutex> lock(m_mutexVolumeInfo);
-    switch(alarmType)
-    {
-        case EAlarmType::EAT_Silent:
-            {
-                if(m_alarmSilence.AlarmType != EAlarmType::EAT_None && m_alarmLastSilence.isAlarm == false)
-                {
-                    /* 报警结束了,返回报警信息,并清空 */
-                    AlarmInfo_t alarmInfo = m_alarmLastSilence;
-                    m_alarmLastSilence = AlarmInfo_t(); // 清空报警信息
-                    return alarmInfo;
-                }
-                return m_alarmSilence;
-            }
-        case EAlarmType::EAT_Overload:
-            {
-                if(m_alarmOverload.AlarmType != EAlarmType::EAT_None && m_alarmLastOverload.isAlarm == false)
-                {
-                    /* 报警结束了,返回报警信息,并清空 */
-                    AlarmInfo_t alarmInfo = m_alarmLastOverload;
-                    m_alarmLastOverload = AlarmInfo_t(); // 清空报警信息
-                    return alarmInfo;
-                }
-                return m_alarmOverload;
-            }
-        case EAlarmType::EAT_Reversed:
-            {
-                if(m_alarmPhase.AlarmType != EAlarmType::EAT_None && m_alarmLastPhase.isAlarm == false)
-                {
-                    /* 报警结束了,返回报警信息,并清空 */
-                    AlarmInfo_t alarmInfo = m_alarmLastPhase;
-                    m_alarmLastPhase = AlarmInfo_t(); // 清空报警信息
-                    return alarmInfo;
-                }
-                return m_alarmPhase;
-            }
-        default:
-            SPDLOG_LOGGER_ERROR(m_logger, "{} 获取报警数据失败,未知报警类型: {}", m_logBase, static_cast<int>(alarmType));
-            return m_alarmNull; // 返回一个空的报警信息
-    }
-}
+// AlarmInfo_t CalculateDBThread::getAlarm(EAlarmType alarmType)
+// {
+//     std::lock_guard<std::mutex> lock(m_mutexVolumeInfo);
+//     switch(alarmType)
+//     {
+//         case EAlarmType::EAT_Silent:
+//             {
+//                 if(m_alarmSilence.AlarmType != EAlarmType::EAT_None && m_alarmLastSilence.isAlarm == false)
+//                 {
+//                     /* 报警结束了,返回报警信息,并清空 */
+//                     AlarmInfo_t alarmInfo = m_alarmLastSilence;
+//                     m_alarmLastSilence = AlarmInfo_t(); // 清空报警信息
+//                     return alarmInfo;
+//                 }
+//                 return m_alarmSilence;
+//             }
+//         case EAlarmType::EAT_Overload:
+//             {
+//                 if(m_alarmOverload.AlarmType != EAlarmType::EAT_None && m_alarmLastOverload.isAlarm == false)
+//                 {
+//                     /* 报警结束了,返回报警信息,并清空 */
+//                     AlarmInfo_t alarmInfo = m_alarmLastOverload;
+//                     m_alarmLastOverload = AlarmInfo_t(); // 清空报警信息
+//                     return alarmInfo;
+//                 }
+//                 return m_alarmOverload;
+//             }
+//         case EAlarmType::EAT_Reversed:
+//             {
+//                 if(m_alarmPhase.AlarmType != EAlarmType::EAT_None && m_alarmLastPhase.isAlarm == false)
+//                 {
+//                     /* 报警结束了,返回报警信息,并清空 */
+//                     AlarmInfo_t alarmInfo = m_alarmLastPhase;
+//                     m_alarmLastPhase = AlarmInfo_t(); // 清空报警信息
+//                     return alarmInfo;
+//                 }
+//                 return m_alarmPhase;
+//             }
+//         default:
+//             SPDLOG_LOGGER_ERROR(m_logger, "{} 获取报警数据失败,未知报警类型: {}", m_logBase, static_cast<int>(alarmType));
+//             return m_alarmNull; // 返回一个空的报警信息
+//     }
+// }
 
 /* 线程功能函数 */
 void CalculateDBThread::task()
@@ -120,7 +121,7 @@ void CalculateDBThread::task()
          * 更新最新数据
          * --------------------------------------------------------------------------------*/
         /* 获取最新数据 */
-        if(!m_threadCreateDBPhase->getLatestResult(m_caculateDBData.ringQueue))
+        if(!m_threadCreateDB->getLatestResult(m_caculateDBData.ringQueue))
         {
             // SPDLOG_LOGGER_DEBUG(m_logger, "{} 获取最新的音量数据失败", m_logBase);
             continue; // 没有获取到最新数据,继续等待
@@ -155,8 +156,17 @@ bool CalculateDBThread::initData()
     auto m_startTime = std::chrono::steady_clock::now(); // 记录开始时间
     while(true)
     {
-        m_threadCreateDBPhase = ThreadMan.getCreateDBThread(m_roadInfo.scRoadInfo.nSoundCardNum, m_roadInfo.scRoadInfo.roadInfo.nRoadNum);
-        if(m_threadCreateDBPhase != nullptr)
+        /* 获取计算音量的线程 */
+        if(m_threadCreateDB == nullptr)
+        {
+            m_threadCreateDB = ThreadMan.getCreateDBThread(m_roadInfo.scRoadInfo.nSoundCardNum, m_roadInfo.scRoadInfo.roadInfo.nRoadNum);
+        }
+        if(m_threadCreateAlarmFile == nullptr)
+        {
+            m_threadCreateAlarmFile = ThreadMan.getCreateLongFileThread(m_roadInfo.scRoadInfo.nSoundCardNum, m_roadInfo.scRoadInfo.roadInfo.nRoadNum);
+        }
+        
+        if(m_threadCreateDB != nullptr && m_threadCreateAlarmFile != nullptr)
         {
             break; // 获取到线程,跳出循环
         }
@@ -168,7 +178,7 @@ bool CalculateDBThread::initData()
         std::this_thread::sleep_for(std::chrono::milliseconds(10));
         
     }
-    if (m_threadCreateDBPhase == nullptr)
+    if (m_threadCreateDB == nullptr)
     {
         SPDLOG_LOGGER_ERROR(m_logger, "{} 获取创建音量线程失败", m_logBase);
         return false;
@@ -287,6 +297,13 @@ void CalculateDBThread::processSilence()
             }
             m_alarmSilence.StartTime = startTime; // 静音开始时间
             m_alarmSilence.EndTime = m_currSecondData.endTime;
+
+            /* 开启录音 */
+            if(!m_threadCreateAlarmFile->startRecordAlarmFile(m_alarmSilence))
+            {
+                /* 开启录制报警音频失败 */
+                SPDLOG_LOGGER_WARN(m_logger, "{} 开启录制静音报警音频失败", m_logBase);
+            }
         }else 
         {
             /* 静音报警已经开启,更新结束时间 */
@@ -311,36 +328,46 @@ void CalculateDBThread::processSilence()
             }
             /* 保存报警信息 */
             // m_alarmLastSilence = m_alarmSilence;
-            // m_alarmSilence = AlarmInfo_t(); // 清空报警信息,报警信息在对比项获取到结果后再清空
-            /* 将报警信息给截取报警文件的线程 */
+            
+            /* 停止录制报警音频 */
+            if(!m_threadCreateAlarmFile->stopRecordAlarmFile(m_alarmSilence))
+            {
+                SPDLOG_LOGGER_WARN(m_logger, "{} 停止录制静音报警音频失败", m_logBase);
+            }
+
+            /* 将报警信息发送给写入报警信息的线程 */
+            AlarmManager.addAlarmInfo(m_alarmSilence);
 
             /* 打印日志 */
             SPDLOG_LOGGER_INFO(m_logger, "{} 静音报警结束,开始时间:{},结束时间:{}",
                 m_logBase, 
                 m_alarmSilence.StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(),
                 m_alarmSilence.EndTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
+
+            /* 清空报警信息 */
+            m_alarmSilence = AlarmInfo_t();
         }
     }
 
     /* 更新结果,实时更新 */
-    if(m_alarmSilence.AlarmType != EAlarmType::EAT_None)
-    {
-        /* 有报警类型,进一步判断是否有报警 */
-        if(m_alarmSilence.isAlarm)
-        {
-            /* 有报警,更新报警信息,判断一下上次的报警是否被取走 */
-            if(m_alarmLastSilence.AlarmType == EAlarmType::EAT_None || m_alarmLastSilence.isAlarm == true)
-            {
-                /* 报警结束信息被取走了,清空了结果,或者正在报警中,更新信息 */
-                m_alarmLastSilence = m_alarmSilence;
-            }
-        }else 
-        {
-            /* 有报警类型无报警,说明是报警结束了 */
-            m_alarmLastSilence = m_alarmSilence;
-            m_alarmSilence = AlarmInfo_t(); // 清空报警信息
-        }
-    }
+    // if(m_alarmSilence.AlarmType != EAlarmType::EAT_None)
+    // {
+    //     /* 有报警类型,进一步判断是否有报警 */
+    //     if(m_alarmSilence.isAlarm)
+    //     {
+    //         /* 有报警,更新报警信息,判断一下上次的报警是否被取走 */
+    //         if(m_alarmLastSilence.AlarmType == EAlarmType::EAT_None || m_alarmLastSilence.isAlarm == true)
+    //         {
+    //             /* 报警结束信息被取走了,清空了结果,或者正在报警中,更新信息 */
+    //             m_alarmLastSilence = m_alarmSilence;
+    //         }
+    //     }else 
+    //     {
+    //         /* 有报警类型无报警,说明是报警结束了 */
+    //         m_alarmLastSilence = m_alarmSilence;
+    //         m_alarmSilence = AlarmInfo_t(); // 清空报警信息
+    //     }
+    // }
 }
 
 /* 处理过载报警 */
@@ -369,6 +396,14 @@ void CalculateDBThread::processOverload()
             }
             m_alarmOverload.StartTime = startTime; // 过载开始时间
             m_alarmOverload.EndTime = m_currSecondData.endTime;
+
+            /* 开启录音 */
+            if(!m_threadCreateAlarmFile->startRecordAlarmFile(m_alarmSilence))
+            {
+                /* 开启录制报警音频失败 */
+                SPDLOG_LOGGER_WARN(m_logger, "{} 开启录制过载报警音频失败", m_logBase);
+            }
+
         }else 
         {
             /* 过载报警已经开启,更新结束时间 */
@@ -393,36 +428,47 @@ void CalculateDBThread::processOverload()
             }
             /* 保存报警信息 */
             // m_alarmLastOverload = m_alarmOverload;
-            // m_alarmOverload = AlarmInfo_t(); // 清空报警信息
-            /* 将报警信息给截取报警文件的线程 */
+            
+            /* 停止录制报警音频 */
+            if(!m_threadCreateAlarmFile->stopRecordAlarmFile(m_alarmOverload))
+            {
+                SPDLOG_LOGGER_WARN(m_logger, "{} 停止录制过载报警音频失败", m_logBase);
+            }
+
+            /* 将报警信息发送给写入报警信息的线程 */
+            AlarmManager.addAlarmInfo(m_alarmOverload);
+
 
             /* 打印日志 */
             SPDLOG_LOGGER_INFO(m_logger, "{} 过载报警结束,开始时间:{},结束时间:{}",
                 m_logBase, 
                 m_alarmOverload.StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(),
                 m_alarmOverload.EndTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
+            
+            /* 清空报警信息 */
+            m_alarmOverload = AlarmInfo_t();
         }
     }
 
     /* 更新结果,实时更新 */
-    if(m_alarmOverload.AlarmType != EAlarmType::EAT_None)
-    {
-        /* 有报警类型,进一步判断是否有报警 */
-        if(m_alarmOverload.isAlarm)
-        {
-            /* 有报警,更新报警信息,判断一下上次的报警是否被取走 */
-            if(m_alarmLastOverload.AlarmType == EAlarmType::EAT_None || m_alarmLastOverload.isAlarm == true)
-            {
-                /* 报警结束信息被取走了,或者正在报警中,更新信息 */
-                m_alarmLastOverload = m_alarmOverload;
-            }
-        }else 
-        {
-            /* 有报警类型无报警,说明是报警结束了 */
-            m_alarmLastOverload = m_alarmOverload;
-            m_alarmOverload = AlarmInfo_t(); // 清空报警信息
-        }
-    }
+    // if(m_alarmOverload.AlarmType != EAlarmType::EAT_None)
+    // {
+    //     /* 有报警类型,进一步判断是否有报警 */
+    //     if(m_alarmOverload.isAlarm)
+    //     {
+    //         /* 有报警,更新报警信息,判断一下上次的报警是否被取走 */
+    //         if(m_alarmLastOverload.AlarmType == EAlarmType::EAT_None || m_alarmLastOverload.isAlarm == true)
+    //         {
+    //             /* 报警结束信息被取走了,或者正在报警中,更新信息 */
+    //             m_alarmLastOverload = m_alarmOverload;
+    //         }
+    //     }else 
+    //     {
+    //         /* 有报警类型无报警,说明是报警结束了 */
+    //         m_alarmLastOverload = m_alarmOverload;
+    //         m_alarmOverload = AlarmInfo_t(); // 清空报警信息
+    //     }
+    // }
     
 }
 
@@ -452,6 +498,14 @@ void CalculateDBThread::processPhase()
             }
             m_alarmPhase.StartTime = startTime; // 反相开始时间
             m_alarmPhase.EndTime = m_currSecondData.endTime;
+
+            /* 开启录音 */
+            if(!m_threadCreateAlarmFile->startRecordAlarmFile(m_alarmSilence))
+            {
+                /* 开启录制报警音频失败 */
+                SPDLOG_LOGGER_WARN(m_logger, "{} 开启录制反相报警音频失败", m_logBase);
+            }
+
         }else 
         {
             /* 反相报警已经开启,更新结束时间 */
@@ -476,35 +530,46 @@ void CalculateDBThread::processPhase()
             }
             /* 保存报警信息 */
             // m_alarmLastPhase = m_alarmPhase;
-            // m_alarmPhase = AlarmInfo_t(); // 清空报警信息
-            /* 将报警信息给截取报警文件的线程 */
+            
+            /* 停止录制报警音频 */
+            if(!m_threadCreateAlarmFile->stopRecordAlarmFile(m_alarmPhase))
+            {
+                SPDLOG_LOGGER_WARN(m_logger, "{} 停止录制反相报警音频失败", m_logBase);
+            }
+
+            /* 将报警信息发送给写入报警信息的线程 */
+            AlarmManager.addAlarmInfo(m_alarmPhase);
+
             /* 打印日志 */
             SPDLOG_LOGGER_INFO(m_logger, "{} 反相报警结束,开始时间:{},结束时间:{}",
                 m_logBase, 
                 m_alarmPhase.StartTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(),
                 m_alarmPhase.EndTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
+            
+            /* 清空报警信息 */
+            m_alarmPhase = AlarmInfo_t();
         }
     }
 
     /* 更新结果,实时更新 */
-    if(m_alarmPhase.AlarmType != EAlarmType::EAT_None)
-    {
-        /* 有报警类型,进一步判断是否有报警 */
-        if(m_alarmPhase.isAlarm)
-        {
-            /* 有报警,更新报警信息,判断一下上次的报警是否被取走 */
-            if(m_alarmLastPhase.AlarmType == EAlarmType::EAT_None || m_alarmLastPhase.isAlarm == true)
-            {
-                /* 报警结束信息被取走了,或者正在报警中,更新信息 */
-                m_alarmLastPhase = m_alarmPhase;
-            }
-        }else 
-        {
-            /* 有报警类型无报警,说明是报警结束了 */
-            m_alarmLastPhase = m_alarmPhase;
-            m_alarmPhase = AlarmInfo_t(); // 清空报警信息
-        }
-    }
+    // if(m_alarmPhase.AlarmType != EAlarmType::EAT_None)
+    // {
+    //     /* 有报警类型,进一步判断是否有报警 */
+    //     if(m_alarmPhase.isAlarm)
+    //     {
+    //         /* 有报警,更新报警信息,判断一下上次的报警是否被取走 */
+    //         if(m_alarmLastPhase.AlarmType == EAlarmType::EAT_None || m_alarmLastPhase.isAlarm == true)
+    //         {
+    //             /* 报警结束信息被取走了,或者正在报警中,更新信息 */
+    //             m_alarmLastPhase = m_alarmPhase;
+    //         }
+    //     }else 
+    //     {
+    //         /* 有报警类型无报警,说明是报警结束了 */
+    //         m_alarmLastPhase = m_alarmPhase;
+    //         m_alarmPhase = AlarmInfo_t(); // 清空报警信息
+    //     }
+    // }
 }
 
 

+ 9 - 5
Server/ThreadCalculate/CalculateDBThread.h

@@ -4,6 +4,7 @@
 #include "AudioData.h"
 #include "BaseCalculateThread.h"
 #include "CreateDBThread.h"
+#include "CreateLongFileThread.h"
 #include "SendStruct.h"
 #include "CalculateAudio.h"
 #include "CompareResult.h"
@@ -34,7 +35,7 @@ public:
     /* 获取最新音量值计算的结果 */
     bool getlastVolumeInfo(OneRoadVolume_t& volumeInfo);
     /* 获取最新的结果,实时结果 */
-    AlarmInfo_t getAlarm(EAlarmType alarmType);
+    // AlarmInfo_t getAlarm(EAlarmType alarmType);
 
 protected:
     /* 线程功能函数 */
@@ -68,10 +69,13 @@ private:
     OneRoadVolume_t m_roadVolumeInfo;                       /* 一个录音通道的音量信息这个是计算结果 */
 
     /* 生成音量的线程 */
-    CreateDBThread* m_threadCreateDBPhase = nullptr;        /* 生成音量的线程 */
+    CreateDBThread* m_threadCreateDB = nullptr;             /* 生成音量的线程 */
     OneSecondData m_currSecondData;                         /* 最新一秒的数据 */
     StVolumeParam m_volumeParam;                            /* 音量计算的参数 */
 
+    /* 录制报警文件的线程 */
+    CreateLongFileThread* m_threadCreateAlarmFile = nullptr;
+
     int32_t m_numQueueSeconds = 0;                         /* 队列元素数目,单位:秒 */
     CaculateDBData m_caculateDBData;                        /* 计算音量的环形队列类 */
 
@@ -94,9 +98,9 @@ private:
 
     /* 这里的报警信息作为返回给对比项线程的中介,防止刚结束报警,结果还未取出,又来了一个报警,
      * 报警时间粘连的问题 */
-    AlarmInfo_t m_alarmLastSilence;                         /* 上一次静音报警信息 */
-    AlarmInfo_t m_alarmLastOverload;                        /* 上一次过载报警信息 */
-    AlarmInfo_t m_alarmLastPhase;                           /* 上一次反相报警信息 */
+    // AlarmInfo_t m_alarmLastSilence;                         /* 上一次静音报警信息 */
+    // AlarmInfo_t m_alarmLastOverload;                        /* 上一次过载报警信息 */
+    // AlarmInfo_t m_alarmLastPhase;                           /* 上一次反相报警信息 */
     AlarmInfo_t m_alarmNull;                                /* 空报警信息 */
 };
 

+ 95 - 9
Server/ThreadCalculate/CompareDoubleThread.cpp

@@ -6,8 +6,8 @@
 #include "GlobalInfo.h"
 #include "ThreadManager.h"
 #include "ConsistencyCompareThread.h"
-#include "ThreadPool.h"
-
+#include "CreateLongFileThread.h"
+#include "ThreadAlarmManager.h"
 
 
 CompareDoubleThread::CompareDoubleThread(CalculateThreadInfo_t& compareItemInfo)
@@ -103,10 +103,13 @@ bool CompareDoubleThread::initData()
         SPDLOG_LOGGER_WARN(m_logger, "{} 对比项信息错误,录音通道数量小于2", m_threadInfo.compareItemInfo.strName.toStdString());
         return false;
     }
-    auto begin = m_threadInfo.compareItemInfo.mapRoad.begin();
-    m_roadInfo1 = begin->scRoadInfo;
-    begin++; // 移动到下一个元素
-    m_roadInfo2 = begin->scRoadInfo; // 录音通道2信息
+    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);
@@ -121,10 +124,13 @@ bool CompareDoubleThread::initData()
     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);
@@ -133,14 +139,25 @@ bool CompareDoubleThread::initData()
         {
             m_threadCreateDB2 = ThreadMan.getCreateDBThread(m_roadInfo2.nSoundCardNum, m_roadInfo2.roadInfo.nRoadNum);
         }
-        if(m_threadCreateDB1 != nullptr && m_threadCreateDB2 != nullptr)
+
+        /* 获取生成报警音频文件的线程 */
+        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))
         {
-            SPDLOG_LOGGER_ERROR(m_logger, "{} 获取生成音量的线程超时",  m_logBase);
             return false;
         }
         std::this_thread::sleep_for(std::chrono::milliseconds(10));
@@ -151,6 +168,12 @@ bool CompareDoubleThread::initData()
         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);
@@ -316,13 +339,19 @@ void CompareDoubleThread::calculateData()
     } 
     
 
-    /* 保存计算信息,目前只保存了一致性结果和报警 */
+    /* ---------------------------------------------------------------
+     * 保存计算信息,目前只保存了一致性结果和报警
+     * ---------------------------------------------------------------*/
     {
         std::lock_guard<std::mutex> lock(m_mutexVolumeInfo);
+        /* 保存一致性结果 */
         m_roadResult.isConsistency = oneRoadVolume.isConsistency;
         m_roadResult.isNotConsistencyWarning = oneRoadVolume.isNotConsistencyWarning;
 
         m_roadResult.dateTime = oneRoadVolume.dateTime;
+
+        /* 保存报警信息 */
+        saveAlarmInfo();
     }
 }
 
@@ -637,3 +666,60 @@ bool CompareDoubleThread::isSameBothMinDB(int db)
     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);
+        }
+    }
+}
+

+ 17 - 1
Server/ThreadCalculate/CompareDoubleThread.h

@@ -13,6 +13,8 @@
 
 
 class ConsistencyCompareThread;
+class CreateLongFileThread;
+
 
 /**
     功能:再检测一遍一致性和噪音,和动态库检测结果进行对比
@@ -85,12 +87,18 @@ private:
     /* 两个低音量是否相似 */
     bool isSameBothMinDB(int db);
 
+    /* 保存报警信息 */
+    void saveAlarmInfo();
+
 private:
     /* ----------------- 基础成员变量 ------------------ */
     SoundCardRoadInfo_t m_roadInfo1;                        /* 录音通道1信息 */
     SoundCardRoadInfo_t m_roadInfo2;                        /* 录音通道2信息 */
+    CompareItemRoadInfo_t m_itemRoadInfo1;                  /* 对比项通道1信息,这两个给报警信息使用的 */
+    CompareItemRoadInfo_t m_itemRoadInfo2;                  /* 对比项通道2信息 */
+    
 
-    /* 生成音量数据的线程 */
+    /* ----------------- 生成音量数据的线程 ------------------ */
     CreateDBThread* m_threadCreateDB1 = nullptr;            /* 生成通道1音量数据的线程 */
     CreateDBThread* m_threadCreateDB2 = nullptr;            /* 生成通道2音量数据的线程 */
     bool m_isUpdated1 = false;                              /* 通道1数据是否更新 */
@@ -99,6 +107,10 @@ private:
     CaculateDBData m_localData1;
     CaculateDBData m_localData2;
 
+    /* ----------------- 生成报警音频文件的线程 ------------------ */
+    CreateLongFileThread* m_threadCreateAlarmFile1 = nullptr;
+    CreateLongFileThread* m_threadCreateAlarmFile2 = nullptr;
+
     /* 计算音量静音、过载、反相的线程,从这里获取到填充好的音量包 */
 
 
@@ -174,7 +186,11 @@ private:
 
     // AI对比更正次数
     int32_t m_arryAIChangeRetNum[8];
+    int m_nCompareTimeSpan = 3000;              // 比对时间间隔,单位毫秒
 
+    /* 一致性报警信息 */
+    AlarmInfo_t m_alarmConsistencyMain;         /* 一致性报警信息,主通道 */
+    AlarmInfo_t m_alarmConsistencySub;          /* 一致性报警信息,次通道 */
 };
 
 #endif // _CompareDoubleThread_H_

+ 89 - 89
Server/ThreadCalculate/CompareItemThread.cpp

@@ -224,7 +224,7 @@ bool CompareItemThread::initData()
 
     /* 获取计算噪音的线程 */
     removeNoiseDetectThreads(); // 清理之前的噪音检测线程
-    // getNoiseDetectThreads();
+    getNoiseDetectThreads();
 
     /* 初始化存储结果的数据结构 */
     m_compareResult = CompareResult_t();
@@ -248,25 +248,25 @@ bool CompareItemThread::initData()
     }
 
     /* 初始化报警信息 */
-    m_mapAlarmSilence.clear();
-    m_mapAlarmOverload.clear();
-    m_mapAlarmPhase.clear();
-    for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
-    {
-        m_mapAlarmSilence.insert({road.nCompareRoadNum, AlarmInfo_t()});
-        m_mapAlarmOverload.insert({road.nCompareRoadNum, AlarmInfo_t()});
-        m_mapAlarmPhase.insert({road.nCompareRoadNum, AlarmInfo_t()});
-    }
-
-    m_mapAlarmSilenceLast.clear();
-    m_mapAlarmOverloadLast.clear();
-    m_mapAlarmPhaseLast.clear();
-    for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
-    {
-        m_mapAlarmSilenceLast.insert({road.nCompareRoadNum, AlarmInfo_t()});
-        m_mapAlarmOverloadLast.insert({road.nCompareRoadNum, AlarmInfo_t()});
-        m_mapAlarmPhaseLast.insert({road.nCompareRoadNum, AlarmInfo_t()});
-    }
+    // m_mapAlarmSilence.clear();
+    // m_mapAlarmOverload.clear();
+    // m_mapAlarmPhase.clear();
+    // for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
+    // {
+    //     m_mapAlarmSilence.insert({road.nCompareRoadNum, AlarmInfo_t()});
+    //     m_mapAlarmOverload.insert({road.nCompareRoadNum, AlarmInfo_t()});
+    //     m_mapAlarmPhase.insert({road.nCompareRoadNum, AlarmInfo_t()});
+    // }
+
+    // m_mapAlarmSilenceLast.clear();
+    // m_mapAlarmOverloadLast.clear();
+    // m_mapAlarmPhaseLast.clear();
+    // for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
+    // {
+    //     m_mapAlarmSilenceLast.insert({road.nCompareRoadNum, AlarmInfo_t()});
+    //     m_mapAlarmOverloadLast.insert({road.nCompareRoadNum, AlarmInfo_t()});
+    //     m_mapAlarmPhaseLast.insert({road.nCompareRoadNum, AlarmInfo_t()});
+    // }
     
 
     return true;
@@ -499,9 +499,9 @@ bool CompareItemThread::updateResultData()
             continue; // 没有获取到最新数据,继续等待
         }
         /* 更新报警信息 */
-        m_mapAlarmSilence[pair.first] = pThread->getAlarm(EAlarmType::EAT_Silent);
-        m_mapAlarmOverload[pair.first] = pThread->getAlarm(EAlarmType::EAT_Overload);
-        m_mapAlarmPhase[pair.first] = pThread->getAlarm(EAlarmType::EAT_Reversed);
+        // m_mapAlarmSilence[pair.first] = pThread->getAlarm(EAlarmType::EAT_Silent);
+        // m_mapAlarmOverload[pair.first] = pThread->getAlarm(EAlarmType::EAT_Overload);
+        // m_mapAlarmPhase[pair.first] = pThread->getAlarm(EAlarmType::EAT_Reversed);
 
         pair.second = true; // 设置更新标志位为true
     }
@@ -565,74 +565,74 @@ bool CompareItemThread::updateResultData()
         3、静音、过载、反相报警信息直接从计算音量的线程中获取,一致性报警从对比项线程中获取,
             噪音报警从噪音检测线程中获取
  */
-void CompareItemThread::processAlarmData()
-{
-    m_listWriteAlarm.clear();
-    /* 处理静音报警数据 */
-    for(auto& pair : m_mapAlarmSilence)
-    {
-        auto& nowAlarm = pair.second;
-        auto& lastAlarm = m_mapAlarmSilenceLast[pair.first];
-        if(nowAlarm.isAlarm)
-        {
-            if(lastAlarm == nowAlarm)
-            {
-                continue; // 和上次的报警信息一样,不需要处理
-            }else {
-                nowAlarm.CompareItemID = m_threadInfo.compareItemInfo.nID;
-                nowAlarm.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString();
-                m_listWriteAlarm.push_back(nowAlarm);
-                m_mapAlarmSilenceLast[pair.first] = nowAlarm;
-            }
-        }
-    }
-
-    /* 处理过载报警数据 */
-    for(auto& pair : m_mapAlarmOverload)
-    {
-        auto& nowAlarm = pair.second;
-        auto& lastAlarm = m_mapAlarmOverloadLast[pair.first];
-        if(nowAlarm.isAlarm)
-        {
-            if(lastAlarm == nowAlarm)
-            {
-                continue; // 和上次的报警信息一样,不需要处理
-            }else {
-                nowAlarm.CompareItemID = m_threadInfo.compareItemInfo.nID;
-                nowAlarm.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString();
-                m_listWriteAlarm.push_back(nowAlarm);
-                m_mapAlarmOverloadLast[pair.first] = nowAlarm;
-            }
-        }
-    }
-
-    /* 处理反相报警数据 */
-    for(auto& pair : m_mapAlarmPhase)
-    {
-        auto& nowAlarm = pair.second;
-        auto& lastAlarm = m_mapAlarmPhaseLast[pair.first];
-        if(nowAlarm.isAlarm)
-        {
-            if(lastAlarm == nowAlarm)
-            {
-                continue; // 和上次的报警信息一样,不需要处理
-            }else {
-                nowAlarm.CompareItemID = m_threadInfo.compareItemInfo.nID;
-                nowAlarm.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString();
-                m_listWriteAlarm.push_back(nowAlarm);
-                m_mapAlarmPhaseLast[pair.first] = nowAlarm;
-            }
-        }
-    }
-
-    /* 处理一致性报警信息 */
-
-    /* 处理噪音报警信息 */
+// void CompareItemThread::processAlarmData()
+// {
+//     m_listWriteAlarm.clear();
+//     /* 处理静音报警数据 */
+//     for(auto& pair : m_mapAlarmSilence)
+//     {
+//         auto& nowAlarm = pair.second;
+//         auto& lastAlarm = m_mapAlarmSilenceLast[pair.first];
+//         if(nowAlarm.isAlarm)
+//         {
+//             if(lastAlarm == nowAlarm)
+//             {
+//                 continue; // 和上次的报警信息一样,不需要处理
+//             }else {
+//                 nowAlarm.CompareItemID = m_threadInfo.compareItemInfo.nID;
+//                 nowAlarm.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString();
+//                 m_listWriteAlarm.push_back(nowAlarm);
+//                 m_mapAlarmSilenceLast[pair.first] = nowAlarm;
+//             }
+//         }
+//     }
+
+//     /* 处理过载报警数据 */
+//     for(auto& pair : m_mapAlarmOverload)
+//     {
+//         auto& nowAlarm = pair.second;
+//         auto& lastAlarm = m_mapAlarmOverloadLast[pair.first];
+//         if(nowAlarm.isAlarm)
+//         {
+//             if(lastAlarm == nowAlarm)
+//             {
+//                 continue; // 和上次的报警信息一样,不需要处理
+//             }else {
+//                 nowAlarm.CompareItemID = m_threadInfo.compareItemInfo.nID;
+//                 nowAlarm.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString();
+//                 m_listWriteAlarm.push_back(nowAlarm);
+//                 m_mapAlarmOverloadLast[pair.first] = nowAlarm;
+//             }
+//         }
+//     }
+
+//     /* 处理反相报警数据 */
+//     for(auto& pair : m_mapAlarmPhase)
+//     {
+//         auto& nowAlarm = pair.second;
+//         auto& lastAlarm = m_mapAlarmPhaseLast[pair.first];
+//         if(nowAlarm.isAlarm)
+//         {
+//             if(lastAlarm == nowAlarm)
+//             {
+//                 continue; // 和上次的报警信息一样,不需要处理
+//             }else {
+//                 nowAlarm.CompareItemID = m_threadInfo.compareItemInfo.nID;
+//                 nowAlarm.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString();
+//                 m_listWriteAlarm.push_back(nowAlarm);
+//                 m_mapAlarmPhaseLast[pair.first] = nowAlarm;
+//             }
+//         }
+//     }
+
+//     /* 处理一致性报警信息 */
+
+//     /* 处理噪音报警信息 */
 
     
-    /* 将报警列表写入到处理报警数据的线程中 */
-    AlarmManager.addAlarmInfo(m_listWriteAlarm);
-}
+//     /* 将报警列表写入到处理报警数据的线程中 */
+//     AlarmManager.addAlarmInfo(m_listWriteAlarm);
+// }
 
 /* 发送数据 */
 void CompareItemThread::sendResultData()

+ 8 - 8
Server/ThreadCalculate/CompareItemThread.h

@@ -84,7 +84,7 @@ private:
     /* 更新数据 */
     bool updateResultData();
     /* 处理报警数据,写入数据库 */
-    void processAlarmData();
+    // void processAlarmData();
     /* 发送数据 */
     void sendResultData();
 
@@ -117,16 +117,16 @@ private:
     CompareResult_t m_compareResult;
 
     /* 存储报警信息,int是对比项中的通道编号 */
-    std::map<int, AlarmInfo_t> m_mapAlarmSilence;           /* 静音报警信息 */
-    std::map<int, AlarmInfo_t> m_mapAlarmOverload;          /* 过载报警信息 */
-    std::map<int, AlarmInfo_t> m_mapAlarmPhase;             /* 反相报警信息 */
+    // std::map<int, AlarmInfo_t> m_mapAlarmSilence;           /* 静音报警信息 */
+    // std::map<int, AlarmInfo_t> m_mapAlarmOverload;          /* 过载报警信息 */
+    // std::map<int, AlarmInfo_t> m_mapAlarmPhase;             /* 反相报警信息 */
 
-    std::map<int, AlarmInfo_t> m_mapAlarmSilenceLast;       /* 上一次静音报警信息 */
-    std::map<int, AlarmInfo_t> m_mapAlarmOverloadLast;      /* 上一次过载报警信息 */
-    std::map<int, AlarmInfo_t> m_mapAlarmPhaseLast;         /* 上一次反相报警信息 */
+    // std::map<int, AlarmInfo_t> m_mapAlarmSilenceLast;       /* 上一次静音报警信息 */
+    // std::map<int, AlarmInfo_t> m_mapAlarmOverloadLast;      /* 上一次过载报警信息 */
+    // std::map<int, AlarmInfo_t> m_mapAlarmPhaseLast;         /* 上一次反相报警信息 */
 
     /* 要写入到数据库的报警信息 */
-    std::list<AlarmInfo_t> m_listWriteAlarm;;
+    // std::list<AlarmInfo_t> m_listWriteAlarm;;
 };
 
 

+ 16 - 10
Server/ThreadCalculate/NoiseDetectThread.cpp

@@ -6,7 +6,7 @@
 #include "ThreadManager.h"
 #include "commonDefine.h"
 #include "GlobalInfo.h"
-#include "signalstats_wrapper.h"
+#include "signalstats.h"
 #include "spdlog.h"
 
 
@@ -50,7 +50,7 @@ void NoiseDetectThread::task()
         {
             continue;
         }
-        SPDLOG_LOGGER_ERROR(m_logger, "{} 获取最新的左右声道数据成功,开始调用动态库计算噪音------------------------------------------ ", m_logBase);
+        // SPDLOG_LOGGER_ERROR(m_logger, "{} 获取最新的左右声道数据成功,开始调用动态库计算噪音------------------------------------------ ", m_logBase);
         /*------------------------------------------------------------------------
          * 计算数据
          *------------------------------------------------------------------------*/
@@ -89,7 +89,7 @@ bool NoiseDetectThread::initData()
     m_sample_rate = static_cast<double>(sampleRate);
 
     /* 初始化噪音检测功能 */
-    signalstats_wrapper::initialize();
+    // signalstats_wrapper::initialize();
 
     return true;
 }
@@ -98,13 +98,13 @@ bool NoiseDetectThread::initData()
 void NoiseDetectThread::clearData()
 {
     /* 释放资源 */
-    signalstats_wrapper::finalize();
+    // signalstats_wrapper::finalize();
 }
 
 /* 调用动态库检测噪音 */
 bool NoiseDetectThread::detectNoise()
 {
-    SPDLOG_LOGGER_ERROR(m_logger, "{} 开始调用动态库计算噪音", m_logBase);
+    // SPDLOG_LOGGER_TRACE(m_logger, "{} 开始调用动态库计算噪音", m_logBase);
     SPDLOG_LOGGER_INFO(m_logger, "{} 左声道数据大小: {}, 右声道数据大小: {}", 
         m_logBase, m_leftRightData.vecLeftData.size(), m_leftRightData.vecRightData.size());
 
@@ -124,7 +124,7 @@ bool NoiseDetectThread::detectNoise()
     {
         /*-------------------------- 先检测左声道 --------------------------*/
         nJson jsonOutput;
-        auto ret = signalstats_wrapper::detect_signal_wrapper(
+        auto ret = signalstats::detect_signal(
             jsonOutput,             /* 返回结果,和jsonResult是一样的 */
             m_leftRightData.vecLeftData,  /* 左声道数据 */
             // audio_signal,           /* 测试数据 */
@@ -142,12 +142,12 @@ bool NoiseDetectThread::detectNoise()
 
         std::chrono::duration<double> duration = std::chrono::steady_clock::now() - startTime;
         std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
-        SPDLOG_LOGGER_ERROR(m_logger, "{} 计算左声道噪音耗时: {}ms", m_logBase, ms.count());
+        SPDLOG_LOGGER_DEBUG(m_logger, "{} 计算左声道噪音耗时: {}ms", m_logBase, ms.count());
         startTime = std::chrono::steady_clock::now(); /* 重置开始时间 */
 
         /*-------------------------- 再检测右声道 --------------------------*/
         jsonOutput.clear(); /* 清空输出结果 */
-        signalstats_wrapper::detect_signal_wrapper(
+        signalstats::detect_signal(
             jsonOutput,             /* 返回结果,和jsonResult是一样的 */
             m_leftRightData.vecRightData,  /* 右声道数据 */
             // audio_signal,           /* 测试数据 */
@@ -163,6 +163,12 @@ bool NoiseDetectThread::detectNoise()
         );
         isNoiseRight = jsonOutput["noise"].is_null() ? false : jsonOutput["noise"].get<bool>();
 
+        // for(const auto& it : m_leftRightData.vecRightData)
+        // {
+        //     fmt::print("{:.5f} ", it);
+        // }
+        SPDLOG_LOGGER_DEBUG(m_logger, "{} 右声道噪音检测结果: {}", m_logBase, jsonOutput.dump(4));
+
     }
     catch (const std::exception& e)
     {
@@ -172,9 +178,9 @@ bool NoiseDetectThread::detectNoise()
 
     std::chrono::duration<double> duration = std::chrono::steady_clock::now() - startTime;
     std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
-    SPDLOG_LOGGER_ERROR(m_logger, "{} 计算右声道噪音耗时: {}ms", m_logBase, ms.count());
+    SPDLOG_LOGGER_DEBUG(m_logger, "{} 计算右声道噪音耗时: {}ms", m_logBase, ms.count());
 
-    SPDLOG_LOGGER_ERROR(m_logger, "{} 左声道噪音检测结果: {}, 右声道噪音检测结果: {}", m_logBase, isNoiseLeft, isNoiseRight);
+    SPDLOG_LOGGER_DEBUG(m_logger, "{} 左声道噪音检测结果: {}, 右声道噪音检测结果: {}", m_logBase, isNoiseLeft, isNoiseRight);
 
     /* -------------------------- 和以往的结果对比 --------------------------*/
     m_isNoiseLast = m_isNoise.load(); /* 上一次的噪音检测结果 */

+ 25 - 10
Server/ThreadManager/ThreadManager.cpp

@@ -123,16 +123,16 @@ bool ThreadManager::createRecordThread(const SoundCardRoadInfo_t& roadInfo, int
     threadInfo.threadType = EThreadType::Type_RtpSend;
     CPPTP.add_task(&ThreadManager::thread_RTPSend, threadInfo);
 
-    // RTPOneRoadThread* pRtpSendThread = new RTPOneRoadThread(threadInfo);
-    // if(pRtpSendThread == nullptr) 
-    // {
-    //     SPDLOG_LOGGER_ERROR(m_logger, "{}:{} 创建发送RTP数据线程失败", roadInfo.strSoundCardName.toStdString(), roadInfo.roadInfo.nRoadNum);
-    // }else 
-    // {
-    //     CPPTP.add_task(&RTPOneRoadThread::threadTask, pRtpSendThread);
-    //     std::lock_guard<std::mutex> lock(m_mutexRtpSendThreads);
-    //     m_rtpSendThreads.push_back(pRtpSendThread);
-    // }
+    RTPOneRoadThread* pRtpSendThread = new RTPOneRoadThread(threadInfo);
+    if(pRtpSendThread == nullptr) 
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "{}:{} 创建发送RTP数据线程失败", roadInfo.strSoundCardName.toStdString(), roadInfo.roadInfo.nRoadNum);
+    }else 
+    {
+        CPPTP.add_task(&RTPOneRoadThread::threadTask, pRtpSendThread);
+        std::lock_guard<std::mutex> lock(m_mutexRtpSendThreads);
+        m_rtpSendThreads.push_back(pRtpSendThread);
+    }
 
     /* 创建录音线程 */
     threadInfo.threadType = EThreadType::Type_RecordSrc;
@@ -600,6 +600,21 @@ RTPOneRoadThread* ThreadManager::getRtpSendThread(int cardID, int recordID)
     return nullptr;
 }
 
+/* 获取录制报警文件的线程 */
+CreateLongFileThread* ThreadManager::getCreateLongFileThread(int cardID, int recordID)
+{
+    std::lock_guard<std::mutex> lock(m_mutexCreateLongWAVThreads);
+    for(auto& pThread : m_createLongWAVThreads)
+    {
+        if(pThread->getThreadInfo().cardRoadInfo.nSoundCardNum == cardID &&
+           pThread->getThreadInfo().cardRoadInfo.roadInfo.nRoadNum == recordID)
+        {
+            return dynamic_cast<CreateLongFileThread*>(pThread);
+        }
+    }
+    return nullptr;
+}
+
 
 /* -------------------------------------------------------------------------------------------
  * 获取计算线程,如果该线程不存在则创建该线程

+ 5 - 1
Server/ThreadManager/ThreadManager.h

@@ -3,7 +3,7 @@
 
 #include "spdlog/spdlog.h"
 #include "BaseRecordThread.h"
-#include "CreateDBThread.h"
+// #include "CreateDBThread.h"
 #include "GlobalVariable.h"
 #include "AudioData.h"
 #include "RingQueue.hpp"
@@ -16,6 +16,8 @@ class CreateWAVThread;
 class ConsistencyCompareThread;
 class NoiseDetectThread;
 class RTPOneRoadThread;
+class CreateLongFileThread;
+class CreateDBThread;
 
 
 #define ThreadMan ThreadManager::getInstance()
@@ -74,6 +76,8 @@ public:
     CreateDBThread* getCreateDBThread(int cardID, int recordID);
     /* 获取发送Rtp数据的线程 */
     RTPOneRoadThread* getRtpSendThread(int cardID, int recordID);
+    /* 获取录制报警文件的线程 */
+    CreateLongFileThread* getCreateLongFileThread(int cardID, int recordID);
 
     /* -------------------------------------------------------------------------------------------
      * 获取计算线程,如果该线程不存在则创建该线程

+ 295 - 126
Server/ThreadRecord/CreateLongFileThread.cpp

@@ -1,5 +1,6 @@
 #include "CreateLongFileThread.h"
 
+#include "AudioData.h"
 #include "GlobalInfo.h"
 #include "spdlog.h"
 #include <cstring>
@@ -35,7 +36,16 @@ bool CreateLongFileThread::setData(const AudioSrcData& srcData)
         return false;
     }
 
+    /* ------------------------------------------------------------------------------- */
+    /* 先写入记录报警文件的环形缓冲区 */
+    auto oldData = m_ringQueue.push_pop(new AudioSrcData(srcData));
+    if(oldData != nullptr)
+    {
+        delete oldData;
+        oldData = nullptr;
+    }
     
+    /* ------------------------------------------------------------------------------- */
     /* 锁定缓冲区 */
     std::lock_guard<std::mutex> lock(m_mutexBuffer);
     /* 如果缓冲区没有分配内存,先分配 */
@@ -71,11 +81,22 @@ bool CreateLongFileThread::setData(const AudioSrcData& srcData)
 /* 开启录制 */
 bool CreateLongFileThread::startRecordAlarmFile(const AlarmInfo_t& alarmInfo)
 {
+    std::lock_guard<std::mutex> lock(m_mutexBuffer);
+    /* 先检查是否已经在队列中了 */
+    AlarmKey_t key = {alarmInfo.CompareItemID, alarmInfo.RoadInfo.nCompareRoadNum, 
+                        alarmInfo.AlarmType, alarmInfo.StartTime};
+    if(m_mapAlarmFile.find(key) != m_mapAlarmFile.end())
+    {
+        SPDLOG_LOGGER_WARN(m_logger, "{} 已经在报警录制队列中,无法重复添加", m_logBase);
+        return true;
+    }
+    /* 添加一个新的报警文件路径 */
+    QString fileName = generateFileName(alarmInfo.StartTime, alarmInfo.EndTime);
 
     return true;
 }
 
-/* 停止录制 */
+/* 停止录制,alarmInfo既是传入参数,也是传出参数,传出文件路径和开始位置 */
 bool CreateLongFileThread::stopRecordAlarmFile(AlarmInfo_t& alarmInfo)
 {
 
@@ -100,118 +121,18 @@ void CreateLongFileThread::task()
 
     while(m_isRunning)
     {
-        /* 线程休眠1秒 */
-        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
-        
-        /* 判断缓存是否达到1分钟数据临界值 */
-        {
-            std::lock_guard<std::mutex> lock(m_mutexBuffer);
-            if(m_bufferData.dataSize < m_writeCriticalSize)
-            {
-                continue; // 缓存数据不足,继续等待
-            }
-            /* 数据足够了将缓冲区数据拷贝出来 */
-            memcpy(m_srcData.pData, m_bufferData.pData, m_bufferData.dataSize);
-            m_srcData.dataSize = m_bufferData.dataSize;
-            m_srcData.startTime = m_bufferData.startTime;
-            m_srcData.endTime = m_bufferData.endTime;
-            /* 清空缓冲区数据 */
-            m_bufferData.clear();
-        }
-        // SPDLOG_LOGGER_DEBUG(m_logger, "{} 设置数据,dataSize: {}, startTime: {}, endTime: {}",
-        // 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());
+        /* 线程休眠100ms */
+        std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
         /*--------------------------------------------------------------
-         * 打开文件。写入的时候判断是否到达了整点,如果到达了整点,则关闭文件
-         * 重新创建一个新的文件
-         *--------------------------------------------------------------*/
-        bool isNewFile = false;
-        if(m_writtenSize == 0)
-        {
-            /* 如果没有写入过数据,则是新文件 */
-            isNewFile = true;
-            m_writtenStartTime = m_srcData.startTime; // 记录开始时间
-            m_writtenNowTime = m_writtenStartTime; // 记录当前时间
-        }
-        /* 设置今日目录 */
-        if(!setTodayPath(isNewFile))
-        {
-            continue;
-        }
+        * 写入报警文件
+        *--------------------------------------------------------------*/
+
         
-        /* 打开文件 */
-        QFile wavFile;
-        if(!openFile(wavFile, isNewFile))
-        {
-            if(m_openFileErrorSize >= 3)
-            {
-                SPDLOG_LOGGER_ERROR(m_logger, "{} 打开文件失败次数过多,重新开始记录", m_logBase);
-                m_writtenSize = 0;
-                m_writtenStartTime = QDateTime::currentDateTime(); // 重新开始时间
-                m_writtenNowTime = m_writtenStartTime; // 重新开始时间
-                m_wavFileName.clear(); // 清空文件名
-                m_srcData.clear(); // 清空缓冲区数据
-                m_openFileErrorSize = 0; // 重置错误次数
-                continue; // 重新开始记录
-            }
-        }
-        /*--------------------------------------------------------------
-         * 将数据写入文件,并记录其携带的时间和写入的数据大小
-         *--------------------------------------------------------------*/
-        int64_t wSize = 0;
-        {
-            std::lock_guard<std::mutex> lock(m_mutexBuffer);
-            wSize = wavFile.write(m_srcData.pData, m_srcData.dataSize);
-            /* 更新结束时间 */
-            m_writtenNowTime = m_srcData.endTime;
-            /* 清空缓冲区 */
-            m_srcData.clear();
-        }
-        if(wSize < 0)
-        {
-            SPDLOG_LOGGER_ERROR(m_logger, "{} 写入WAV文件失败: {}", m_logBase, wavFile.errorString().toStdString());
-            SPDLOG_LOGGER_WARN(m_logger, "文件路径:{}", m_wavFileName.toStdString());
-            wavFile.close();
-            continue;
-        } else {
-            SPDLOG_LOGGER_TRACE(m_logger, "{} 写入WAV文件成功: {}, 大小: {} 字节", m_logBase, m_wavFileName.toStdString(), wSize);
-        }
-        wavFile.close();
-        // SPDLOG_LOGGER_DEBUG(m_logger, "{} 写入WAV文件完成: {}, 大小: {} 字节", 
-        //     m_logBase, m_wavFileName.toStdString(), wSize);
-    
         /*--------------------------------------------------------------
-         * 对该文件进行其他操作,判断是否已经过了一个整点,修改其文件名称
-         * 现在这里的时间是这一分钟的开始时间,现在需要根据开始时间求出已写入
-         * 数据大小对应的结束时间
-         *--------------------------------------------------------------*/
-        m_writtenSize += wSize;
-        
-        /* 修改文件名称 */
-        QString newFileName = generateFileName(m_writtenStartTime, m_writtenNowTime);
-        if(modifyFileName(m_wavFileName, newFileName))
-        {
-            m_wavFileName = newFileName;
-        }
-        
-        /* 判断是否过了整点 */
-        if(isOneHourPassed())
-        {
-            /* 修改文件头中记录的数据大小 */
-            m_wavHeader.setDataSize(m_writtenSize);
-            m_wavHeader.calculateDerivedFields();
-            modifyWavFileHeader(m_wavFileName, m_wavHeader);
-
-            SPDLOG_LOGGER_INFO(m_logger, "{} 结束记录一个文件: {}, 已写入大小: {} 字节", 
-                m_logBase, m_wavFileName.toStdString(), m_writtenSize);
-
-            /* 重置已写入大小 */
-            m_writtenSize = 0;
-            m_writtenStartTime = QDateTime();       // 重新开始时间
-            m_writtenNowTime = m_writtenStartTime;  // 重新开始时间
-            m_wavFileName.clear();                  // 清空文件名
-            m_openFileErrorSize = 0;                // 重置错误次数
-        }
+        * 写入长记录文件
+        *--------------------------------------------------------------*/
+        writeLongRecordFile();
         
     }
     SPDLOG_LOGGER_WARN(m_logger, "➢ {} 记录长文件线程结束运行", m_logBase);
@@ -239,8 +160,9 @@ bool CreateLongFileThread::initData()
     /* 给缓存分配空间 */
     m_bufferData.allocateMemory(m_writeCriticalSize * 3);
     m_srcData.allocateMemory(m_writeCriticalSize * 3);
-    /* 获取记录文件的位置 */
-    m_recordPath = GInfo.longWavPath();
+
+    /* 设置环形队列大小 */
+    m_ringQueue.setQueueCapacity(GInfo.queueElementCount());
 
     return true;
 }
@@ -252,29 +174,166 @@ void CreateLongFileThread::clearData()
     m_bufferData.clear();
 }
 
+/* 写入长记录文件 */
+bool CreateLongFileThread::writeLongRecordFile()
+{
+    /* 判断缓存是否达到1分钟数据临界值 */
+    {
+        std::lock_guard<std::mutex> lock(m_mutexBuffer);
+        if(m_bufferData.dataSize < m_writeCriticalSize)
+        {
+            return true; // 缓存数据不足,继续等待
+        }
+        /* 数据足够了将缓冲区数据拷贝出来 */
+        memcpy(m_srcData.pData, m_bufferData.pData, m_bufferData.dataSize);
+        m_srcData.dataSize = m_bufferData.dataSize;
+        m_srcData.startTime = m_bufferData.startTime;
+        m_srcData.endTime = m_bufferData.endTime;
+        /* 清空缓冲区数据 */
+        m_bufferData.clear();
+    }
+    // SPDLOG_LOGGER_DEBUG(m_logger, "{} 设置数据,dataSize: {}, startTime: {}, endTime: {}",
+    // 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());
+    /*--------------------------------------------------------------
+     * 打开文件。写入的时候判断是否到达了整点,如果到达了整点,则关闭文件
+     * 重新创建一个新的文件
+     *--------------------------------------------------------------*/
+    bool isNewFile = false;
+    if(m_writtenSize == 0)
+    {
+        /* 如果没有写入过数据,则是新文件 */
+        isNewFile = true;
+        m_writtenStartTime = m_srcData.startTime; // 记录开始时间
+        m_writtenNowTime = m_writtenStartTime; // 记录当前时间
+    }
+    /* 设置今日目录 */
+    if(!setTodayPath(isNewFile))
+    {
+        return false;
+    }
+    
+    /* 打开文件 */
+    QFile wavFile;
+    if(!openFile(wavFile, isNewFile))
+    {
+        if(m_openFileErrorSize >= 3)
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "{} 打开文件失败次数过多,重新开始记录", m_logBase);
+            m_writtenSize = 0;
+            m_writtenStartTime = QDateTime::currentDateTime(); // 重新开始时间
+            m_writtenNowTime = m_writtenStartTime; // 重新开始时间
+            m_wavFileName.clear(); // 清空文件名
+            m_srcData.clear(); // 清空缓冲区数据
+            m_openFileErrorSize = 0; // 重置错误次数
+            return false; // 重新开始记录
+        }
+    }
+    /*--------------------------------------------------------------
+     * 将数据写入文件,并记录其携带的时间和写入的数据大小
+     *--------------------------------------------------------------*/
+    int64_t wSize = 0;
+    {
+        std::lock_guard<std::mutex> lock(m_mutexBuffer);
+        wSize = wavFile.write(m_srcData.pData, m_srcData.dataSize);
+        /* 更新结束时间 */
+        m_writtenNowTime = m_srcData.endTime;
+        /* 清空缓冲区 */
+        m_srcData.clear();
+    }
+    if(wSize < 0)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "{} 写入WAV文件失败: {}", m_logBase, wavFile.errorString().toStdString());
+        SPDLOG_LOGGER_WARN(m_logger, "文件路径:{}", m_wavFileName.toStdString());
+        wavFile.close();
+        return false;
+    } else {
+        SPDLOG_LOGGER_TRACE(m_logger, "{} 写入WAV文件成功: {}, 大小: {} 字节", m_logBase, m_wavFileName.toStdString(), wSize);
+    }
+    wavFile.close();
+    // SPDLOG_LOGGER_DEBUG(m_logger, "{} 写入WAV文件完成: {}, 大小: {} 字节", 
+    //     m_logBase, m_wavFileName.toStdString(), wSize);
+
+    /*--------------------------------------------------------------
+     * 对该文件进行其他操作,判断是否已经过了一个整点,修改其文件名称
+     * 现在这里的时间是这一分钟的开始时间,现在需要根据开始时间求出已写入
+     * 数据大小对应的结束时间
+     *--------------------------------------------------------------*/
+    m_writtenSize += wSize;
+    
+    /* 修改文件名称 */
+    QString newFileName = generateFileName(m_writtenStartTime, m_writtenNowTime);
+    if(modifyFileName(m_wavFileName, newFileName))
+    {
+        m_wavFileName = newFileName;
+    }
+    
+    /* 判断是否过了整点 */
+    if(isOneHourPassed())
+    {
+        /* 修改文件头中记录的数据大小 */
+        m_wavHeader.setDataSize(m_writtenSize);
+        m_wavHeader.calculateDerivedFields();
+        modifyWavFileHeader(m_wavFileName, m_wavHeader);
+        SPDLOG_LOGGER_INFO(m_logger, "{} 结束记录一个文件: {}, 已写入大小: {} 字节", 
+            m_logBase, m_wavFileName.toStdString(), m_writtenSize);
+        /* 重置已写入大小 */
+        m_writtenSize = 0;
+        m_writtenStartTime = QDateTime();       // 重新开始时间
+        m_writtenNowTime = m_writtenStartTime;  // 重新开始时间
+        m_wavFileName.clear();                  // 清空文件名
+        m_openFileErrorSize = 0;                // 重置错误次数
+    }
+
+    return true;
+}
+
 /* 设置今日目录 */
 bool CreateLongFileThread::setTodayPath(bool isNewFile)
 {
-    if(isNewFile)
+    if(!isNewFile)
     {
-        QString todayDirName = QString("%1/%2/Record_%3-%4")
-            .arg(m_recordPath)
-            .arg(QDate::currentDate().toString("yyyy-MM-dd"))
-            .arg(m_threadInfo.cardRoadInfo.strSoundCardID)
-            .arg(QString::number(m_threadInfo.cardRoadInfo.roadInfo.nRoadNum));
-        m_todayDir.setPath(todayDirName);
-        if(!m_todayDir.exists())
+        return true;
+    }
+
+    /* 判断现在日期是否还是当天日期 */
+    QDate today = QDate::currentDate();
+    if(m_todayDateRecord == today)
+    {
+        return true;
+    }
+    m_todayDateRecord = today;
+    /* 先检查现在的日期文件夹是否存在,因为其他线程可能已经创建了 */
+    QString todayDirName = QString("%1/%2").arg(GInfo.longWavPath()).arg(today.toString("yyyy-MM-dd"));
+    m_todayDir.setPath(todayDirName);
+    if(!m_todayDir.exists())
+    {
+        if(!m_todayDir.mkpath(todayDirName))
         {
-            if(!m_todayDir.mkpath(todayDirName))
-            {
-                SPDLOG_LOGGER_ERROR(m_logger, "{} 创建目录失败: {}", m_logBase, todayDirName.toStdString());
-            } else {
-                SPDLOG_LOGGER_INFO(m_logger, "{} 创建目录成功: {}", m_logBase, todayDirName.toStdString());
-            }
+            SPDLOG_LOGGER_ERROR(m_logger, "{} 创建今日目录失败: {}", m_logBase, todayDirName.toStdString());
+            return false; // 创建目录失败
+        } else {
+            SPDLOG_LOGGER_INFO(m_logger, "{} 创建今日目录成功: {}", m_logBase, todayDirName.toStdString());
         }
     }
 
-    return m_todayDir.exists();
+    /* 创建这个通道的文件夹,文件夹格式: AudioPCI-0 */
+    QString roadDirName = QString("%1/%2-%3")
+        .arg(todayDirName)
+        .arg(m_threadInfo.cardRoadInfo.strSoundCardID)
+        .arg(QString::number(m_threadInfo.cardRoadInfo.roadInfo.nRoadNum));
+    m_todayDir.setPath(roadDirName);
+    if(!m_todayDir.exists())
+    {
+        if(!m_todayDir.mkpath(todayDirName))
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "{} 创建目录失败: {}", m_logBase, roadDirName.toStdString());
+            return false;
+        } else {
+            SPDLOG_LOGGER_INFO(m_logger, "{} 创建目录成功: {}", m_logBase, roadDirName.toStdString());
+        }
+    }
+    
+    return true;
 }
 
 /* 打开文件 */
@@ -339,6 +398,7 @@ QString CreateLongFileThread::generateFileName(const QDateTime& startTime, const
     return m_todayDir.filePath(fileName);
 }
 
+
 /* 判断是否过了整点 */
 bool CreateLongFileThread::isOneHourPassed()
 {
@@ -363,3 +423,112 @@ bool CreateLongFileThread::isOneHourPassed()
     return isPassed;
 }
 
+
+/* 生成报警文件名 */
+QString CreateLongFileThread::generateAlarmFileName(const AlarmInfo_t& alarmInfo, bool isNewFile)
+{
+    QString retFileName;
+    if(isNewFile)
+    {
+        /* 先检查是否已经过了一天了,设置日期文件夹 */
+        setTodayAlarmPath();
+
+        /* 检查这个对比项的报警文件夹是否存在 */
+        QString itemDirName = QString("CompareItemID_%1").arg(QString::number(alarmInfo.CompareItemID));
+        QDir itemDir = m_todayDirAlarm;
+        itemDir.cd(itemDirName);
+        if(!itemDir.exists())
+        {
+            if(!itemDir.mkpath(itemDirName))
+            {
+                SPDLOG_LOGGER_ERROR(m_logger, "{} 创建报警文件夹失败: {}", m_logBase, itemDirName.toStdString());
+                return QString(); // 创建目录失败
+            } else {
+                SPDLOG_LOGGER_INFO(m_logger, "{} 创建报警文件夹成功: {}", m_logBase, itemDirName.toStdString());
+            }
+        }
+        /* 生成文件名, 格式: Alarm_RoadNum_AlarmType_yyyyMMdd_hhmmss-yyyyMMdd_hhmmss.wav
+           这里创建的录音文件只有开始日期,没有结束日期,等报警结束之后才会有结束日期 */
+        QString fileName = QString("Alarm_%1_%2_%3-.wav")
+            .arg(QString::number(alarmInfo.RoadInfo.nCompareRoadNum))
+            .arg(getAlarmTypeString(alarmInfo.AlarmType))
+            .arg(alarmInfo.StartTime.toString("yyyyMMdd_hhmmss"));
+        
+        /* 拼接文件夹路径 */
+        retFileName = itemDir.filePath(fileName);
+    }else 
+    {
+        /* 已有的文件,是报警结束的文件名 */
+        retFileName = QString::fromStdString(alarmInfo.strAlarmFilePath);
+        /* 这里的文件名格式是:Alarm_CompareItemID_RoadNum_AlarmType_yyyyMMdd_hhmmss-yyyyMMdd_hhmmss.wav,
+           这里带上结束时间 */
+        QString endTimeStr = alarmInfo.EndTime.toString("yyyyMMdd_hhmmss");
+        /* 替换掉原来的结束时间 */
+        retFileName.replace("-.wav", QString("-%1.wav").arg(endTimeStr));    
+    }
+
+    return retFileName;
+}
+
+
+/* 写入报警文件 */
+void CreateLongFileThread::writeAlarmFile()
+{
+    /* 先判断环形队列中数据是否足够的秒数,不一定是每一秒都会写的 */
+}
+
+
+/* 设置今日报警文件夹 */
+bool CreateLongFileThread::setTodayAlarmPath()
+{
+    /* 先检查当天日期文件夹是否存在,因为其他线程可能已经创建了 */
+    QDate today = QDate::currentDate();
+    if(today == m_todayDateAlarm)
+    {
+        return true; // 今天的目录已经存在
+    }
+    m_todayDateAlarm = today;
+    /* 创建今日报警目录 */
+    /* 格式: Application/2025-07-21 */
+    QString todayDirName = QString("%1/%2").arg(GInfo.alarmWavPath()).arg(today.toString("yyyy-MM-dd"));
+    m_todayDirAlarm.setPath(todayDirName);
+    if(!m_todayDirAlarm.exists())
+    {
+        if(!m_todayDirAlarm.mkpath(todayDirName))
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "{} 创建今日报警目录失败: {}", m_logBase, todayDirName.toStdString());
+            return false; // 创建目录失败
+        } else {
+            SPDLOG_LOGGER_INFO(m_logger, "{} 创建今日报警目录成功: {}", m_logBase, todayDirName.toStdString());
+        }
+    }
+
+    /* 设置目录 */
+    m_todayDirAlarm.setPath(todayDirName);
+    QString yesterdayDirName = QString("%1/%2").arg(GInfo.alarmWavPath()).arg(QDate::currentDate().addDays(-1).toString("yyyy-MM-dd"));
+    m_yesterdayDir.setPath(yesterdayDirName);
+
+    return true;
+}
+
+/* 根据报警类型的枚举获取字符 */
+QString CreateLongFileThread::getAlarmTypeString(EAlarmType type) const
+{
+    switch(type)
+    {
+        case EAlarmType::EAT_Silent:
+            return "Silent";
+        case EAlarmType::EAT_Overload:
+            return "Overload";
+        case EAlarmType::EAT_Reversed:
+            return "Reversed";
+        case EAlarmType::EAR_Consistency:
+            return "Consistency";
+        case EAlarmType::EAT_Noise:
+            return "Noise";
+        default:
+            return "Unknown";
+    }
+}
+
+

+ 95 - 4
Server/ThreadRecord/CreateLongFileThread.h

@@ -4,6 +4,7 @@
 #include "BaseRecordThread.h"
 #include "AudioData.h"
 #include "GlobalVariable.h"
+#include "RingQueue.hpp"
 
 #include <mutex>
 #include <QFile>
@@ -11,6 +12,68 @@
 #include <qt5/QtCore/qchar.h>
 
 
+/**
+ * @brief 录音状态
+ * 
+ */
+enum class eAlarmState
+{
+    eAlarm_Init = 0,        /* 初始化状态 */
+    eAlarm_Recording,       /* 录音状态 */
+    eAlarm_Stopped,         /* 停止状态 */
+    eAlarm_Error,           /* 错误状态 */
+};
+
+/**
+    同一个对比项中多个一致性报警时,主通道的录音可能开始录音时间不同,
+    会有多个录音同时存在
+ */
+struct AlarmKey_t
+{
+    int compareItemID;          /* 对比项ID */
+    int roadNum;                /* 对比通道编号 */
+    EAlarmType alarmType;       /* 报警类型 */
+    QDateTime startTime;        /* 报警开始时间 */
+
+    AlarmKey_t(int id, int num, EAlarmType type, const QDateTime& time)
+        : compareItemID(id), roadNum(num), alarmType(type), startTime(time) {}
+    
+    bool operator<(const AlarmKey_t& other) const
+    {
+        if(compareItemID != other.compareItemID) {
+            return compareItemID < other.compareItemID;
+        }
+        if(roadNum != other.roadNum) {
+            return roadNum < other.roadNum;
+        }
+        if(alarmType != other.alarmType) {
+            return alarmType < other.alarmType;
+        }
+
+        return startTime < other.startTime;
+    }
+};
+
+
+
+
+/**
+    报警文件队列的值
+
+ */
+struct AlarmValue_t
+{
+    QString fileName;          /* 报警文件名 */
+    eAlarmState state;         /* 录音状态 */
+    QDateTime startTime;       /* 录音开始时间 */
+    QDateTime endTime;         /* 录音结束时间 */
+
+    AlarmValue_t(const QString& name, eAlarmState s, const QDateTime& start, const QDateTime& end)
+        : fileName(name), state(s), startTime(start), endTime(end) {}
+};
+
+
+
 /**
     这个线程类记录一个长的录音文件,1小时一个文件
     功能1:记录一个长的录音文件,1小时一个文件
@@ -24,6 +87,12 @@
            根据对比项ID和对比项通道以及报警类型来区分
         4、报警文件的命名规则:Alarm_CompareItemID_RoadNum_AlarmType_yyyyMMdd_hhmmss-yyyyMMdd_hhmmss.wav
            例如:Alarm_1_1_Silent_20250101_120000-20250101_120100.wav
+    
+    文件夹路径格式:
+        1、长录音文件夹: Application/ACAServerData/Record/yyyy-MM-dd/SoundCardID-RoadNum/Record_yyyy-MM-dd-hh-mm-ss-yyyy-MM-dd-hh-mm-ss.wav
+              例如:Application/2025-01-01/SoundCard1-1/Record_2025-01-01-12-00-00-2025-01-01-12-01-00.wav
+        2、报警录音文件夹:Application/ACAServerData/AlarmWav/yyyy-MM-dd/CompareItemName/Alarm_CompareItemID_RoadNum_AlarmType_yyyyMMdd_hhmmss-yyyyMMdd_hhmmss.wav
+              例如:Application/2025-01-01/1-1/Alarm_1_1_Silent_20250101_120000-20250101_120100.wav
 
  */
 class CreateLongFileThread : public BaseRecordThread
@@ -49,6 +118,9 @@ private:
     /* 清理数据 */
     void clearData() override;
 
+    /*===============================================================================*/
+    /* 写入长记录文件 */
+    bool writeLongRecordFile();
     /* 设置今日目录 */
     inline bool setTodayPath(bool isNewFile);
     /* 打开文件 */
@@ -60,6 +132,17 @@ private:
     /* 判断是否过了整点 */
     inline bool isOneHourPassed();
 
+    /*===============================================================================*/
+    /* 写入报警文件 */
+    void writeAlarmFile();
+    /* 生成报警文件名 */
+    inline QString generateAlarmFileName(const AlarmInfo_t& alarmInfo, bool isNewFile);
+    /* 设置今日报警文件夹 */
+    bool setTodayAlarmPath();
+    /* 根据报警类型的枚举获取字符 */
+    QString getAlarmTypeString(EAlarmType type) const;
+    
+
 private:
     /* 临时缓存数据, 一分钟写入一次,给这个分配2分钟的数据大小 */
     std::mutex m_mutexBuffer;
@@ -70,10 +153,11 @@ private:
     int32_t m_writeCriticalSize = 0;  /* 写入文件的临界大小,单位:字节,缓存超过这个大小就写入文件 */
     int32_t m_oneHourSize = 0;       /* 一小时的音频数据大小 */
 
-    int m_openFileErrorSize = 0;    /* 打开文件错误次数 */
-    QString m_recordPath;           /* 记录长文件的路径 */
+
     QDir m_todayDir;                /* 今日目录 */
+    QDate m_todayDateRecord;        /* 今日日期,记录长文件用 */
     QString m_wavFileName;          /* wav文件对象 */
+    int m_openFileErrorSize = 0;    /* 打开文件错误次数 */
     WavHeader m_wavHeader;          /* 当前wav文件头信息 */
     int64_t m_writtenSize = 0;      /* 已经写入的数据大小 */
     QDateTime m_writtenStartTime;   /* 已经写入数据的开始时间点 */
@@ -81,8 +165,15 @@ private:
 
 
     /*===============================================================================*/
-    /* 报警文件相关 */
-    std::map<AlarmInfo_t, bool> m_mapAlarmFileName; /* 报警文件名,key是报警信息,value是文件名 */
+    /* 报警文件名,key是报警信息,value是文件信息 */
+    std::map<AlarmKey_t, AlarmValue_t> m_mapAlarmFile;
+
+    QDir m_yesterdayDir;                    /* 昨日目录,用来给还未录制完成的报警文件使用的 */
+    QDir m_todayDirAlarm;                   /* 今日报警目录,这个目录只到日期,里面的子文件夹是对比项相关的 */
+    QDate m_todayDateAlarm;                 /* 今日日期,记录报警文件用 */
+
+    RingQueue<AudioSrcData*> m_ringQueue;   /* 环形队列,存储几分钟的数据,用来写入报警文件 */
+    QDateTime m_alarmWrittenTime;       /* 报警文件中环形队列已写入文件的时间 */
 };
 
 

+ 2 - 0
Server/ThreadRecord/CreateWAVThread.cpp

@@ -419,6 +419,8 @@ bool CreateWAVThread::splitLeftRightChannel()
             {
                 pLeftRightData->vecRightData.push_back(sampleDouble);
             }
+            // fmt::print(" |{} {}, short: {}, double: {:.2f}", static_cast<uint8_t>(*(data->pData + j)), static_cast<uint8_t>(*(data->pData + 1001)), sample, sampleDouble);
+            
         }
         pLeftRightData->numMSecond += 1000; // 每次处理1秒的数据,增加1000毫秒
 

+ 1 - 1
Server/main.cpp

@@ -7,7 +7,7 @@
 #include "ThreadPool.h"
 
 #include "LHCompareAPI.h"
-#include "signalstats_wrapper.h"
+#include "signalstats.h"
 #include "ACAServer.h"
 
 #include <QDir>

+ 1 - 1
ThreeLib/demo/noiseTest.cpp

@@ -29,7 +29,7 @@ int main() {
         nlohmann::json output;
         std::vector<std::string> window_params = {"tukey", "0.25"};
         
-        nlohmann::json& result = signalstats_wrapper::detect_signal_wrapper(
+        nlohmann::json& result = signalstats::detect_signal(
             audio_signal,
             sample_rate,
             3e-3,  // silence_threshold

BIN
ThreeLib/signalstats-uos-v1.tar.gz


+ 64 - 0
ThreeLib/signalstats/include/signalstats.h

@@ -0,0 +1,64 @@
+#ifndef SIGNALSTATS_H
+#define SIGNALSTATS_H
+
+#include <nlohmann/json.hpp>
+
+// 定义导出宏
+#ifdef _WIN32
+#ifdef BUILDING_DLL
+#define EXPORT_API __declspec(dllexport)
+#else
+#define EXPORT_API __declspec(dllimport)
+#endif
+#else
+#define EXPORT_API __attribute__((visibility("default")))
+#endif
+
+namespace signalstats
+{
+    /**
+     * @brief 初始化
+     * 必须在使用前调用此函数。
+     *
+     * @param debug 是否输出调试信息
+     */
+    EXPORT_API void initialize(bool debug=false);
+
+    /**
+     * @brief 释放资源
+     *
+     * 应在程序结束时调用此函数。
+     */
+    EXPORT_API void finalize();
+
+    /**
+     * @brief 信号检测
+     *
+     * @param output 输出结果容器
+     * @param audio_signal 音频信号数据(vector)
+     * @param audio_samplerate 采样率(Hz)
+     * @param silence_threshold 静音检测阈值
+     * @param db_threshold 分贝阈值
+     * @param cv_threshold 变异系数阈值
+     * @param window_params 窗函数参数
+     * @param nperseg 每段样本数
+     * @param noverlap 重叠样本数
+     * @param nfft FFT点数
+     * @param debug 是否输出调试信息
+     * @return nlohmann::json& 输出结果容器
+     */
+    EXPORT_API nlohmann::json& detect_signal(
+        nlohmann::json &output,
+        const std::vector<double> &audio_signal,
+        double audio_samplerate,
+        double silence_threshold = 3e-3,
+        double db_threshold = -70.0,
+        double cv_threshold = -70.0,
+        const std::vector<std::string> &window_params = {"tukey", "0.25"},
+        int nperseg = 256,
+        int noverlap = 32,
+        int nfft = 256,
+        bool debug = false);
+}
+
+#endif // SIGNALSTATS_H

+ 0 - 0
ThreeLib/signalstats/include/signalstats_wrapper.h → ThreeLib/signalstats/include/signalstats_wrapper.h_


+ 0 - 1
ThreeLib/signalstats/lib/libffi.7.so

@@ -1 +0,0 @@
-libffi.so.8.1.2

+ 0 - 1
ThreeLib/signalstats/lib/libffi.8.so

@@ -1 +0,0 @@
-libffi.so.8.1.2

+ 0 - 1
ThreeLib/signalstats/lib/libffi.so

@@ -1 +0,0 @@
-libffi.so.8.1.2

+ 0 - 1
ThreeLib/signalstats/lib/libffi.so.7

@@ -1 +0,0 @@
-libffi.so.8.1.2

+ 0 - 1
ThreeLib/signalstats/lib/libffi.so.8

@@ -1 +0,0 @@
-libffi.so.8.1.2

BIN
ThreeLib/signalstats/lib/libffi.so.8.1.2


+ 0 - 1
ThreeLib/signalstats/lib/libpython3.12.so

@@ -1 +0,0 @@
-libpython3.12.so.1.0

BIN
ThreeLib/signalstats/lib/libpython3.12.so.1.0


BIN
ThreeLib/signalstats/lib/libpython3.so


BIN
ThreeLib/signalstats/lib/libsignalstats.so


BIN
ThreeLib/signalstats/lib/libsignalstats.so.1


BIN
ThreeLib/signalstats/lib/libsignalstats.so.1.0


BIN
ThreeLib/signalstats/lib/python3.12/__future__.pyc


BIN
ThreeLib/signalstats/lib/python3.12/_compat_pickle.pyc


BIN
ThreeLib/signalstats/lib/python3.12/_compression.pyc


BIN
ThreeLib/signalstats/lib/python3.12/_sysconfigdata__linux_x86_64-linux-gnu.pyc


BIN
ThreeLib/signalstats/lib/python3.12/_weakrefset.pyc


BIN
ThreeLib/signalstats/lib/python3.12/argparse.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ast.pyc


BIN
ThreeLib/signalstats/lib/python3.12/base64.pyc


BIN
ThreeLib/signalstats/lib/python3.12/bisect.pyc


BIN
ThreeLib/signalstats/lib/python3.12/calendar.pyc


BIN
ThreeLib/signalstats/lib/python3.12/collections/__init__.pyc


BIN
ThreeLib/signalstats/lib/python3.12/collections/abc.pyc


BIN
ThreeLib/signalstats/lib/python3.12/concurrent/__init__.pyc


BIN
ThreeLib/signalstats/lib/python3.12/concurrent/futures/__init__.pyc


BIN
ThreeLib/signalstats/lib/python3.12/concurrent/futures/_base.pyc


BIN
ThreeLib/signalstats/lib/python3.12/concurrent/futures/process.pyc


BIN
ThreeLib/signalstats/lib/python3.12/concurrent/futures/thread.pyc


BIN
ThreeLib/signalstats/lib/python3.12/contextlib.pyc


BIN
ThreeLib/signalstats/lib/python3.12/contextvars.pyc


BIN
ThreeLib/signalstats/lib/python3.12/copy.pyc


BIN
ThreeLib/signalstats/lib/python3.12/copyreg.pyc


BIN
ThreeLib/signalstats/lib/python3.12/csv.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ctypes/__init__.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ctypes/_aix.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ctypes/_endian.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ctypes/macholib/__init__.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ctypes/macholib/dyld.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ctypes/macholib/dylib.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ctypes/macholib/framework.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ctypes/util.pyc


BIN
ThreeLib/signalstats/lib/python3.12/ctypes/wintypes.pyc


BIN
ThreeLib/signalstats/lib/python3.12/dataclasses.pyc


BIN
ThreeLib/signalstats/lib/python3.12/datetime.pyc


BIN
ThreeLib/signalstats/lib/python3.12/decimal.pyc


BIN
ThreeLib/signalstats/lib/python3.12/difflib.pyc


BIN
ThreeLib/signalstats/lib/python3.12/dis.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/__init__.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/_encoded_words.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/_header_value_parser.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/_parseaddr.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/_policybase.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/base64mime.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/charset.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/contentmanager.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/encoders.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/errors.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/feedparser.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/generator.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/header.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/headerregistry.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/iterators.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/message.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/mime/__init__.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/mime/application.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/mime/audio.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/mime/base.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/mime/image.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/mime/message.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/mime/multipart.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/mime/nonmultipart.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/mime/text.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/parser.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/policy.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/quoprimime.pyc


BIN
ThreeLib/signalstats/lib/python3.12/email/utils.pyc


BIN
ThreeLib/signalstats/lib/python3.12/encodings/__init__.pyc


BIN
ThreeLib/signalstats/lib/python3.12/encodings/aliases.pyc


BIN
ThreeLib/signalstats/lib/python3.12/encodings/ascii.pyc


Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff