Browse Source

V0.4.1
1、修复了RTP发送数据的错误

Apple 23 hours ago
parent
commit
1cad26a866
37 changed files with 356 additions and 385 deletions
  1. 33 31
      RTPServer/RtpOneRoadThread.cpp
  2. 2 1
      RTPServer/RtpOneRoadThread.h
  3. 2 0
      Server/CMakeLists.txt
  4. 0 70
      Server/LHLibraryAPI/signalstats_wrapper.h_
  5. 15 2
      Server/ThreadCalculate/CalculateDBThread.cpp
  6. 53 116
      Server/ThreadCalculate/CompareItemThread.cpp
  7. 2 4
      Server/ThreadCalculate/CompareItemThread.h
  8. 1 23
      Server/ThreadCalculate/ConsistencyCompareThread.cpp
  9. 2 4
      Server/ThreadCalculate/NoiseDetectThread.cpp
  10. 12 4
      Server/ThreadManager/ThreadCompareItemManager.cpp
  11. 1 1
      Server/ThreadManager/ThreadCompareItemManager.h
  12. 128 79
      Server/ThreadRecord/AssignSrcDataThread.cpp
  13. 45 14
      Server/ThreadRecord/AssignSrcDataThread.h
  14. 11 1
      Server/ThreadRecord/CreateDBThread.cpp
  15. 2 0
      Server/ThreadRecord/CreateDBThread.h
  16. 14 7
      Server/ThreadRecord/RecordThread.cpp
  17. 1 1
      Server/ThreadRecord/RecordThread.h
  18. 2 1
      Server/main.cpp
  19. BIN
      ThreeLib/signalstats-uos-20250731-01.tar.xz
  20. BIN
      ThreeLib/signalstats-uos-v1.tar.gz
  21. BIN
      ThreeLib/signalstats-v1.0.tar.xz
  22. 9 11
      ThreeLib/signalstats/include/signalstats.h
  23. BIN
      ThreeLib/signalstats/lib/libsignalstats.so
  24. 1 0
      ThreeLib/signalstats/lib/libsignalstats.so
  25. BIN
      ThreeLib/signalstats/lib/libsignalstats.so.1
  26. 1 0
      ThreeLib/signalstats/lib/libsignalstats.so.1
  27. BIN
      ThreeLib/signalstats/lib/libsignalstats.so.1.0
  28. BIN
      ThreeLib/uos-20250731-01/bin/test_demo
  29. BIN
      ThreeLib/uos-20250731-01/bin/test_main
  30. BIN
      ThreeLib/uos-20250731-01/bin/test_mp
  31. 9 11
      ThreeLib/uos-20250731-01/include/signalstats.h
  32. 1 0
      ThreeLib/uos-20250731-01/lib/libsignalstats.so
  33. 1 0
      ThreeLib/uos-20250731-01/lib/libsignalstats.so.1
  34. BIN
      ThreeLib/uos-20250731-01/lib/libsignalstats.so.1.0
  35. 2 0
      ThreeLib/uos-20250731-01/run.sh
  36. 4 0
      show3/CMakeLists.txt
  37. 2 4
      show3/main.cpp

+ 33 - 31
RTPServer/RtpOneRoadThread.cpp

@@ -61,7 +61,12 @@ bool RTPOneRoadThread::setData(const AudioSrcData& srcData)
     {
         return false;
     }
-    m_ringQueue.push(data);
+    if(!m_ringQueue.push_noBlock(data))
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "{} 环形队列已满,无法添加新的音频数据", m_logBase);
+        delete data; // 删除无用数据
+        return false;
+    }
 
     return false;
 }
@@ -88,9 +93,9 @@ bool RTPOneRoadThread::addUdpSession(const RtpSendClientInfo_t& udpSession)
         m_localPort = udpSession.localPort;
     }
     
-    m_lockUdpSockets.lock();
+    m_lockClients.lock();
     m_listClients.append(udpSession);
-    m_lockUdpSockets.unlock();
+    m_lockClients.unlock();
 
     return true;
 }
@@ -98,7 +103,7 @@ bool RTPOneRoadThread::addUdpSession(const RtpSendClientInfo_t& udpSession)
 /* 删除一个会话 */
 bool RTPOneRoadThread::removeUdpSession(QString clientIP, quint16 clientPort)
 {
-    std::lock_guard<std::mutex> lock(m_lockUdpSockets);
+    std::lock_guard<std::mutex> lock(m_lockClients);
     for(auto it = m_listClients.begin(); it != m_listClients.end(); ++it)
     {
         if(it->clientIP == clientIP && it->clientPort == clientPort)
@@ -179,17 +184,15 @@ void RTPOneRoadThread::clearData()
 {
     m_isRecvData.store(false); // 设置为不接收数据状态
     /* 清空UDP会话列表 */
-    std::lock_guard<std::mutex> lock(m_lockUdpSockets);
-    // for(auto& session : m_listClients)
-    // {
-        // if(session.udpSocket != nullptr)
-        // {
-        //     session.udpSocket->close();
-        //     delete session.udpSocket;
-        //     session.udpSocket = nullptr;
-        // }
-    // }
+    std::lock_guard<std::mutex> lock(m_lockClients);
     m_listClients.clear();
+    /* 关闭UDP占用的本地端口 */
+    if(m_udpSocket != nullptr)
+    {
+        m_udpSocket->close();
+        m_udpSocket->deleteLater();
+    }
+    m_udpState = eUDPState::eUDP_None;
     
     /* 清空环形队列 */
     while(m_ringQueue.QueueSize() > 0)
@@ -232,9 +235,9 @@ bool RTPOneRoadThread::processUdpState()
         m_isRecvData.store(true);
         m_udpState = eUDPState::eUDP_Opened;
     }
-    else if(m_udpState == eUDPState::eUDP_Closed)
+    else if(m_udpState == eUDPState::eUDP_Closed || m_udpState == eUDPState::eUDP_Error)
     {
-        /* 关闭接收 */
+        /* 关闭接收数据 */
         m_isRecvData.store(false);
         /* 关闭UDP占用的本地端口 */
         if(m_udpSocket != nullptr)
@@ -248,7 +251,16 @@ bool RTPOneRoadThread::processUdpState()
         m_localPort = -1;
         emit signal_udpClosed(m_threadInfo.cardRoadInfo.nSoundCardNum, 
                               m_threadInfo.cardRoadInfo.roadInfo.nRoadNum, m_localPort);
-    
+        /* 清空环形队列中的数据 */
+        while(m_ringQueue.QueueSize() > 0)
+        {
+            auto data = m_ringQueue.front_pop_noBlock();
+            if(data != nullptr)
+            {
+                delete data;
+                data = nullptr;
+            }
+        }
     }
 
     return true;
@@ -277,15 +289,10 @@ bool RTPOneRoadThread::sendData()
             delete data;
             continue;
         }
-        std::lock_guard<std::mutex> lock(m_lockUdpSockets);
+        std::lock_guard<std::mutex> lock(m_lockClients);
         /* 遍历所有的UDP会话,发送数据 */
         for(const auto& session : m_listClients)
         {
-            // if(session.udpSocket == nullptr || !session.udpSocket->isValid())
-            // {
-            //     SPDLOG_LOGGER_WARN(m_logger, "{} 无效的UDP套接字: {}:{}", m_logBase, session.clientIP.toStdString(), session.clientPort);
-            //     continue;
-            // }
 
             // qint64 bytesSent = session.udpSocket->writeDatagram(data->pData, data->dataSize,
                                                                 // QHostAddress(session.clientIP), session.clientPort);
@@ -336,14 +343,9 @@ void RTPOneRoadThread::do_udpError(QAbstractSocket::SocketError socketError)
     } else
     {
         SPDLOG_LOGGER_ERROR(m_logger, "{} UDP套接字发生错误: {}", m_logBase, static_cast<int>(socketError));
+        SPDLOG_LOGGER_ERROR(m_logger, "{} 错误信息: {}", m_logBase, senderSocket->errorString().toStdString());
     }
-    /* 获取UDP远程连接的IP和端口 */
-    if(senderSocket != nullptr)
-    {
-        QString remoteIP = senderSocket->peerAddress().toString();
-        quint16 remotePort = senderSocket->peerPort();
-        /* 从队列中移除这个会话 */
-        removeUdpSession(remoteIP, remotePort);
-    }
+    
+    m_udpState = eUDPState::eUDP_Error;
 }
 

