Переглянути джерело

V0.4.2
1、修改了音量包的发送方式

Apple 1 день тому
батько
коміт
b6fb1c3bcd

+ 24 - 0
Server/DataStruct/AudioData.cpp

@@ -244,6 +244,30 @@ bool OneSecondData::isConstDB(int &nLeftDB, int &nRightDB)
 }
 
 
+OneDBData& OneDBData::operator=(const OneDBData &obj)
+{
+	if (this == &obj)
+	{
+		return *this; // 防止自赋值
+	}
+	leftDB = obj.leftDB;
+	rightDB = obj.rightDB;
+	phase = obj.phase;
+	startTime = obj.startTime;
+	endTime = obj.endTime;
+	return *this;
+}
+
+void OneDBData::clear()
+{
+	leftDB = VOLUME_MIN_BD;
+	rightDB = VOLUME_MIN_BD;
+	phase = 0.0f;
+	startTime = QDateTime();
+	endTime = QDateTime();
+}
+
+
 
 
 /*-------------------------------------------------------------------------------

+ 24 - 1
Server/DataStruct/AudioData.h

@@ -85,7 +85,7 @@ struct StPhase
 };
 
 
-// 一秒钟的数据
+// 一秒钟的数据音量包
 struct OneSecondData
 {
     OneSecondData();
@@ -132,6 +132,29 @@ public:
     QDateTime endTime;            /* 结束时间戳 */
 };
 
+/**
+ * @brief 单个音量包数据
+ * 
+ */
+struct OneDBData
+{
+    OneDBData() = default;
+    ~OneDBData() = default;
+
+    OneDBData(const OneDBData& obj) { *this = obj; }
+    OneDBData& operator=(const OneDBData &obj);
+    void clear();
+    
+    int leftDB = VOLUME_MIN_BD;         /* 左声道音量包 */
+    int rightDB = VOLUME_MIN_BD;        /* 右声道音量包 */
+    float phase = 0.0;                  /* 相位包 */
+    QDateTime startTime;                /* 开始时间戳 */
+    QDateTime endTime;                  /* 结束时间戳 */
+};
+
+
+
+
 /**
  * @brief 音频原始数据
  * 

+ 142 - 90
Server/ThreadCalculate/CompareItemThread.cpp

@@ -10,7 +10,7 @@
 #include "commonDefine.h"
 #include "ThreadAlarmManager.h"
 #include "spdlog.h"
-#include <qdatetime.h>
+#include <QDateTime>
 
 
 
@@ -57,11 +57,11 @@ void CompareItemThread::threadTask()
         SPDLOG_LOGGER_ERROR(m_logger, "{} 创建定时器失败", m_logBase);
     }
     
-        // SPDLOG_LOGGER_WARN(m_logger, "{} 创建定时器成功,开启定时器", m_logBase);
+    // SPDLOG_LOGGER_WARN(m_logger, "{} 创建定时器成功,开启定时器", m_logBase);
     m_pTimer->setTimerType(Qt::PreciseTimer);
     m_pTimer->setSingleShot(false); // 设置为非单次定时器
-    m_pTimer->setInterval(50);
-    m_eventLoop.connect(m_pTimer, &QTimer::timeout, this, &CompareItemThread::do_timeout);
+    m_pTimer->setInterval(30);
+    m_eventLoop.connect(m_pTimer, &QTimer::timeout, this, &CompareItemThread::do_timeout, Qt::DirectConnection);
     m_pTimer->start();
     
 
@@ -147,39 +147,7 @@ void CompareItemThread::task()
         /* 睡眠100ms */
         std::this_thread::sleep_for(std::chrono::milliseconds(50));
 
-        /* -------------------------------------------------------------------------------------
-         * 更新对比项信息
-         * ------------------------------------------------------------------------------------- */
-        if(updateThreadInfoInternal())
-        {
-            SPDLOG_LOGGER_INFO(m_logger, "{} 暂停对比检测,更新对比项信息");
-            m_threadInfo.compareItemInfo = m_threadInfoNew.compareItemInfo;
-            initData();
-            SPDLOG_LOGGER_INFO(m_logger, "{} 更新对比项信息完成,继续检测对比");
-        }
-
-        /* -------------------------------------------------------------------------------------
-         * 更新数据
-         * ------------------------------------------------------------------------------------- */
-        if(!updateResultData())
-        {
-            continue;
-            // return;
-        }
-
-        /* -------------------------------------------------------------------------------------
-         * 处理数据,将报警信息给写报警数据的线程
-         * ------------------------------------------------------------------------------------- */
-        // processAlarmData();
-
-        /* -------------------------------------------------------------------------------------
-         * 将音量包数据发送到MQTT中
-         * ------------------------------------------------------------------------------------- */
-        sendResultData();
-
-        /* 清除标志位 */
-        clearUpdateFlags();
-        SPDLOG_LOGGER_WARN(m_logger, "{} 发送对比项数据到MQTT中", m_logBase);
+        timerTask();
     }
     /* 清理数据 */
     clearData();
@@ -189,6 +157,7 @@ void CompareItemThread::task()
 /* 定时器任务 */
 void CompareItemThread::timerTask()
 {
+    
     /* -------------------------------------------------------------------------------------
      * 更新对比项信息
      * ------------------------------------------------------------------------------------- */
@@ -210,7 +179,7 @@ void CompareItemThread::timerTask()
         return;
     }
     /* -------------------------------------------------------------------------------------
-     * 处理数据,将报警信息给写报警数据的线程,直接由各个计算线程直接写入
+     * 处理数据,将报警信息给写报警数据的线程,现在直接由各个计算线程直接写入
      * ------------------------------------------------------------------------------------- */
     // processAlarmData();
     
@@ -220,7 +189,7 @@ void CompareItemThread::timerTask()
     sendResultData();
     /* 清除标志位 */
     clearUpdateFlags();
-    // SPDLOG_LOGGER_WARN(m_logger, "{} 发送对比项数据到MQTT中", m_logBase);
+
 }
 
 /* 初始化数据 */
@@ -240,10 +209,26 @@ bool CompareItemThread::initData()
     destroyCompareThreads();
     createCompareThreads();
 
-    /* 获取计算噪音的线程 */
+    /* 创建计算噪音的线程 */
     destroyNoiseDetectThreads();
     createNoiseDetectThreads();
 
+    /* 获取创建实时音量包的线程 */
+    if(!getCreateDBThread())
+    {
+        // SPDLOG_LOGGER_ERROR(m_logger, "{} 获取创建实时音量线程失败", m_logBase);
+        return false;
+    }
+    // for(const auto& pThread : m_mapCreateDBThreads)
+    // {
+    //     if(pThread.second == nullptr)
+    //     {
+    //         SPDLOG_LOGGER_ERROR(m_logger, "{} 获取创建实时音量线程失败,通道: {}", m_logBase, pThread.first);
+    //     }else {
+    //         SPDLOG_LOGGER_INFO(m_logger, "{} 获取创建实时音量线程成功,通道: {}", m_logBase, pThread.first);
+    //     }
+    // }
+
     /* 初始化存储结果的数据结构 */
     m_compareResult = CompareResult_t();
     m_compareResult.compareItemID = m_threadInfo.compareItemInfo.nID;
@@ -257,6 +242,8 @@ bool CompareItemThread::initData()
         oneRoadVolume.roadInfo = road; // 设置通道信息
         oneRoadVolume.dateTime = QDateTime::currentDateTime(); // 初始化时间
         m_compareResult.mapRoadVolumes.insert({road.nCompareRoadNum, oneRoadVolume});
+
+        m_mapRealTimeData.insert({road.nCompareRoadNum, std::list<OneDBData>()}); // 初始化实时数据
     }
 
     m_mapCDBUpdated.clear();
@@ -265,8 +252,8 @@ bool CompareItemThread::initData()
         m_mapCDBUpdated.insert({it.nCompareRoadNum, false}); // 初始化更新标志位为false
     }
 
-    m_lastDetectPeriodUpdateTime = QDateTime::currentDateTime();
-    
+    QDateTime currentTime = QDateTime::currentDateTime();
+    m_lastDetectPeriodUpdateTime = currentTime;
 
     return true;
 }
@@ -278,8 +265,7 @@ void CompareItemThread::clearData()
     destroyCompareThreads();
     /* 销毁音量报警线程 */
     destroyCalculateDBThreads();
-    /* 移除噪音检测线程 */
-    // removeNoiseDetectThreads();
+    /* 销毁噪音检测线程 */
     destroyNoiseDetectThreads();
 
     /* 移除使用到的录音通道 */
@@ -302,12 +288,17 @@ void CompareItemThread::clearData()
 /* 定时器槽函数 */
 void CompareItemThread::do_timeout()
 {
+    std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
     // SPDLOG_LOGGER_WARN(m_logger, "{} 定时器触发,开始执行定时任务", m_logBase);
     if(m_pFromMQTT == nullptr)
     {
         initMQTT();
     }
     timerTask();
+
+    std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
+    std::chrono::milliseconds duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
+    SPDLOG_LOGGER_DEBUG(m_logger, "{} 定时器任务完成,耗时: {} ms", m_logBase, duration.count());
 }
 
 /* 初始化MQTT */
@@ -333,6 +324,45 @@ void CompareItemThread::initMQTT()
 
 
 