+ 2 - 1
RTPServer/RtpOneRoadThread.h

@@ -60,6 +60,7 @@ protected:
 
     /* 处理UDP状态 */
     bool processUdpState();
+    /*  */
     /* 发送数据 */
     bool sendData();
 
@@ -81,7 +82,7 @@ private:
     eUDPState m_udpState = eUDPState::eUDP_None;    /* UDP状态 */
     /* UDP会话列表 */
     std::atomic_bool m_isRecvData = false;          /* 是否接收数据的标志 */
-    std::mutex m_lockUdpSockets;                    /* 用于保护UDP套接字列表的读写锁 */
+    std::mutex m_lockClients;                       /* 用于保护客户端列表的锁 */
     QList<RtpSendClientInfo_t> m_listClients;       /* 用于发送数据的客户端信息列表 */
 
     RingQueue<AudioSrcData*> m_ringQueue;           /* 用于存储音频数据的环形队列 */

+ 2 - 0
Server/CMakeLists.txt

@@ -89,6 +89,8 @@ target_include_directories(${this_exe} PRIVATE
     ${CMAKE_SOURCE_DIR}/External/module/mqtt
     ${CMAKE_SOURCE_DIR}/External/module/mqtt_cpp
     ${CMAKE_SOURCE_DIR}/External/module/OneThread
+
+    ${CMAKE_SOURCE_DIR}/ThreeLib/signalstats/include
     
 
     ${spdlog_INCLUDE_DIR}

+ 0 - 70
Server/LHLibraryAPI/signalstats_wrapper.h_

@@ -1,70 +0,0 @@
-#ifndef SIGNALSTATS_WRAPPER_H
-#define SIGNALSTATS_WRAPPER_H
-
-#include <vector>
-#include <string>
-// #include <pybind11/pybind11.h>
-// #include <pybind11/numpy.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 py = pybind11;
-
-namespace signalstats_wrapper
-{
-    /**
-     * @brief 初始化Python解释器
-     *
-     * 初始化嵌入式Python解释器并设置必要的Python路径。
-     * 必须在调用任何Python相关功能前调用此函数。
-     */
-    EXPORT_API void initialize();
-
-    /**
-     * @brief 释放Python解释器
-     *
-     * 释放嵌入式Python解释器资源。
-     * 应在程序结束时调用此函数。
-     */
-    EXPORT_API void finalize();
-
-    /**
-     * @brief C++接口封装函数
-     *
-     * @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 是否输出调试信息
-     */
-    EXPORT_API nlohmann::json& detect_signal_wrapper(
-        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_WRAPPER_H

+ 15 - 2
Server/ThreadCalculate/CalculateDBThread.cpp

@@ -49,8 +49,20 @@ bool CalculateDBThread::getlastVolumeInfo(OneRoadVolume_t& volumeInfo)
     volumeInfo.isSilence = m_roadVolumeInfo.isSilence;
     volumeInfo.isOverload = m_roadVolumeInfo.isOverload;
     volumeInfo.isReversed = m_roadVolumeInfo.isReversed;
-    memcpy(volumeInfo.vecleftDB, m_roadVolumeInfo.vecleftDB, VOLUME_INFO_NUM);
-    memcpy(volumeInfo.vecrightDB, m_roadVolumeInfo.vecrightDB, VOLUME_INFO_NUM);
+    memcpy(volumeInfo.vecleftDB, m_roadVolumeInfo.vecleftDB, VOLUME_INFO_NUM * sizeof(volumeInfo.vecleftDB[0]));
+    memcpy(volumeInfo.vecrightDB, m_roadVolumeInfo.vecrightDB, VOLUME_INFO_NUM * sizeof(volumeInfo.vecleftDB[0]));
+
+    // const OneRoadVolume_t& volume = m_roadVolumeInfo;
+    //     for(int i = 0; i < VOLUME_INFO_NUM; ++i)
+    //     {
+    //         fmt::print("LDB:{}, RDB:{}\n", volume.vecleftDB[i], volume.vecrightDB[i]);
+    //     }
+
+    // const OneRoadVolume_t& volume1 = volumeInfo;
+    //     for(int i = 0; i < VOLUME_INFO_NUM; ++i)
+    //     {
+    //         fmt::print("LDB1:{}, RDB1:{}\n", volume1.vecleftDB[i], volume1.vecrightDB[i]);
+    //     }
 
     /* 更新时间 */
     volumeInfo.dateTime = m_roadVolumeInfo.dateTime;
@@ -233,6 +245,7 @@ void CalculateDBThread::calcuDBData()
     {
         m_roadVolumeInfo.vecleftDB[i] = m_currSecondData.aryLeftDB[i];
         m_roadVolumeInfo.vecrightDB[i] = m_currSecondData.aryRightDB[i];
+        // fmt::print("LDB:{}, RDB:{}\n", m_roadVolumeInfo.vecleftDB[i], m_roadVolumeInfo.vecrightDB[i]);
     }
 
     /* 更新时间信息 */

+ 53 - 116
Server/ThreadCalculate/CompareItemThread.cpp

@@ -110,7 +110,7 @@ void CompareItemThread::stopThreadBlock()
 void CompareItemThread::setDetectPeriod(const DetectPeriodConfig_t& detectPeriod)
 {
     std::lock_guard<std::mutex> lock(m_mutexDetectPeriod);
-    if(detectPeriod.nID != m_detectPeriod.nID)
+    if(detectPeriod.nID != m_threadInfo.compareItemInfo.nID)
     {
         SPDLOG_LOGGER_ERROR(m_logger, "{} 设置检测时段失败,ID不匹配: {}, 当前ID: {}", m_logBase, detectPeriod.nID, m_detectPeriod.nID);
         return;
@@ -200,13 +200,8 @@ void CompareItemThread::timerTask()
         SPDLOG_LOGGER_INFO(m_logger, "{} 更新对比项信息完成,继续检测对比");
     }
 
-    /* 判断检测时段 */
-    if(!checkDetectPeriod())
-    {
-        // 不在检测时段内,不进行对比检测
-        // SPDLOG_LOGGER_WARN(m_logger, "{} 当前不在检测时段内,停止对比检测", m_logBase);
-        return;
-    }
+    /* 更新检测时间段 */
+    checkDetectPeriod();
     /* -------------------------------------------------------------------------------------
      * 更新数据
      * ------------------------------------------------------------------------------------- */
@@ -270,26 +265,7 @@ bool CompareItemThread::initData()
         m_mapCDBUpdated.insert({it.nCompareRoadNum, false}); // 初始化更新标志位为false
     }
 
-    /* 初始化报警信息 */
-    // 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_lastDetectPeriodUpdateTime = QDateTime::currentDateTime();
     
 
     return true;
@@ -348,6 +324,7 @@ void CompareItemThread::initMQTT()
     }
     /* 登陆MQTT */
     m_pFromMQTT->setIPAndPort(GInfo.mqttIP(), GInfo.mqttPort());
+    m_pFromMQTT->setAutoReconnect();
     m_pFromMQTT->connectToServer();
 
     m_pubTopic = QString("%1/%2").arg(GInfo.mqttPubTopicDB()).arg(QString::number(m_threadInfo.compareItemInfo.nID));
@@ -565,10 +542,12 @@ 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);
+
+        // const OneRoadVolume_t& volume = m_compareResult.mapRoadVolumes[pair.first];
+        // for(int i = 0; i < VOLUME_INFO_NUM; ++i)
+        // {
+        //     fmt::print("LDB:{}, RDB:{}\n", volume.vecleftDB[i], volume.vecrightDB[i]);
+        // }
 
         pair.second = true; // 设置更新标志位为true
     }