+/* 获取创建实时音量的线程,这个线程属于录音线程,不需要在这里移除和销毁 */
+bool CompareItemThread::getCreateDBThread()
+{
+    m_mapCreateDBThreads.clear();
+    QDateTime startTime = QDateTime::currentDateTime();
+    /* 先设置有多少录音通道 */
+    for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
+    {
+        m_mapCreateDBThreads.insert({road.nCompareRoadNum, nullptr}); // 初始化为nullptr
+    }
+    while(true)
+    {
+        bool isAllThreadsReady = true;
+        for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
+        {
+            CreateDBThread* pThread = ThreadMan.getCreateDBThread(road.scRoadInfo.nSoundCardNum, road.scRoadInfo.roadInfo.nRoadNum);
+            if(pThread != nullptr)
+            {
+                m_mapCreateDBThreads[road.nCompareRoadNum] = pThread;
+                // SPDLOG_LOGGER_INFO(m_logger, "{} 获取创建实时音量线程成功,通道: {}:{}", m_logBase, road.scRoadInfo.strSoundCardName.toStdString(), road.scRoadInfo.roadInfo.nRoadNum);
+            } else
+            {
+                isAllThreadsReady = false;
+                SPDLOG_LOGGER_WARN(m_logger, "{} 获取创建实时音量线程失败,通道: {}:{}", m_logBase, road.scRoadInfo.strSoundCardName.toStdString(), road.scRoadInfo.roadInfo.nRoadNum);
+            }
+        }
+        if(isAllThreadsReady)
+        {
+            return true;
+        }
+        QDateTime currentTime = QDateTime::currentDateTime();
+        if(startTime.secsTo(currentTime) > 10) // 超过10秒还没有获取到线程,直接返回失败
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "{} 获取创建实时音量线程超时,通道: {}", m_logBase, m_threadInfo.compareItemInfo.strName.toStdString());
+            return false;
+        }
+    }
+}
+
 
 
 /* 创建两个对比线程,主通道是第一个通道,其他都需要和主通道进行对比 */
@@ -513,54 +543,76 @@ void CompareItemThread::destroyNoiseDetectThreads()
 
 
 /**
- * @brief 更新数据
- *          更新数据逻辑:
- *              1、先从音量计算线程获取最新的音量包信息,如果没有全部更新,则等待下次获取,不进行后面的操作
- *              2、获取噪音检测线程的噪音信息和获取一致性信息的线程的结果无需关系是否是最新的
- * 
+    音量包更新逻辑:
+        1、先从音量创建线程获取最新的音量包信息,固定n个音量包,音量包数量和发送速度有关系,一秒
+            最大有30个音量包(由宏定义VOLUME_INFO_NUM决定),如果每次发送3个音量包,则100ms发送一次
+        2、获取音量包直接从录音线程(CreateDBThread)获取,每次获取3个,循环等待所有通道获取完3个后
+            进行发送
+        3、客户端依赖音量包绘制波形,因此音量包尽可能地快速发送
+
+    检测结果更新逻辑
+        2、获取噪音检测线程的噪音信息和获取一致性信息的线程的结果无需关心是否是最新的
+
  */
 bool CompareItemThread::updateResultData()
 {
     /* -------------------------------------------------------------------------------------
-     * 先从音量计算数据中获取音量包信息和报警信息(静音、过载、反相)
+     * 先从音量计算数据中获取音量包信息,循环等待获取完成
      * ------------------------------------------------------------------------------------- */
-    for(auto& pair : m_mapCDBUpdated)
+    bool isAllUpdated = false;
+    while(isAllUpdated == false)
     {
-        if(pair.second == true)
-        {
-            /* 已经更新过了 */
-            continue;
-        }
-        CalculateDBThread* pThread = m_mapCalculateDBThreads[pair.first];
-        if(pThread == nullptr)
-        {
-            SPDLOG_LOGGER_ERROR(m_logger, "{} 音量计算线程失效", m_logBase);
-            continue;
-        }
-        /* 获取最新的音量数据,包括静音、过载、反向等报警信息 */
-        if(!pThread->getlastVolumeInfo(m_compareResult.mapRoadVolumes[pair.first]))
+        std::this_thread::sleep_for(std::chrono::milliseconds(1));
+        for(auto& pair : m_mapCDBUpdated)
         {
-            continue; // 没有获取到最新数据,继续等待
-        }
-
-        // 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]);
-        // }
+            if(pair.second == true)
+            {
+                /* 已经更新过了 */
+                continue;
+            }
+            // CalculateDBThread* pThread = m_mapCalculateDBThreads[pair.first];
+            // if(pThread == nullptr)
+            // {
+            //     SPDLOG_LOGGER_ERROR(m_logger, "{} 音量计算线程失效", m_logBase);
+            //     continue;
+            // }
+            // /* 获取最新的音量包数据 */
+            // if(!pThread->getlastVolumeInfo(m_compareResult.mapRoadVolumes[pair.first]))
+            // {
+            //     continue; // 没有获取到最新数据,继续等待
+            // }
+            CreateDBThread* pThread = m_mapCreateDBThreads[pair.first];
+            if(pThread == nullptr)
+            {
+                SPDLOG_LOGGER_WARN(m_logger, "{} 获取音量创建线程失败,通道: {}", m_logBase, pair.first);
+                continue;
+            }
+            /* 获取最新的音量包数据 */
+            if(!pThread->getLatestRealTimeResult(m_mapRealTimeData[pair.first], 3))
+            {
+                // SPDLOG_LOGGER_WARN(m_logger, "{} 获取最新音量值失败,通道: {}", m_logBase, pair.first);
+                continue;
+            }
 
-        pair.second = true; // 设置更新标志位为true
-    }
-    /* 判断是否全部更新,如果没有则返回,等待下次再次获取 */
-    for(auto& pair : m_mapCDBUpdated)
-    {
-        if(false == pair.second)
+            pair.second = true;
+        }
+        /* 判断是否全部更新,如果没有则返回,等待下次再次获取 */
+        isAllUpdated = true;
+        for(auto& pair : m_mapCDBUpdated)
         {
-            // SPDLOG_LOGGER_DEBUG(m_logger, "{} 音量计算线程数据未全部更新,等待下次获取", m_logBase);
-            return false;
+            if(false == pair.second)
+            {
+                isAllUpdated = false;
+                // SPDLOG_LOGGER_DEBUG(m_logger, "{} 音量计算线程数据未全部更新,等待下次获取", m_logBase);
+                break;
+            }
         }
     }
 
+    /* -------------------------------------------------------------------------------------
+     * 获取静音、过载、反相的结果
+     * ------------------------------------------------------------------------------------- */
+
 
     /* -------------------------------------------------------------------------------------
      * 获取噪音计算的结果(从噪音对比线程中获取)
@@ -674,11 +726,12 @@ bool CompareItemThread::generateMQTTJsonData(const CompareResult_t& compareResul
         
         for(const auto& roadVolume : compareResult.mapRoadVolumes)
         {
+            const int roadNum = roadVolume.first;
             nJson json1;
             json1["soundCard_id"] = roadVolume.second.roadInfo.scRoadInfo.strSoundCardID.toStdString(); /* 声卡id和声卡通道id */
             json1["soundCard_road_id"] = roadVolume.second.roadInfo.scRoadInfo.roadInfo.nRoadNum;
             /* 对比项通道编号和名称 */
-            json1["item_road_num"] = roadVolume.second.roadInfo.nCompareRoadNum;
+            json1["item_road_num"] = roadNum;
             json1["item_road_name"] = roadVolume.second.roadInfo.strCompareRoadName.toStdString();
             json1["similarity"] = roadVolume.second.similarity;
             json1["is_silence"] = roadVolume.second.isSilence;
@@ -688,19 +741,18 @@ bool CompareItemThread::generateMQTTJsonData(const CompareResult_t& compareResul
             json1["is_noise_warning"] = roadVolume.second.isNoiseWarning;
             json1["is_consistency"] = roadVolume.second.isConsistency;
             json1["is_not_consistency_warning"] = roadVolume.second.isNotConsistencyWarning;
-            json1["left_real_time_db"] = roadVolume.second.leftRealTimeDB;
-            json1["right_real_time_db"] = roadVolume.second.rightRealTimeDB;
             /* 添加音量包信息 */
-            for(const auto& db : roadVolume.second.vecleftDB)
+            auto& listRTData = m_mapRealTimeData[roadNum];
+            for(const auto& db : listRTData)
             {
-                json1["left_db_array"].push_back(db);
+                json1["left_db_array"].push_back(db.leftDB);
+                json1["right_db_array"].push_back(db.rightDB);
                 // 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);
-            }
+            listRTData.clear();
+
+            // json1["left_real_time_db"] = m_mapRealTimeData[roadNum].leftDB;
+            // json1["right_real_time_db"] = m_mapRealTimeData[roadNum].rightDB;
 
             /* 添加到基础信息中 */
             json0["road_volumes"].push_back(json1);

+ 15 - 2
Server/ThreadCalculate/CompareItemThread.h

@@ -9,11 +9,14 @@
 #include "BaseCalculateThread.h"
 #include "CompareResult.h"
 #include "FromMQTT.h"
+#include "AudioData.h"
+
 
 
 class CalculateDBThread;
 class NoiseDetectThread;
 class CompareDoubleThread;
+class CreateDBThread;
 
 
 /**
@@ -72,6 +75,9 @@ private slots:
     
 
 private:
+    /* 获取创建实时音量的线程,这个线程属于录音线程,不需要在这里移除和销毁 */
+    bool getCreateDBThread();
+
     /* 创建两个对比线程,主通道是第一个通道,其他都需要和主通道进行对比 */
     bool createCompareThreads();
     /* 销毁两两对比线程 */
@@ -86,6 +92,7 @@ private:
     /* 销毁噪音检测线程 */
     void destroyNoiseDetectThreads();
 
+
     /* 获取噪音检测的线程 */
     // bool getNoiseDetectThreads();
     /* 移除噪音检测的线程 */
@@ -115,18 +122,24 @@ private:
     /* 发布的主题 */
     QString m_pubTopic;
 
+    /* ---------------------- 对比项 ---------------------- */
+
     /* 计算音量信息的线程指针,第一个是主通道线程,int是对比项中的通道号 */
     std::map<int, CalculateDBThread*> m_mapCalculateDBThreads;
-    /* 音量包更新标志位 */
-    std::map<int, bool> m_mapCDBUpdated;
     /* 计算噪音的线程指针 */
     std::map<int, NoiseDetectThread*> m_mapNoiseDetectThreads;
     /* 对比项信息线程,这个线程在这里创建,不会和其他对比项复用,int是第二路对比通道的编号 */
     std::map<int, CompareDoubleThread*> m_mapCompareDoubleThreads;
+    /* 创建音量包的线程指针 */
+    std::map<int, CreateDBThread*> m_mapCreateDBThreads;
 
+    /* 音量包更新标志位,int是录音通道 */
+    std::map<int, bool> m_mapCDBUpdated;
 
     /* 计算的数据结果 */
     CompareResult_t m_compareResult;
+    /* 实时音频数据 */
+    std::map<int, std::list<OneDBData>> m_mapRealTimeData;
 
     /* ---------------------- 检测时段 ---------------------- */
     std::mutex m_mutexDetectPeriod;         /* 检测时段互斥锁 */

+ 45 - 22
Server/ThreadRecord/AssignSrcDataThread.cpp

@@ -139,8 +139,7 @@ void AssignSrcDataThread::task()
         }
         latestData->startTime = previTime(latestData->endTime, latestData->dataSize);
 