@@ -618,97 +597,43 @@ bool CompareItemThread::updateResultData()
         }
     }
 
+    // for(const auto& roadVolume : m_compareResult.mapRoadVolumes)
+    // {
+    //     const OneRoadVolume_t& volume = roadVolume.second;
+    //     for(int i = 0; i < VOLUME_INFO_NUM; ++i)
+    //     {
+    //         fmt::print("LDB:{}, RDB:{}\n", volume.vecleftDB[i], volume.vecrightDB[i]);
+    //     }
+    // }
+
     return true;
 }
 
 
 
-/**
-    处理报警数据,现在的报警信息都是实时的,不再是报警结束后得到的数据了
-    处理逻辑:
-        1、如果是开始报警了,将报警信息发送给录制报警文件的线程,开始录音
-        2、如果是结束报警了,将报警结束信息再次通知录制报警文件的线程,结束录音
-           然后将报警信息发送给写入数据库的线程,写入到数据库中
-        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;
-//             }
-//         }
-//     }
-
-//     /* 处理一致性报警信息 */
-
-//     /* 处理噪音报警信息 */
-
-    
-//     /* 将报警列表写入到处理报警数据的线程中 */
-//     AlarmManager.addAlarmInfo(m_listWriteAlarm);
-// }
 
 /* 发送数据 */
 void CompareItemThread::sendResultData()
 {
+    // for(const auto& roadVolume : m_compareResult.mapRoadVolumes)
+    // {
+    //     const OneRoadVolume_t& volume = roadVolume.second;
+    //     for(int i = 0; i < VOLUME_INFO_NUM; ++i)
+    //     {
+    //         fmt::print("LDB:{}, RDB:{}\n", volume.vecleftDB[i], volume.vecrightDB[i]);
+    //     }
+    // }
+
     if(m_pFromMQTT == nullptr)
     {
         SPDLOG_LOGGER_WARN(m_logger, "{} MQTT连接未初始化,无法发送数据", m_logBase);
         return;
     }
+    if(m_pFromMQTT->connectState() != QMQTT::ConnectionState::STATE_CONNECTED)
+    {
+        SPDLOG_LOGGER_WARN(m_logger, "{} MQTT连接未成功,无法发送数据", m_logBase);
+        return;
+    }
     /* 生成json数据 */
     QByteArray jsonData;
     if(!generateMQTTJsonData(m_compareResult, jsonData))
@@ -769,10 +694,12 @@ bool CompareItemThread::generateMQTTJsonData(const CompareResult_t& compareResul
             for(const auto& db : roadVolume.second.vecleftDB)
             {
                 json1["left_db_array"].push_back(db);
+                // fmt::print("left_db_array: {}\n", db);
             }
             for(const auto& db : roadVolume.second.vecrightDB)
             {
                 json1["right_db_array"].push_back(db);
+                // fmt::print("right_db_array: {}\n", db);
             }
 
             /* 添加到基础信息中 */
@@ -789,19 +716,23 @@ bool CompareItemThread::generateMQTTJsonData(const CompareResult_t& compareResul
 }
 
 
-/* 检查是否在检测时间段内,返回false,不开启检测 */
+/* 检查是否在检测时间段内,更新其他检测功能的检测时间,对比项是否启用由外部控制 */
 bool CompareItemThread::checkDetectPeriod()
 {
-    std::lock_guard<std::mutex> lock(m_mutexDetectPeriod);
-    
-    /* 先判断是否启用了该对比项,这个设置在对比项中设置 */
-    if(!m_threadInfo.compareItemInfo.isEnable)
+    QDateTime currentTime = QDateTime::currentDateTime();
+    /* 2秒更新一次一致性检测时间 */
+    if(m_lastDetectPeriodUpdateTime.secsTo(currentTime) < 2)
     {
-        return false; // 对比项未启用,不进行检测
+        return true;
     }
+    m_lastDetectPeriodUpdateTime = currentTime;
 
-    QDateTime currentTime = QDateTime::currentDateTime();
+    std::lock_guard<std::mutex> lock(m_mutexDetectPeriod);
+
+    
     int currentWeekday = currentTime.date().dayOfWeek(); // 获取当前星期几,1-7表示周日到周六
+    QTime allDayTime;
+    allDayTime.setHMS(0, 0, 0);
     /* 判断时段 */
     bool isInDetectPeriod = false;
     for(const auto& period : m_detectPeriod.listDetect)
@@ -809,6 +740,12 @@ bool CompareItemThread::checkDetectPeriod()
         /* 先判断是否有符合的周几 */
         if(static_cast<int>(period.weekType) == currentWeekday)
         {
+            /* 判断一种特殊情况,开始时间和结束时间都是“00:00:00”,这个是全天都检测 */
+            if(period.timeStart == allDayTime && period.timeEnd == allDayTime)
+            {
+                isInDetectPeriod = true;
+                break;
+            }
             /* 判断当前时间是否在检测时段内 */
             if(currentTime.time() >= period.timeStart && currentTime.time() <= period.timeEnd)
             {

+ 2 - 4
Server/ThreadCalculate/CompareItemThread.h

@@ -94,8 +94,6 @@ private:
 
     /* 更新数据 */
     bool updateResultData();
-    /* 处理报警数据,写入数据库 */
-    // void processAlarmData();
     /* 发送数据 */
     void sendResultData();
 
@@ -104,7 +102,7 @@ private:
     /* 生成发送至MQTT的JSON数据 */
     bool generateMQTTJsonData(const CompareResult_t& compareResult, QByteArray& jsonData);
 
-    /* 检查是否在检测时间段内,返回false,不开启检测 */
+    /* 检查是否在检测时间段内,更新其他检测功能的检测时间,对比项是否启用由外部控制 */
     bool checkDetectPeriod();
 
 private:
@@ -134,7 +132,7 @@ private:
     std::mutex m_mutexDetectPeriod;         /* 检测时段互斥锁 */
     // std::atomic_bool m_isDetectPeriodUpdated = false; /* 检测时段更新标志 */
     DetectPeriodConfig_t m_detectPeriod;    /* 检测时段配置 */
-
+    QDateTime m_lastDetectPeriodUpdateTime; /* 上次检测时段更新时间 */
 };
 
 

+ 1 - 23
Server/ThreadCalculate/ConsistencyCompareThread.cpp

@@ -112,29 +112,7 @@ void ConsistencyCompareThread::task()
     {
         std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
-        /*--------------------------------------------------------------
-         * 更新最新数据
-         *--------------------------------------------------------------*/
-        m_pCreateWAVThread1->getLatestFileName(m_wavFilePath1);
-        m_pCreateWAVThread2->getLatestFileName(m_wavFilePath2);
-        /* 检查是否有新的数据 */
-        if(m_wavFilePath1 == m_prevWavFilePath1 || m_wavFilePath2 == m_prevWavFilePath2)
-        {
-            // SPDLOG_LOGGER_INFO(m_logger, "{} 检测到文件路径未变化", m_logBase);
-            continue;
-        }
-
-
-        /*--------------------------------------------------------------
-         * 开始比对计算,并保存计算结果
-         *--------------------------------------------------------------*/
-        if(!compareConsistency())
-        {
-            continue;
-        }
-
-        m_prevWavFilePath1 = m_wavFilePath1; // 更新上一个wav文件路径
-        m_prevWavFilePath2 = m_wavFilePath2; // 更新上一个wav文件路径
+        compareConsistencyData();
     }
     clearData();
     SPDLOG_LOGGER_WARN(m_logger, " ★ {} 一致性对比线程(调用动态库)已结束运行  ", m_logBase);

+ 2 - 4
Server/ThreadCalculate/NoiseDetectThread.cpp

@@ -209,8 +209,7 @@ bool NoiseDetectThread::detectNoise()
             m_window_params,        /* 窗函数参数 */
             m_nperseg,              /* 每段样本数 */
             m_noverlap,             /* 重叠样本数 */
-            m_nfft,                 /* FFT点数 */
-            false                   /* 是否输出调试信息, true表示输出调试信息, false表示不输出调试信息 */
+            m_nfft                  /* FFT点数 */
         );
         isNoiseLeft = jsonOutput["noise"].is_null() ? false : jsonOutput["noise"].get<bool>();
 
@@ -231,8 +230,7 @@ bool NoiseDetectThread::detectNoise()
             m_window_params,        /* 窗函数参数 */
             m_nperseg,              /* 每段样本数 */
             m_noverlap,             /* 重叠样本数 */
-            m_nfft,                 /* FFT点数 */
-            false                   /* 是否输出调试信息, true表示输出调试信息, false表示不输出调试信息 */
+            m_nfft                  /* FFT点数 */
         );
         isNoiseRight = jsonOutput["noise"].is_null() ? false : jsonOutput["noise"].get<bool>();
 

+ 12 - 4
Server/ThreadManager/ThreadCompareItemManager.cpp

@@ -423,7 +423,7 @@ void ThreadCompareItemManager::processDetectPeriodInfo()
     }
 
     QMap<int, DetectPeriodConfig_t> mapUpdateDetectConfig;
-    checkDetectPeriodInfo(mapNewDetectConfig, mapUpdateDetectConfig);
+    checkDetectPeriodInfo(m_mapDetectPeriod, mapNewDetectConfig, mapUpdateDetectConfig);
 
     /* 更新检测时段 */
     for(const auto& it : mapUpdateDetectConfig)
@@ -440,19 +440,22 @@ void ThreadCompareItemManager::processDetectPeriodInfo()
             }
         }
     }