-        /* 将发送数据到Rtp线程 */
-        sendSrcDataToRtp(*latestData);
+        sendRealTimeSrcData(*latestData);
 
 
         /*------------------------------------------------------------------------
@@ -272,6 +271,30 @@ bool AssignSrcDataThread::getDispatchThread()
     return true;
 }
 
+
+
+/* 发送常规数据,对实时性要求不高的数据,数据时长1秒 */
+void AssignSrcDataThread::sendRegularData(const AudioSrcData& srcData)
+{
+    /* 发送计算音量的数据 */
+    if(m_pThreadCreateWAV != nullptr)
+    {
+        m_pThreadCreateWAV->setData(srcData);
+    }
+    /* 发送生成wav小文件的数据 */
+    if(m_pThreadCreateDB != nullptr)
+    {
+        m_pThreadCreateDB->setData(srcData);
+    }
+    /* 发送生成长文件的数据 */
+    if(m_pThreadCreateLongFile != nullptr)
+    {
+        m_pThreadCreateLongFile->setData(srcData);
+    }
+}
+
+
+
 /* 判断是否满足1秒的数据 */
 bool AssignSrcDataThread::isFullOneSecondData() const
 {
@@ -337,6 +360,26 @@ bool AssignSrcDataThread::processData()
     return true;
 }
 
+
+
+/* 发送实时音频数据 */
+void AssignSrcDataThread::sendRealTimeSrcData(const AudioSrcData& srcData)
+{
+    /* 发送实时数据到RTP中 */
+    if(m_rtpSenderThread != nullptr)
+    {
+        m_rtpSenderThread->setData(srcData);
+    }
+
+    /* 发送实时数据到创建音量包的线程 */
+    if(m_pThreadCreateDB != nullptr)
+    {
+        m_pThreadCreateDB->setRealTimeData(srcData);
+    }
+}
+
+
+
 /* 发送原始数据到Rtp中,实时发送,有新的就发送 */
 void AssignSrcDataThread::sendSrcDataToRtp(const AudioSrcData& srcData)
 {
@@ -388,25 +431,5 @@ void AssignSrcDataThread::sendSrcDataToRtp(const AudioSrcData& srcData)
 }
 
 
-/* 发送常规数据,对实时性要求不高的数据,数据时长1秒 */
-void AssignSrcDataThread::sendRegularData(const AudioSrcData& srcData)
-{
-    /* 发送计算音量的数据 */
-    if(m_pThreadCreateWAV != nullptr)
-    {
-        m_pThreadCreateWAV->setData(srcData);
-    }
-    /* 发送生成wav小文件的数据 */
-    if(m_pThreadCreateDB != nullptr)
-    {
-        m_pThreadCreateDB->setData(srcData);
-    }
-    /* 发送生成长文件的数据 */
-    if(m_pThreadCreateLongFile != nullptr)
-    {
-        m_pThreadCreateLongFile->setData(srcData);
-    }
-}
-
 
 

+ 9 - 3
Server/ThreadRecord/AssignSrcDataThread.h

@@ -51,16 +51,22 @@ protected:
 private:
     /* 获取需要分派数据的线程 */
     bool getDispatchThread();
+
+    /* ---------------------- 发送常规音量 ---------------------- */
+    /* 发送常规数据,对实时性要求不高的数据,数据时长1秒 */
+    void sendRegularData(const AudioSrcData& srcData);
     /* 判断是否满足1秒的数据 */
     bool isFullOneSecondData() const;
     /* 处理数据,将数据分配成1秒的小数据 */
     bool processData();
 
+    /* ---------------------- 发送实时音频数据 ---------------------- */
+    /* 发送实时音频数据 */
+    void sendRealTimeSrcData(const AudioSrcData& srcData);
     /* 发送原始数据到Rtp中,实时发送,有新的就发送 */
-    void sendSrcDataToRtp(const AudioSrcData& srcData);
+    inline void sendSrcDataToRtp(const AudioSrcData& srcData);
 
-    /* 发送常规数据,对实时性要求不高的数据,数据时长1秒 */
-    void sendRegularData(const AudioSrcData& srcData);
+    
 private:
     /* 条件变量 */
     std::atomic_bool m_isDataUpdate = false;            /* 数据更新标志,数据更新时设置为true */

+ 151 - 8
Server/ThreadRecord/CreateDBThread.cpp

@@ -1,7 +1,6 @@
 #include "CreateDBThread.h"
 
 #include "GlobalVariable.h"
-#include "AudioData.h"
 #include "GlobalInfo.h"
 
 #include "CalculateAudio.h"
@@ -61,7 +60,15 @@ bool CreateDBThread::setData(const AudioSrcData& srcData)
 /* 设置实时数据 */
 bool CreateDBThread::setRealTimeData(const AudioSrcData& srcData)
 {
-
+    auto oldData = m_queueRealTimeData.push_pop(new AudioSrcData(srcData));
+    if(oldData != nullptr)
+    {
+        /* 这里一般不会满,会被实时消耗,如果满了,说明出现问题了 */
+        SPDLOG_LOGGER_WARN(m_logger, "{} 实时数据环形队列已满,出队一个元素,时间: {}, 大小: {}", 
+            m_logBase, oldData->startTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), oldData->dataSize);
+        delete oldData;
+        oldData = nullptr;
+    }
 
     return true;
 }
@@ -189,6 +196,57 @@ bool CreateDBThread::getLatestResult(RingQueueManualMutex<OneSecondData*>& resul
 }
 
 