+    /* 更新当前检测时段信息 */
+    m_mapDetectPeriod = mapNewDetectConfig;
 }
 
 /* 检查获取出更新的对比项信息 */
-void ThreadCompareItemManager::checkDetectPeriodInfo(QMap<int, DetectPeriodConfig_t> newDetectInfo, QMap<int, DetectPeriodConfig_t>& updateList)
+void ThreadCompareItemManager::checkDetectPeriodInfo(QMap<int, DetectPeriodConfig_t>& nowDetectInfo, QMap<int, DetectPeriodConfig_t> newDetectInfo, QMap<int, DetectPeriodConfig_t>& updateList)
 {
     for(const auto& it : newDetectInfo)
     {
         int compareItemID = it.nID;
-
-        for(const auto& existingItem : m_mapDetectPeriod)
+        bool isFound = false;
+        for(const auto& existingItem : nowDetectInfo)
         {
             if(existingItem.nID == compareItemID)
             {
+                isFound = true;
                 /* 已经存在的对比项,检查是否需要更新 */
                 if(existingItem == it)
                 {
@@ -466,6 +469,11 @@ void ThreadCompareItemManager::checkDetectPeriodInfo(QMap<int, DetectPeriodConfi
                 return;
             }
         }
+        if(isFound == false)
+        {
+            /* 新对比项,添加到更新列表 */
+            updateList.insert(compareItemID, it);
+        }
     }
 }
 

+ 1 - 1
Server/ThreadManager/ThreadCompareItemManager.h

@@ -78,7 +78,7 @@ private:
     /* 处理检测时段信息 */
     void processDetectPeriodInfo();
     /* 检查获取出更新的对比项信息 */
-    void checkDetectPeriodInfo(QMap<int, DetectPeriodConfig_t> newDetectInfo, QMap<int, DetectPeriodConfig_t>& updateList);
+    void checkDetectPeriodInfo(QMap<int, DetectPeriodConfig_t>& nowDetectInfo, QMap<int, DetectPeriodConfig_t> newDetectInfo, QMap<int, DetectPeriodConfig_t>& updateList);
 
     /* ---------------------- 向MQTT发送对比项信息 ---------------------- */
     /* 更新对比项信息到MQTT */

+ 128 - 79
Server/ThreadRecord/AssignSrcDataThread.cpp

@@ -10,7 +10,11 @@
 #include <QWriteLocker>
 #include <QReadLocker>
 #include <cstdint>
-#include <qreadwritelock.h>
+
+#include "CreateDBThread.h"
+#include "CreateWAVThread.h"
+#include "CreateLongFileThread.h"
+
 
 
 AssignSrcDataThread::AssignSrcDataThread(RecordThreadInfo_t& threadInfo)
@@ -21,11 +25,11 @@ AssignSrcDataThread::AssignSrcDataThread(RecordThreadInfo_t& threadInfo)
 
 AssignSrcDataThread::~AssignSrcDataThread()
 {
-    if(m_pRwLock != nullptr)
-    {
-        delete m_pRwLock;
-        m_pRwLock = nullptr;
-    }
+    // if(m_pRwLock != nullptr)
+    // {
+    //     delete m_pRwLock;
+    //     m_pRwLock = nullptr;
+    // }
     for(auto& audioData : m_listAudioSrcData)
     {
         if(audioData != nullptr)
@@ -42,6 +46,14 @@ AssignSrcDataThread::~AssignSrcDataThread()
     }
 }
 
+/* 停止线程 */
+void AssignSrcDataThread::stopThread()
+{
+    m_isRunning = false;
+    m_condDataUpdate.notify_all(); // 通知所有等待的线程
+
+}
+
 
 
 /* 设置数据,这里不用 */
@@ -69,9 +81,17 @@ bool AssignSrcDataThread::setSrcData(const char* srcData, int32_t dataSize, QDat
     audioData->appendData(srcData, dataSize);
     audioData->endTime = endTime;
     /* 获取读写锁 */
-    QWriteLocker locker(m_pRwLock);
-    m_listAudioSrcData.push_back(audioData);
-    m_listDataSize += dataSize; // 更新缓存中的数据大小
+    {
+        // std::lock_guard<QReadWriteLock> lock(m_pRwLock);
+        std::unique_lock<std::mutex> lock(m_mutexDataUpdate);
+        m_listAudioSrcData.push_back(audioData);
+        m_listDataSize += dataSize; // 更新缓存中的数据大小
+        m_isDataUpdate.store(true);
+    }
+    m_condDataUpdate.notify_one();
+
+    // SPDLOG_LOGGER_WARN(m_logger, "{} 收到音频数据: 大小: {}, 时间: {}", m_logBase, dataSize, endTime.toString().toStdString());
+
     return true;
 }
 
@@ -93,20 +113,39 @@ void AssignSrcDataThread::task()
         return;
     }
     /* 将自身设置到录音线程中 */
-    m_pRecordThread->setAssignSrcDataThread(this);
+    m_pThreadRecord->setAssignSrcDataThread(this);
     
     m_isRunning = true;
     while(m_isRunning)
     {
         /* 休眠一段时间 */
-        std::this_thread::sleep_for(std::chrono::milliseconds(10));
-        
+        // std::this_thread::sleep_for(std::chrono::milliseconds(10));
+        std::unique_lock<std::mutex> lock(m_mutexDataUpdate);
+        m_condDataUpdate.wait(lock, [this] {
+            return (m_isDataUpdate.load() || !m_isRunning.load());
+        });
+        m_isDataUpdate.store(false);
+        // std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
+
         /*------------------------------------------------------------------------
-         * 获取一个数据并处理数据,将每一个数据都设置成1s大小,将时间设置为这个数据的开始时间
+         * 分派实时数据
          *------------------------------------------------------------------------*/
+        /* 获取最新的数据,给其添加开始时间戳 */
+        auto latestData = m_listAudioSrcData.back();
+        if(latestData == nullptr || latestData->isEmpty())
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "{} 分派数据线程获取到空数据", m_logBase);
+            continue;
+        }
+        latestData->startTime = previTime(latestData->endTime, latestData->dataSize);
+
         /* 将发送数据到Rtp线程 */
-        sendSrcDataToRtp();
-        
+        sendSrcDataToRtp(*latestData);
+
+
+        /*------------------------------------------------------------------------
+         * 将每一个数据都设置成1s大小,将时间设置为这个数据的开始时间
+         *------------------------------------------------------------------------*/
         /* 判断数据是否满足1s大小 */
         if(!isFullOneSecondData())
         {
@@ -119,18 +158,16 @@ void AssignSrcDataThread::task()
         m_dispatchSrcData->startTime = previTime(m_dispatchSrcData->endTime, m_dispatchSrcData->dataSize);
 
         /*------------------------------------------------------------------------
-         * 分派数据
+         * 分派常规数据
          *------------------------------------------------------------------------*/
         /* 分派数据给各个线程 */
-        for(auto& dispatchThread : m_listDispatchThreads)
-        {
-            if(dispatchThread != nullptr)
-            {
-                dispatchThread->setData(*m_dispatchSrcData);
-            }
-        }
+        sendRegularData(*m_dispatchSrcData);
         /* 清空分派数据 */
         m_dispatchSrcData->clear();
+
+        // std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
+        // auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime);
+        // SPDLOG_LOGGER_TRACE(m_logger, "{} 分派数据耗时: {}us", m_logBase, duration.count());
     }
     /* 清理数据 */
     clearData();
@@ -153,8 +190,10 @@ bool AssignSrcDataThread::initData()
 
     m_dispatchSrcData = new AudioSrcData(m_oneSecondSize);
 
+    m_lastSendTime = QDateTime::currentDateTime(); // 初始化最后发送时间
+
     /* 初始化读写锁 */
-    m_pRwLock = new QReadWriteLock();
+    // m_pRwLock = new QReadWriteLock();
 
     return true;
 }