+/**
+ * @brief 获取最新的音量包结果
+ * 
+ * @param listData 
+ * @param count 等于负数是获取所有数据,等于正数,如果暂时没有这么多数据,则返回false
+ * @return true 获取成功
+ * @return false 无数据或者数据不足
+ */
+bool CreateDBThread::getLatestRealTimeResult(std::list<OneDBData>& listData, int count)
+{
+    std::lock_guard<std::mutex> lock(m_mutexRealTimeResult);
+    if(m_listRealTimeResult.empty())
+    {
+        // SPDLOG_LOGGER_TRACE(m_logger, "{} 最新实时音量数据为空", m_logBase);
+        return false;
+    }
+    if(count <= 0)
+    {
+        count = m_listRealTimeResult.size();
+    }
+    if(count > static_cast<int>(m_listRealTimeResult.size()))
+    {
+        // SPDLOG_LOGGER_WARN(m_logger, "{} 最新实时音量数据不足,要求: {}, 实际: {}", m_logBase, count, m_listRealTimeResult.size());
+        return false;
+    }
+    /* 获取最新的count个数据 */
+    for(int i = 0; i < count; ++i)
+    {
+        listData.push_back(m_listRealTimeResult.front());
+        m_listRealTimeResult.pop_front();
+    }
+
+    return true;
+}
+
+/* 获取一个最新音量值 */
+bool CreateDBThread::getLatestRealTimeResult(OneDBData& resultData)
+{
+    std::lock_guard<std::mutex> lock(m_mutexRealTimeResult);
+    if(m_listRealTimeResult.empty())
+    {
+        // SPDLOG_LOGGER_TRACE(m_logger, "{} 最新实时音量数据为空", m_logBase);
+        return false;
+    }
+    resultData = m_listRealTimeResult.front();
+    m_listRealTimeResult.pop_front();
+    return true;
+}
+
+
+
 /* 计算音量和反相的线程函数 */
 void CreateDBThread::task()
 {
@@ -202,14 +260,39 @@ void CreateDBThread::task()
 
     while(m_isRunning)
     {
-        /* 取出一个数据,没有数据则阻塞住 */
-        AudioSrcData* audioData = m_queueAudioData.front_pop();
-        // SPDLOG_LOGGER_DEBUG(m_logger, "{} 从环形队列中取出数据,队列大小: {}", m_logBase, m_queueAudioData.QueueSize());
+        
+        /*--------------------------------------------------------------
+        * 计算实时音量值(这个数据量很小,大概只有33ms,所以阻塞在这里)
+        *--------------------------------------------------------------*/
+        /* 判断实时数据列表是否有数据,没有数据则阻塞,直到有数据 */
+        auto rtData = m_queueRealTimeData.front();
+        if(rtData == nullptr)
+        {
+            SPDLOG_LOGGER_DEBUG(m_logger, "{} 实时数据队列为空,等待数据", m_logBase);
+            continue;
+        }
+        // std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
+        /* 计算实时音量值 */
+        calculateRealTimeVolume();
+
+        // std::chrono::steady_clock::time_point rtEndTime = std::chrono::steady_clock::now();
+        // std::chrono::microseconds rtDuration = std::chrono::duration_cast<std::chrono::microseconds>(rtEndTime - startTime);
+        // SPDLOG_LOGGER_DEBUG(m_logger, "{} 计算实时音量包完成,耗时: {} 微秒", m_logBase, rtDuration.count());
+        /*--------------------------------------------------------------
+        * 计算常规音量值,1秒计算一次
+        *--------------------------------------------------------------*/
+        /* 判断是否够一秒的数据 */
+        if(m_queueAudioData.isEmpty())
+        {
+            continue;
+        }
+
+        auto audioData = m_queueAudioData.front_pop();
 
         if(audioData == nullptr)
         {
             SPDLOG_LOGGER_WARN(m_logger, "{} 从环形队列中取出数据失败,可能是队列为空", m_logBase);
-            std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 等待一段时间再尝试
+            // std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 等待一段时间再尝试
             continue;
         }
         /* 计算音量和反相,结果存储在m_result */
@@ -234,8 +317,9 @@ void CreateDBThread::task()
         delete audioData; // 释放内存
         audioData = nullptr;
         
-        // SPDLOG_LOGGER_DEBUG(m_logger, "{} 创建音量的线程处理数据完成,队列大小: {}", 
-        //     m_logBase, m_queueResultData->QueueSize());
+        // std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
+        // std::chrono::microseconds duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - rtEndTime);
+        // SPDLOG_LOGGER_DEBUG(m_logger, "{} 计算1秒的音量包完成,耗时: {} 微秒", m_logBase, duration.count());
     }
     /* 清理数据 */
     clearData();
@@ -253,6 +337,8 @@ bool CreateDBThread::initData()
     m_queueAudioData.clearQueue();
     m_queueAudioData.setQueueCapacity(queueSize);
 
+    m_queueRealTimeData.setQueueCapacity(queueSize);
+
     m_sampleRate = GInfo.sampleRate();          /* 采样率 */
     m_numChannels = GInfo.numChannels();        /* 声道数 */
     m_bitsPerSample = GInfo.bitsPerSample();    /* 每个采样点的位数 */
@@ -342,3 +428,60 @@ bool CreateDBThread::CreateDBPhase(AudioSrcData* audioData)
 }
 
 
+/* 计算实时音量值 */
+bool CreateDBThread::calculateRealTimeVolume()
+{
+    /* 一秒钟平分30个音量值,每个音量值占有的长度 */
+    const int oneDBSize = m_oneDBLengthOfSrcData;
+
+    while(!m_queueRealTimeData.isEmpty())
+    {
+        /* 取出一个数据,没有数据则阻塞住 */
+        AudioSrcData* audioData = m_queueRealTimeData.front_pop_noBlock();
+        if(audioData == nullptr)
+        {
+            continue;
+        }
+        
+        /* 计算音量和反相的计算类 */
+        CAudio2ChanCorrelator audioCor;
+        StAudioNum audioInfo;
+        audioInfo.roadInfo = m_threadInfo.cardRoadInfo; // 设置通道信息
+        audioInfo.nTotal = m_singleDataLength;
+
+        short* pData = reinterpret_cast<short*>(audioData->pData);
+        // 采样点最大值
+        short sMaxA, sMaxB, sRMSA, sRMSB;
+        audioCor.CorrelateChunks(pData, pData + 1, oneDBSize, &sMaxA, &sMaxB, &sRMSA, &sRMSB, audioInfo);
+        
+        /* 这里乘2是要增加两个通道的数据大小 */
+        int leftDB = calculateDB(sMaxA);
+        int rightDB = 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();
+        if(iReversed > REVERSED_MAX_VALUE || iReversed < REVERSED_MIN_VALUE)
+        {
+            iReversed = 0;
+        }
+        // 和反相阈值比较,来判定是否为反相
+        float dReversed = iReversed / 100.00;
+
+        OneDBData oneDBData;
+        oneDBData.leftDB = leftDB;
+        oneDBData.rightDB = rightDB;
+        oneDBData.phase = dReversed;
+        oneDBData.startTime = audioData->startTime;
+        oneDBData.endTime = audioData->endTime;
+        /* 保存结果 */
+        std::lock_guard<std::mutex> lock(m_mutexRealTimeResult);
+        m_listRealTimeResult.push_back(oneDBData);
+    }
+
+    return true;
+}
+
+