@@ -192,19 +231,22 @@ bool AssignSrcDataThread::getDispatchThread()
     auto pWavThread = ThreadMan.findRecordThread(EThreadType::Type_CreateWAV, m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
     if(pWavThread != nullptr)
     {
-        m_listDispatchThreads.push_back(dynamic_cast<BaseRecordThread*>(pWavThread));
+        // m_listDispatchThreads.push_back(dynamic_cast<BaseRecordThread*>(pWavThread));
+        m_pThreadCreateWAV = dynamic_cast<CreateWAVThread*>(pWavThread);
     }
     /* 获取生成音量和反相数据的线程 */
     auto pDBAndPhaseThread = ThreadMan.findRecordThread(EThreadType::Type_CreateDB, m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
     if(pDBAndPhaseThread != nullptr)
     {
-        m_listDispatchThreads.push_back(dynamic_cast<BaseRecordThread*>(pDBAndPhaseThread));
+        // m_listDispatchThreads.push_back(dynamic_cast<BaseRecordThread*>(pDBAndPhaseThread));
+        m_pThreadCreateDB = dynamic_cast<CreateDBThread*>(pDBAndPhaseThread);
     }
     /* 获取生成长文件的线程 */
     auto pLongFileThread = ThreadMan.findRecordThread(EThreadType::Type_CreateLongWAV, m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
     if(pLongFileThread != nullptr )
     {
-        m_listDispatchThreads.push_back(dynamic_cast<BaseRecordThread*>(pLongFileThread));
+        // m_listDispatchThreads.push_back(dynamic_cast<BaseRecordThread*>(pLongFileThread));
+        m_pThreadCreateLongFile = dynamic_cast<CreateLongFileThread*>(pLongFileThread);
     }
     /* 获取发送RTP数据的线程 */
     m_rtpSenderThread = ThreadMan.findRecordThread(EThreadType::Type_RtpSend, m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
@@ -220,7 +262,7 @@ bool AssignSrcDataThread::getDispatchThread()
         auto pThreadBase = ThreadMan.findRecordThread(EThreadType::Type_RecordSrc, m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
         if(pThreadBase != nullptr)
         {
-            m_pRecordThread = dynamic_cast<RecordThread*>(pThreadBase);
+            m_pThreadRecord = dynamic_cast<RecordThread*>(pThreadBase);
             break; // 找到录音线程了
         }
         /* 如果没有找到录音线程,则等待一段时间再继续查找 */
@@ -233,7 +275,7 @@ bool AssignSrcDataThread::getDispatchThread()
 /* 判断是否满足1秒的数据 */
 bool AssignSrcDataThread::isFullOneSecondData() const
 {
-    QReadLocker locker(m_pRwLock);
+    // QReadLocker locker(m_pRwLock);
     /* 判断缓存中的数据是否满足1秒大小 */
     if(m_listDataSize + m_remainingDataSize >= m_oneSecondSize)
     {
@@ -273,10 +315,8 @@ bool AssignSrcDataThread::processData()
         } else 
         {
             /* 取出最新的一个数据,这里只取出数据,不进行数据拷贝,数据处理进入下一个循环后再处理 */
-            m_pRwLock->lockForRead();
             m_pCurrentSrcData = m_listAudioSrcData.front();
             m_listAudioSrcData.pop_front();
-            m_pRwLock->unlock();
             if(m_pCurrentSrcData == nullptr)
             {
                 break;
@@ -298,64 +338,73 @@ bool AssignSrcDataThread::processData()
 }
 
 /* 发送原始数据到Rtp中,实时发送,有新的就发送 */
-void AssignSrcDataThread::sendSrcDataToRtp()
+void AssignSrcDataThread::sendSrcDataToRtp(const AudioSrcData& srcData)
 {
-    QReadLocker locker(m_pRwLock);
+    // QReadLocker locker(m_pRwLock);
     if(m_rtpSenderThread == nullptr)
     {
         return; // 如果没有RTP发送线程,则直接返回
     }
+
+    m_rtpSenderThread->setData(srcData);
     
-    if(m_listAudioSrcData.empty())
+    // if(m_listAudioSrcData.empty())
+    // {
+    //     return; // 如果没有数据,则直接返回
+    // }
+
+    // SPDLOG_LOGGER_DEBUG(m_logger, "{} 发送RTP数据,队列大小: {}, 开始时间: {}, 当前时间:{}", 
+    //         m_logBase, m_listAudioSrcData.count(), m_listAudioSrcData.back()->startTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), 
+    //         m_lastSendTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString());
+
+    // auto it = m_listAudioSrcData.end();
+    // if(it != m_listAudioSrcData.begin())
+    // {
+    //     --it; // 移动到最后一个数据
+    // }
+
+    // /* 已发送过数据,获取这个数据在队列中的位置,然后发送剩余的数据 */
+    // for(; it != m_listAudioSrcData.begin(); --it)
+    // {
+    //     if((*it)->startTime == m_lastSendTime)
+    //     {
+    //         break; // 找到已发送数据的位置
+    //     }
+    // }
+    
+    // if(it == m_listAudioSrcData.begin())
+    // {
+    //     SPDLOG_LOGGER_TRACE(m_logger, "{} RTP线程需要拷贝全部数据", m_logBase);
+    // }
+    // /* 开始发送数据 */
+    // for(; it != m_listAudioSrcData.end(); ++it)
+    // {
+    //     if(*it != nullptr)
+    //     {
+    //         m_rtpSenderThread->setData(**it);
+    //         m_lastSendTime = (*it)->startTime; // 更新已发送数据
+    //     }
+    // }
+}
+
+
+/* 发送常规数据,对实时性要求不高的数据,数据时长1秒 */
+void AssignSrcDataThread::sendRegularData(const AudioSrcData& srcData)
+{
+    /* 发送计算音量的数据 */
+    if(m_pThreadCreateWAV != nullptr)
     {
-        return; // 如果没有数据,则直接返回
+        m_pThreadCreateWAV->setData(srcData);
     }
-    /* 如果发送数据和最新的数据不一样,则发送数据 */
-    if(m_pSendSrcData == nullptr)
+    /* 发送生成wav小文件的数据 */
+    if(m_pThreadCreateDB != nullptr)
     {
-        /* 还未发送过,直接发送所有数据 */
-        for(auto& audioData : m_listAudioSrcData)
-        {
-            if(audioData != nullptr)
-            {
-                m_rtpSenderThread->setData(*audioData);
-                m_pSendSrcData = audioData; // 更新已发送数据
-            }
-        }
-    }else 
+        m_pThreadCreateDB->setData(srcData);
+    }
+    /* 发送生成长文件的数据 */
+    if(m_pThreadCreateLongFile != nullptr)
     {
-        /* 已发送过数据,获取这个数据在队列中的位置,然后发送剩余的数据 */
-        auto it = m_listAudioSrcData.begin();
-        for(; it != m_listAudioSrcData.end(); ++it)
-        {
-            if(*it == m_pSendSrcData)
-            {
-                break; // 找到已发送数据的位置
-            }
-        }
-        if(it != m_listAudioSrcData.end())
-        {
-            ++it; // 移动到下一个数据
-            for(; it != m_listAudioSrcData.end(); ++it)
-            {
-                if(*it != nullptr)
-                {
-                    m_rtpSenderThread->setData(**it);
-                    m_pSendSrcData = *it; // 更新已发送数据
-                }
-            }
-        }else 
-        {
-            /* 没有找到相等的,说明这个队列中是全新的数据,所有的都需要发送 */
-            for(auto& audioData : m_listAudioSrcData)
-            {
-                if(audioData != nullptr)
-                {
-                    m_rtpSenderThread->setData(*audioData);
-                    m_pSendSrcData = audioData; // 更新已发送数据
-                }
-            }
-        }
+        m_pThreadCreateLongFile->setData(srcData);
     }
 }
 

+ 45 - 14
Server/ThreadRecord/AssignSrcDataThread.h

@@ -2,18 +2,26 @@
 #define _ASSIGNSRCDATATHREAD_H_
 
 #include "BaseRecordThread.h"
+#include <condition_variable>
 
 #include <cstdint>
-#include <list>
+#include <QList>
 #include <QReadWriteLock>
 
+
 struct AudioSrcData;
 class RecordThread;
+class CreateDBThread;
+class CreateWAVThread;
+class CreateLongFileThread;
+
 
 /**
- * 线程功能:
- *          1、获取小于1s的数据,将其拼接成1s大小的数据,并配上这段数据开始时间(由数据大小推算而来)
- *          2、将拼接好的数据分发给各个数据处理线程,满1秒就分发一次
+    线程功能:
+            1、获取小于1s的数据,将其拼接成1s大小的数据,并配上这段数据开始时间(由数据大小推算而来)
+            2、线程等待不再使用线程休眠的方式,使用条件变量休眠线程,有数据后可以立马唤醒线程
+            3、常规分发数据: 将拼接好的数据分发给各个数据处理线程,满1秒就分发一次
+            4、实时分发数据: 收到数据后立马进行转发
  */
 class AssignSrcDataThread : public BaseRecordThread
 {
@@ -21,12 +29,16 @@ public:
     AssignSrcDataThread(RecordThreadInfo_t& threadInfo);
     ~AssignSrcDataThread() override;
 
+    /* 停止线程 */
+    void stopThread() override;
 
     /* 设置数据,这里不用 */
     bool setData(const AudioSrcData& srcData) override;
     /* 设置数据,输入小于1秒的数据 */
     bool setSrcData(const char* srcData, int32_t dataSize, QDateTime& endTime);
 
+
+
 protected:
     /* 线程任务函数 */
     void task() override;
@@ -45,23 +57,42 @@ private:
     bool processData();
 
     /* 发送原始数据到Rtp中,实时发送,有新的就发送 */
-    void sendSrcDataToRtp();
+    void sendSrcDataToRtp(const AudioSrcData& srcData);
 
+    /* 发送常规数据,对实时性要求不高的数据,数据时长1秒 */
+    void sendRegularData(const AudioSrcData& srcData);
 private:
-    /* 需要分配数据的线程指针集合 */
-    std::list<BaseRecordThread*> m_listDispatchThreads;
-    RecordThread* m_pRecordThread = nullptr;            /* 录音线程 */
-    BaseRecordThread* m_rtpSenderThread = nullptr;      /* RTP发送线程 */
-    AudioSrcData* m_pSendSrcData = nullptr;             /* 已发送的数据,用牌判断是否有新数据了 */
+    /* 条件变量 */
+    std::atomic_bool m_isDataUpdate = false;            /* 数据更新标志,数据更新时设置为true */
+    std::condition_variable m_condDataUpdate;           /* 数据更新条件变量 */
+    std::mutex m_mutexDataUpdate;                       /* 数据更新互斥锁 */
 
-    QReadWriteLock* m_pRwLock = nullptr;                /* 读写锁,保护数据的读写 */
-    std::list<AudioSrcData*> m_listAudioSrcData;        /* 数据缓存列表 */
-    int32_t m_listDataSize = 0;                        /* 缓存中的数据是否满1秒大小 */
+    /* ---------------------- 数据缓存列表 ---------------------- */
+    // QReadWriteLock m_pRwLock;                           /* 读写锁,保护数据的读写 */
+    QList<AudioSrcData*> m_listAudioSrcData;            /* 数据缓存列表,这里使用QList,可以使用[]运算符 */
+    int32_t m_listDataSize = 0;                         /* 缓存中的数据是否满1秒大小 */
 
     AudioSrcData* m_dispatchSrcData = nullptr;          /* 分发的数据,1秒大小 */
 
     AudioSrcData* m_pCurrentSrcData = nullptr;          /* 当前处理的数据 */
-    int32_t m_remainingDataSize = 0;                   /* 当前的AudioSrcData剩余可用数据的大小 */
+    int32_t m_remainingDataSize = 0;                    /* 当前的AudioSrcData剩余可用数据的大小 */
+
+    /* ---------------------- 录音线程指针 ---------------------- */
+    RecordThread* m_pThreadRecord = nullptr;            /* 录音线程 */
+
+    /* ---------------------- RTP发送相关变量 ---------------------- */
+    BaseRecordThread* m_rtpSenderThread = nullptr;      /* RTP发送线程 */
+    QDateTime m_lastSendTime;                           /* 上次发送数据的时间 */
+
+    /* ---------------------- 计算音量的线程 ---------------------- */
+    CreateDBThread* m_pThreadCreateDB = nullptr;        /* 创建音量的线程 */
+
+    /* ---------------------- 生成Wav小文件的线程 ---------------------- */
+    CreateWAVThread* m_pThreadCreateWAV = nullptr;      /* 创建Wav小文件的线程 */
+
+    /* ---------------------- 生成长文件的线程 ---------------------- */
+    CreateLongFileThread* m_pThreadCreateLongFile = nullptr; /* 创建长文件的线程 */
+
 };
 
 #endif // _ASSIGNSRCDATATHREAD_H_

+ 11 - 1
Server/ThreadRecord/CreateDBThread.cpp

@@ -58,6 +58,14 @@ bool CreateDBThread::setData(const AudioSrcData& srcData)
     return true;
 }
 
+/* 设置实时数据 */
+bool CreateDBThread::setRealTimeData(const AudioSrcData& srcData)
+{
+
+
+    return true;
+}
+
 
 /* 获取最新的结果,根据时间进行对比,最新的时间比传入的晚,就是有新的数据了 */
 bool CreateDBThread::getLatestResult(OneSecondData& resultData)
@@ -307,11 +315,13 @@ bool CreateDBThread::CreateDBPhase(AudioSrcData* audioData)
         // 采样点最大值
         short sMaxA, sMaxB, sRMSA, sRMSB;
         audioCor.CorrelateChunks(pWaveVu + iCurPos, (pWaveVu + iCurPos + 1), oneDBSize, &sMaxA, &sMaxB, &sRMSA, &sRMSB, audioInfo);
-
+        
         /* 这里乘2是要增加两个通道的数据大小 */
         iCurPos += (oneDBSize * 2);
         m_result->aryLeftDB[i] = calculateDB(sMaxA);
         m_result->aryRightDB[i] = calculateDB(sMaxB);
+        // fmt::print("音量计算: sMaxA: {}, sMaxB: {}, sRMSA: {}, sRMSB: {}, LDB:{}, RDB:{}\n", sMaxA, sMaxB, sRMSA, sRMSB, 
+        //     m_result->aryLeftDB[i], m_result->aryRightDB[i]);
 
         // 获取反相值,-100 到 100;反相是左右声道比对得到的值,所以只有一个
         int iReversed = audioCor.GetCorrelationLevel();

+ 2 - 0
Server/ThreadRecord/CreateDBThread.h

@@ -24,6 +24,8 @@ public:
 
     /* 设置数据 */
     bool setData(const AudioSrcData& srcData) override;
+    /* 设置实时数据 */
+    bool setRealTimeData(const AudioSrcData& srcData);
 
     /* 获取结果的环形队列 */
     RingQueueManualMutex<OneSecondData*>* getResultQueue() { return m_queueResultData; }

+ 14 - 7
Server/ThreadRecord/RecordThread.cpp

@@ -76,14 +76,18 @@ void RecordThread::task()
     m_isRunning = true;
     while(m_isRunning)
     {
-        // SPDLOG_LOGGER_DEBUG(m_logger, "{} 开始录音", m_logBase);
+        // std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
+        
         /* 获取音频数据,读取的帧数就是采样率,也就是一秒钟数据 */
-        if(!m_audioRecord.recordAudio(m_pRecordBuffer, m_recordBufferSize, m_oneRecordSize))
+        if(!m_audioRecord.recordAudio(m_pRecordBuffer, m_recordBufferSize, m_oneRecordCount))
         {
             SPDLOG_LOGGER_ERROR(m_logger, "{} 录音失败,可能是声卡被占用或其他错误", m_logBase);
             break;  /* 录音失败,退出循环 */
         }
-        // SPDLOG_LOGGER_DEBUG(m_logger, "{} 录音完成,数据大小: {}", m_logBase, m_recordBufferSize);
+
+        // std::chrono::steady_clock::time_point recordTime = std::chrono::steady_clock::now();
+        // auto recordDuration = std::chrono::duration_cast<std::chrono::milliseconds>(recordTime - startTime);
+        // SPDLOG_LOGGER_TRACE(m_logger, "{} 录音完成,数据大小: {}, 消耗时长:{}ms", m_logBase, m_recordBufferSize, recordDuration.count());
 
         QDateTime currentTime = QDateTime::currentDateTime();
         /* 将音频数据拷贝给分派数据的线程 */
@@ -98,7 +102,10 @@ void RecordThread::task()
         //     static_cast<int16_t>(*(m_pRecordBuffer + i * 2)));
         // }
         memset(m_pRecordBuffer, 0, m_recordBufferSize);  /* 清空缓存,准备下一次录音 */
-        // SPDLOG_LOGGER_DEBUG(m_logger, "{} 录音数据已分派给AssignSrcDataThread线程", m_logBase);
+
+        // std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
+        // auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - recordTime);
+        // SPDLOG_LOGGER_TRACE(m_logger, "{} 分派数据耗时: {}us", m_logBase, duration.count());
     }
 
     SPDLOG_LOGGER_WARN(m_logger, "➢ {} 结束录音", m_logBase);
@@ -123,9 +130,9 @@ bool RecordThread::initData()
 
     m_oneSecondSize = m_sampleRate * m_numChannels * (m_bitsPerSample / 8); /* 每秒钟的音频数据大小 */
 
-    /* 每次录音的音频数据大小,这里是100ms去一次数据,监听的时候延迟会小一些 */
-    m_recordBufferSize = m_oneSecondSize / 10;
-    m_oneRecordSize = m_sampleRate / 10;
+    /* 每次录音的音频数据大小,这里的大小是计算一个音量包所需要的大小 */
+    m_recordBufferSize = m_oneSecondSize / VOLUME_INFO_NUM;
+    m_oneRecordCount = m_sampleRate / VOLUME_INFO_NUM;
     m_pRecordBuffer = new char[m_recordBufferSize] {0};  /* 录音数据缓存 */
 
     /* 初始化录制类的参数 */

+ 1 - 1
Server/ThreadRecord/RecordThread.h

@@ -52,7 +52,7 @@ private:
     std::string m_audioRecordDesc;      /* 声卡描述符 */
     char* m_pRecordBuffer = nullptr;    /* 录音数据缓存 */
     int32_t m_recordBufferSize = 0;     /* 录音数据缓存大小 */
-    int32_t m_oneRecordSize = 0;        /* 每次录音的音频数据大小,单位音频帧,位深度 * 通道数 */
+    int32_t m_oneRecordCount = 0;       /* 每次录音的音频数据大小,单位音频帧,位深度 * 通道数 */
 
     AssignSrcDataThread* m_assignThread = nullptr; /* 分派数据线程指针 */
 };

+ 2 - 1
Server/main.cpp

@@ -45,7 +45,7 @@ int main(int argc, char* argv[])
     }
     SPDLOG_LOGGER_DEBUG(logger, "☆ 初始化噪音检测服务");
     /* 初始化噪音检测功能 */
-    // signalstats_wrapper::initialize();
+    signalstats::initialize(false);
     SPDLOG_LOGGER_DEBUG(logger, "★ 噪音检测服务初始化完成");
 
     ACAServer acas;
@@ -68,6 +68,7 @@ int main(int argc, char* argv[])
 
     int result = a.exec();
 
+    signalstats::finalize(); // 结束噪音检测服务
     SPDLOG_LOGGER_INFO(logger, "ACAServer 结束运行");
 
     return result;

BIN
ThreeLib/signalstats-uos-20250731-01.tar.xz


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


BIN
ThreeLib/signalstats-v1.0.tar.xz


+ 9 - 11
ThreeLib/signalstats/include/signalstats.h

@@ -37,28 +37,26 @@ namespace signalstats
      * @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 是否输出调试信息
+     * @param silence_threshold 信号强度之静音检测阈值(默认-60.0),范围(-100,0],单位dBFS(相对于满量程的分贝)
+     * @param db_threshold 能量强度之噪声分贝阈值(默认-70.0),范围[-100,0],单位dB
+     * @param cv_threshold 能量强度之变异系数阈值(默认-70.0),范围[-100,0],单位dB
+     * @param window_params 窗函数参数,窗函数类型和参数(默认("tukey", 0.25)),alpha (0.0,1.0)
+     * @param nperseg 每段样本数(默认256),正整数
+     * @param noverlap 重叠样本数(默认32),正整数
+     * @param nfft FFT点数(默认256),正整数
      * @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 silence_threshold = -60.0,
         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);
+        int nfft = 256);
 }
 
 #endif // SIGNALSTATS_H