+ 18 - 7
Server/ThreadRecord/CreateDBThread.h

@@ -5,10 +5,10 @@
 #include "BaseRecordThread.h"
 #include "RingQueue.hpp"
 #include "RingQueueManualMutex.hpp"
-
+#include "AudioData.h"
 
 struct AudioSrcData;
-class OneSecondData;
+
 
 /**
  * 这个功能线程计算出音量的线程,给音量报警线程使用
@@ -34,6 +34,11 @@ public:
     /* 获取最新的结果,让整个环形队列相等 */
     bool getLatestResult(RingQueueManualMutex<OneSecondData*>& resultQueue);
 
+    /* 获取最新的音量包结果,count等于负数是获取所有数据,等于正数,如果暂时没有这么多数据,则返回false */
+    bool getLatestRealTimeResult(std::list<OneDBData>& listData, int count = -1);
+    /* 获取一个最新音量值 */
+    bool getLatestRealTimeResult(OneDBData& resultData);
+
 private:
     /* 执行任务函数 */
     void task() override;
@@ -45,21 +50,27 @@ private:
     /* 计算音量和反相 */
     bool CreateDBPhase(AudioSrcData* audioData);
 
+    /* 计算实时音量值 */
+    bool calculateRealTimeVolume();
 
 private:
+
+    /* --------------------------- 正常音量值的数据 --------------------------- */
     /* 原始音频数据环形队列 */
     RingQueue<AudioSrcData*> m_queueAudioData;
 
-    // AudioSrcData* m_remainData = nullptr;   /* 不满一个队列元素的剩余数据,使用AudioSrcData来存储,方便管理 */
-
     /* 计算相关的变量 */
     int m_oneDBLengthOfSrcData = 0;         /* 计算一个DB需要的原始音频数据的长度,单位:short */
     int m_singleDataLength = 0;             /* 一秒钟单声道数据长度,单位:字节 */
 
     OneSecondData* m_result = nullptr;      /* 存储每秒钟的音量和反相数据 */
-    // int m_queueAudioDataCapacity = 0;       /* 音频数据环形队列的容量,单位:秒 */
-    /* 存储结果 */
-    RingQueueManualMutex<OneSecondData*>* m_queueResultData = nullptr; /* 计算结果环形队列,存储每秒钟的音量和反相数据 */
+    /* 计算结果环形队列,存储每秒钟的音量和反相数据 */
+    RingQueueManualMutex<OneSecondData*>* m_queueResultData = nullptr;
+
+    /* --------------------------- 正常音量值的数据 --------------------------- */
+    RingQueue<AudioSrcData*> m_queueRealTimeData;   /* 存储小于1秒的音频数据,应该是33m的 */
+    std::mutex m_mutexRealTimeResult;               /* 实时结果的互斥锁 */
+    std::list<OneDBData> m_listRealTimeResult;          /* 实时音量数据 */
 };
 
 

+ 15 - 0
show2/main.cpp

@@ -5,6 +5,7 @@
 #include <qapplication.h>
 #include <qchar.h>
 #include <QDebug>
+#include <QTimer>
 
 
 #include "spdlog/spdlog.h"
@@ -26,6 +27,20 @@ int main(int argc, char *argv[])
     Widget w;
     w.show();
 
+    // std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
+    // QTimer timer;
+    // timer.setInterval(16);
+    // timer.setSingleShot(false);
+    // timer.setTimerType(Qt::PreciseTimer);
+    // QObject::connect(&timer, &QTimer::timeout, [&]() 
+    // {
+    //     std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+    //     std::chrono::milliseconds duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - startTime);
+    //     SPDLOG_INFO("Timer triggered, elapsed time: {} ms", duration.count());
+    //     startTime = now; // 重置开始时间
+    // });
+
+    // timer.start();
 
     return a.exec();
 }

+ 4 - 3
show3/main.cpp

@@ -12,7 +12,8 @@ void test1();
 void test2();
 void test3();
 
-int main() {
+int main() 
+{
 
     // 初始化Python解释器
     // signalstats_wrapper::initialize();
@@ -23,8 +24,8 @@ int main() {
     // std::this_thread::sleep_for(std::chrono::seconds(5));
     
     
-    test3();
-    std::this_thread::sleep_for(std::chrono::seconds(2)); // 等待任务执行
+    // test3();
+    // std::this_thread::sleep_for(std::chrono::seconds(2)); // 等待任务执行
 
     // signalstats_wrapper::finalize();