BIN
ThreeLib/signalstats/lib/libsignalstats.so


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

@@ -0,0 +1 @@
+libsignalstats.so.1

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


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

@@ -0,0 +1 @@
+libsignalstats.so.1.0

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


BIN
ThreeLib/uos-20250731-01/bin/test_demo


BIN
ThreeLib/uos-20250731-01/bin/test_main


BIN
ThreeLib/uos-20250731-01/bin/test_mp


+ 9 - 11
Server/LHLibraryAPI/signalstats.h → ThreeLib/uos-20250731-01/include/signalstats.h

@@ -37,28 +37,26 @@ namespace signalstats
      * @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 是否输出调试信息
+     * @param silence_threshold 信号强度之静音检测阈值(默认-60.0),范围(-100,0],单位dBFS(相对于满量程的分贝)
+     * @param db_threshold 能量强度之噪声分贝阈值(默认-70.0),范围[-100,0],单位dB
+     * @param cv_threshold 能量强度之变异系数阈值(默认-70.0),范围[-100,0],单位dB
+     * @param window_params 窗函数参数,窗函数类型和参数(默认("tukey", 0.25)),alpha (0.0,1.0)
+     * @param nperseg 每段样本数(默认256),正整数
+     * @param noverlap 重叠样本数(默认32),正整数
+     * @param nfft FFT点数(默认256),正整数
      * @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 silence_threshold = -60.0,
         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);
+        int nfft = 256);
 }
 
 #endif // SIGNALSTATS_H

+ 1 - 0
ThreeLib/uos-20250731-01/lib/libsignalstats.so

@@ -0,0 +1 @@
+libsignalstats.so.1

+ 1 - 0
ThreeLib/uos-20250731-01/lib/libsignalstats.so.1

@@ -0,0 +1 @@
+libsignalstats.so.1.0

BIN
ThreeLib/uos-20250731-01/lib/libsignalstats.so.1.0


+ 2 - 0
ThreeLib/uos-20250731-01/run.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+LD_LIBRARY_PATH=./lib ./bin/test_main

+ 4 - 0
show3/CMakeLists.txt

@@ -3,6 +3,10 @@
 set(this_exe show3)
 
 
+#设置第三方库路径
+link_directories(
+    ${CMAKE_SOURCE_DIR}/ThreeLib/signalstats/lib
+)
 
 #包含源文件
 file(GLOB LOCAL_SRC

+ 2 - 4
show3/main.cpp

@@ -64,8 +64,7 @@ void test1()
             window_params,
             256,   // nperseg
             32,    // noverlap
-            256,   // nfft
-            true  // debug
+            256   // nfft
         );
         std::cout << "源数据: " << std::endl;
         for(const auto it : audio_signal)
@@ -125,8 +124,7 @@ void test2()
             window_params,
             256,   // nperseg
             32,    // noverlap
-            256,   // nfft
-            true  // debug
+            256   // nfft
         );
         
         // 处理输出结果