فهرست منبع

V0.5.6
1、修复了RTP监听时客户端断开再连接没有声音的问题
2、修复了分派数据的线程分派的时间不准确的问题
3、新增了录音线程读取文件进行debug的功能
4、修复了一致性报警录制报警音频失败的问题
5、修复了一致性报警写入数据库失败的问题

Apple 1 ماه پیش
والد
کامیت
57b7debb38

+ 10 - 4
RTPServer/RtpOneRoadThread.cpp

@@ -90,12 +90,14 @@ bool RTPOneRoadThread::addUdpSession(const RtpSendClientInfo_t& udpSession)
     {
         m_udpState = eUDPState::eUDP_Init;
         m_localIP = udpSession.localIP;
-        // m_localPort = udpSession.localPort;
     }
     
     std::lock_guard<std::mutex> lock(m_lockClients);
     m_listClients.append(udpSession);
 
+    /* 触发一次定时器槽函数,执行处理UDP状态的函数 */
+    emit signal_timerSendData();
+    
     return true;
 }
 
@@ -135,6 +137,9 @@ bool RTPOneRoadThread::removeUdpSession(QString clientIP, quint16 clientPort)
         m_udpState = eUDPState::eUDP_Closed;
         
         SPDLOG_LOGGER_DEBUG(m_logger, "{} UDP会话列表为空,不再接收音频原始数据", m_logBase);
+
+        /* 触发一次定时器槽函数,执行处理UDP状态的函数 */
+        emit signal_timerSendData();
     }
 
     return true;
@@ -154,6 +159,7 @@ void RTPOneRoadThread::task()
     m_sendTimer.setSingleShot(false); // 设置为循环定时器
     m_sendTimer.setInterval(10); // 每10毫秒发送一次数据
     QEventLoop::connect(&m_sendTimer, &QTimer::timeout, this, &RTPOneRoadThread::do_timerSendData);
+    connect(this, &RTPOneRoadThread::signal_timerSendData, this, &RTPOneRoadThread::do_timerSendData);
     m_sendTimer.start();
 
     m_isRunning.store(true); // 设置为运行状态
@@ -302,9 +308,9 @@ bool RTPOneRoadThread::sendData()
                 SPDLOG_LOGGER_ERROR(m_logger, "{} 发送数据失败: {}:{}", m_logBase, session.clientIP.toStdString(), session.clientPort);
             } else
             {
-                // SPDLOG_LOGGER_TRACE(m_logger, "{} 发送数据成功: {}:{}, 本地IP: {}:{}, 大小: {}", m_logBase, 
-                //         session.clientIP.toStdString(), session.clientPort, 
-                //         m_udpSocket->localAddress().toString().toStdString(), m_udpSocket->localPort(), bytesSent);
+            //     SPDLOG_LOGGER_TRACE(m_logger, "{} 发送数据成功: {}:{}, 本地IP: {}:{}, 大小: {}", m_logBase, 
+            //             session.clientIP.toStdString(), session.clientPort, 
+            //             m_udpSocket->localAddress().toString().toStdString(), m_udpSocket->localPort(), bytesSent);
             }
         }
         /* 发送完数据后,删除这个数据 */

+ 2 - 0
RTPServer/RtpOneRoadThread.h

@@ -49,6 +49,8 @@ public:
 signals:
     /* 一个UDP关闭了,通知RTP服务,释放掉了一个本地端口 */
     void signal_udpClosed(int soundCardNum, int roadNum);
+    /* 用来触发槽函数 do_timerSendData 用于立刻处理UDP状态  */
+    void signal_timerSendData();
 
 protected:
     /* 任务函数 */

+ 2 - 0
RTPServer/RtpServer.cpp

@@ -274,6 +274,8 @@ void RTPServer::handleLogin(RtpSendClientInfo_t& clientInfo)
     {
         return;
     }
+    /* 先断开槽函数的连接,防止多次连接 */
+    pThread->disconnect(pThread, &RTPOneRoadThread::signal_udpClosed, this, &RTPServer::do_udpClosed);
     connect(pThread, &RTPOneRoadThread::signal_udpClosed, this, &RTPServer::do_udpClosed);
     /* 将本地端口添加到心跳列表中 */
     RtpClientKey_t clientKey;

+ 102 - 1
SQL/ACAServer.sql

@@ -44,6 +44,7 @@ SELECT LAST_INSERT_ID() AS pkid;
 
 #同时插入两条报警信息
 -- 先插入主通道报警信息, 获取其主键 pkid
+BEGIN
 INSERT INTO tACAAlarmInfo (
     ItemID, ItemName, AlarmType, SoundCardNum, SoundCardName, SoundCardRoadNum, CompareRoadNum, CompareRoadName, CompareRoadType, 
     AlarmStartTime, AlarmEndTime, AlarmDuration, AlarmFilePath, FileAlarmStartPos)
@@ -51,7 +52,7 @@ VALUES (
     @itemID1, @itemName1, @alarmType1, @soundCardNum1, @soundCardName1, @soundCardRoadNum1, @compareRoadNum1, @compareRoadName1, @compareRoadType1, 
     @alarmStartTime1, @alarmEndTime1, @alarmDuration1, @alarmFilePath1, @fileAlarmStartPos1);
 -- 获取主通道报警信息的
-SELECT SCOPE_IDENTITY() AS pkid;
+SELECT MAX(PKID) INTO pkid FROM tACAAlarmInfo;
 -- 插入第二条报警信息,MainRoadPKID 就是上面获取的 pkid
 INSERT INTO tACAAlarmInfo (
     ItemID, ItemName, AlarmType, SoundCardNum, SoundCardName, SoundCardRoadNum, CompareRoadNum, CompareRoadName, CompareRoadType, 
@@ -60,4 +61,104 @@ VALUES (
     @itemID2, @itemName2, @alarmType2, @soundCardNum2, @soundCardName2, @soundCardRoadNum2, @compareRoadNum2, @compareRoadName2, @compareRoadType2,
     @alarmStartTime2, @alarmEndTime2, @alarmDuration2, @alarmFilePath2, @fileAlarmStartPos2, pkid);
 
+END;
+
+
+
+
+#创建达梦数据库存储过程
+CREATE OR REPLACE PROCEDURE ACAS_InsertTwoAlarmInfo(
+    itemID1 IN INT, itemName1 IN VARCHAR(100), alarmType1 IN INT,
+    soundCardNum1 IN INT, soundCardName1 IN VARCHAR(100), soundCardRoadNum1 IN INT,
+    compareRoadNum1 IN INT, compareRoadName1 IN VARCHAR(100), compareRoadType1 IN INT,
+    alarmStartTime1 IN DATETIME, alarmEndTime1 IN DATETIME, alarmDuration1 IN INT,
+    alarmFilePath1 IN VARCHAR(255), fileAlarmStartPos1 IN INT,
+    itemID2 IN INT, itemName2 IN VARCHAR(100), alarmType2 IN INT,
+    soundCardNum2 IN INT, soundCardName2 IN VARCHAR(100), soundCardRoadNum2 IN INT,
+    compareRoadNum2 IN INT, compareRoadName2 IN VARCHAR(100), compareRoadType2 IN INT,
+    alarmStartTime2 IN DATETIME, alarmEndTime2 IN DATETIME, alarmDuration2 IN INT,
+    alarmFilePath2 IN VARCHAR(255), fileAlarmStartPos2 IN INT
+)
+AS
+    pkid INT 2;
+BEGIN
+    INSERT INTO tACAAlarmInfo (
+        ItemID, ItemName, AlarmType, SoundCardNum, SoundCardName, SoundCardRoadNum, CompareRoadNum, CompareRoadName, CompareRoadType,
+        AlarmStartTime, AlarmEndTime, AlarmDuration, AlarmFilePath, FileAlarmStartPos
+    ) VALUES (
+        itemID1, itemName1, alarmType1, soundCardNum1, soundCardName1, soundCardRoadNum1, compareRoadNum1, compareRoadName1, compareRoadType1,
+        alarmStartTime1, alarmEndTime1, alarmDuration1, alarmFilePath1, fileAlarmStartPos1
+    );
+    pkid := SCOPE_IDENTITY();
+    INSERT INTO tACAAlarmInfo (
+        ItemID, ItemName, AlarmType, SoundCardNum, SoundCardName, SoundCardRoadNum, CompareRoadNum, CompareRoadName, CompareRoadType,
+        AlarmStartTime, AlarmEndTime, AlarmDuration, AlarmFilePath, FileAlarmStartPos, MainRoadPKID
+    ) VALUES (
+        itemID2, itemName2, alarmType2, soundCardNum2, soundCardName2, soundCardRoadNum2, compareRoadNum2, compareRoadName2, compareRoadType2,
+        alarmStartTime2, alarmEndTime2, alarmDuration2, alarmFilePath2, fileAlarmStartPos2, pkid
+    );
+END;
+
+# 调用存储过程
+CALL ACAS_InsertTwoAlarmInfo(
+    @itemID1, @itemName1, @alarmType1,
+    @soundCardNum1, @soundCardName1, @soundCardRoadNum1,
+    @compareRoadNum1, @compareRoadName1, @compareRoadType1,
+    @alarmStartTime1, @alarmEndTime1, @alarmDuration1,
+    @alarmFilePath1, @fileAlarmStartPos1,
+    @itemID2, @itemName2, @alarmType2,
+    @soundCardNum2, @soundCardName2, @soundCardRoadNum2,
+    @compareRoadNum2, @compareRoadName2, @compareRoadType2,
+    @alarmStartTime2, @alarmEndTime2, @alarmDuration2,
+    @alarmFilePath2, @fileAlarmStartPos2
+);
+
+"itemID1": 2,
+"itemName1": "two",
+"alarmType1": 4,
+"soundCardNum1": 1,
+"soundCardName1": "主通道",
+"soundCardRoadNum1": 0,
+"compareRoadNum1": 1,
+"compareRoadName1": "主通道",
+"compareRoadType1": 0,
+"alarmStartTime1": "2025-08-07 16:14:12",
+"alarmEndTime1": "2025-08-07 16:14:37",
+"alarmDuration1": 24,
+"alarmFilePath1": "/data/home/Apple/Work/11-ACAServer/RecordFile/AlarmWav/2025-08-07/CompareItemID_2/Road1_Consistency_20250807_161412-20250807_161437.wav",
+"fileAlarmStartPos1": 0,
+"itemID2": 2,
+"itemName2": "two",
+"alarmType2": 4,
+"soundCardNum2": 2,
+"soundCardName2": "第2通道",
+"soundCardRoadNum2": 0,
+"compareRoadNum2": 2,
+"compareRoadName2": "第2通道",
+"compareRoadType2": 1,
+"alarmStartTime2": "2025-08-07 16:14:12",
+"alarmEndTime2": "2025-08-07 16:14:37",
+"alarmDuration2": 24,
+"alarmFilePath2": "/data/home/Apple/Work/11-ACAServer/RecordFile/AlarmWav/2025-08-07/CompareItemID_2/Road2_Consistency_20250807_161412-20250807_161437.wav",
+"fileAlarmStartPos2": 0
+
+"EQM_CESHI"."ACAS_InsertTwoAlarmInfo"(
+    :"itemID1", :"itemName1", :"alarmType1", :"soundCardNum1", :"soundCardName1", :"soundCardRoadNum1", :"compareRoadNum1", :"compareRoadName1", :"compareRoadType1", 
+    :"alarmStartTime1", :"alarmEndTime1",
+     :"alarmDuration1", :"alarmFilePath1", 
+     :"fileAlarmStartPos1", 
+     :"itemID2", 
+     :"itemName2", :"alarmType2", :"soundCardNum2",
+      :"soundCardName2", :"soundCardRoadNum2", :"compareRoadNum2", 
+      :"compareRoadName2", :"compareRoadType2", :"alarmStartTime2",
+       :"alarmEndTime2", :"alarmDuration2", :"alarmFilePath2", :"fileAlarmStartPos2");
+"EQM_CESHI"."ACAS_InsertTwoAlarmInfo"(
+    2, 'two', 4, 1, '主通道', 0, 1, '主通道', 0, '2025-08-07 16:14:12', '2025-08-07 16:14:37',
+    24, '/data/home/Apple/Work/11-ACAServer/RecordFile/AlarmWav/2025-08-07/CompareItemID_2/Road1_Consistency_20250807_161412-20250807_161437.wav', 0,
+    2, 'two', 4, 2, '第2通道', 0, 2, '第2通道', 1, '2025-08-07 16:14:12', '2025-08-07 16:14:37', 24, 
+    '/data/home/Apple/Work/11-ACAServer/RecordFile/AlarmWav/2025-08-07/CompareItemID_2/Road2_Consistency_20250807_161412-20250807_161437.wav', 0
+);
+
+"EQM_CESHI"."ACAS_InsertTwoAlarmInfo"(
+    2, 'two', 4, 1, '主通道', 0, 1, '主通道', 0, '2025-08-07 16:14:12', 
 

+ 81 - 0
SQL/ACAServer.sqlbook

@@ -0,0 +1,81 @@
+-- SQLBook: Code
+#写入报警数据库的存储过程
+
+-- 达梦数据库
+CREATE OR REPLACE PROCEDURE ACAS_InsertTwoAlarmInfo(
+    itemID1 IN INT, itemName1 IN VARCHAR(100), alarmType1 IN INT,
+    soundCardNum1 IN INT, soundCardName1 IN VARCHAR(100), soundCardRoadNum1 IN INT,
+    compareRoadNum1 IN INT, compareRoadName1 IN VARCHAR(100), compareRoadType1 IN INT,
+    alarmStartTime1 IN DATETIME, alarmEndTime1 IN DATETIME, alarmDuration1 IN INT,
+    alarmFilePath1 IN VARCHAR(255), fileAlarmStartPos1 IN INT,
+    itemID2 IN INT, itemName2 IN VARCHAR(100), alarmType2 IN INT,
+    soundCardNum2 IN INT, soundCardName2 IN VARCHAR(100), soundCardRoadNum2 IN INT,
+    compareRoadNum2 IN INT, compareRoadName2 IN VARCHAR(100), compareRoadType2 IN INT,
+    alarmStartTime2 IN DATETIME, alarmEndTime2 IN DATETIME, alarmDuration2 IN INT,
+    alarmFilePath2 IN VARCHAR(255), fileAlarmStartPos2 IN INT
+)
+AS
+    pkid INT;
+BEGIN
+    INSERT INTO tACAAlarmInfo (
+        ItemID, ItemName, AlarmType, SoundCardNum, SoundCardName, SoundCardRoadNum, CompareRoadNum, CompareRoadName, CompareRoadType,
+        AlarmStartTime, AlarmEndTime, AlarmDuration, AlarmFilePath, FileAlarmStartPos
+    ) VALUES (
+        itemID1, itemName1, alarmType1, soundCardNum1, soundCardName1, soundCardRoadNum1, compareRoadNum1, compareRoadName1, compareRoadType1,
+        alarmStartTime1, alarmEndTime1, alarmDuration1, alarmFilePath1, fileAlarmStartPos1
+    );
+    SELECT MAX(PKID) INTO pkid FROM tACAAlarmInfo;
+    INSERT INTO tACAAlarmInfo (
+        ItemID, ItemName, AlarmType, SoundCardNum, SoundCardName, SoundCardRoadNum, CompareRoadNum, CompareRoadName, CompareRoadType,
+        AlarmStartTime, AlarmEndTime, AlarmDuration, AlarmFilePath, FileAlarmStartPos, MainRoadPKID
+    ) VALUES (
+        itemID2, itemName2, alarmType2, soundCardNum2, soundCardName2, soundCardRoadNum2, compareRoadNum2, compareRoadName2, compareRoadType2,
+        alarmStartTime2, alarmEndTime2, alarmDuration2, alarmFilePath2, fileAlarmStartPos2, pkid
+    );
+END;
+
+# 调用存储过程
+CALL ACAS_InsertTwoAlarmInfo(
+    @itemID1, @itemName1, @alarmType1,
+    @soundCardNum1, @soundCardName1, @soundCardRoadNum1,
+    @compareRoadNum1, @compareRoadName1, @compareRoadType1,
+    @alarmStartTime1, @alarmEndTime1, @alarmDuration1,
+    @alarmFilePath1, @fileAlarmStartPos1,
+    @itemID2, @itemName2, @alarmType2,
+    @soundCardNum2, @soundCardName2, @soundCardRoadNum2,
+    @compareRoadNum2, @compareRoadName2, @compareRoadType2,
+    @alarmStartTime2, @alarmEndTime2, @alarmDuration2,
+    @alarmFilePath2, @fileAlarmStartPos2
+);
+
+#GBase版本的存储过程
+CREATE PROCEDURE ACAS_InsertTwoAlarmInfo(
+    IN itemID1 INT, IN itemName1 VARCHAR(100), IN alarmType1 INT,
+    IN soundCardNum1 INT, IN soundCardName1 VARCHAR(100), IN soundCardRoadNum1 INT,
+    IN compareRoadNum1 INT, IN compareRoadName1 VARCHAR(100), IN compareRoadType1 INT,
+    IN alarmStartTime1 DATETIME, IN alarmEndTime1 DATETIME, IN alarmDuration1 INT,
+    IN alarmFilePath1 VARCHAR(255), IN fileAlarmStartPos1 INT,
+    IN itemID2 INT, IN itemName2 VARCHAR(100), IN alarmType2 INT,
+    IN soundCardNum2 INT, IN soundCardName2 VARCHAR(100), IN soundCardRoadNum2 INT,
+    IN compareRoadNum2 INT, IN compareRoadName2 VARCHAR(100), IN compareRoadType2 INT,
+    IN alarmStartTime2 DATETIME, IN alarmEndTime2 DATETIME, IN alarmDuration2 INT,
+    IN alarmFilePath2 VARCHAR(255), IN fileAlarmStartPos2 INT
+)
+DEFINE pkid INT;
+BEGIN
+    INSERT INTO tACAAlarmInfo (
+        ItemID, ItemName, AlarmType, SoundCardNum, SoundCardName, SoundCardRoadNum, CompareRoadNum, CompareRoadName, CompareRoadType,
+        AlarmStartTime, AlarmEndTime, AlarmDuration, AlarmFilePath, FileAlarmStartPos
+    ) VALUES (
+        itemID1, itemName1, alarmType1, soundCardNum1, soundCardName1, soundCardRoadNum1, compareRoadNum1, compareRoadName1, compareRoadType1,
+        alarmStartTime1, alarmEndTime1, alarmDuration1, alarmFilePath1, fileAlarmStartPos1
+    );
+    LET pkid = dbinfo('sqlca.sqlerrd1');
+    INSERT INTO tACAAlarmInfo (
+        ItemID, ItemName, AlarmType, SoundCardNum, SoundCardName, SoundCardRoadNum, CompareRoadNum, CompareRoadName, CompareRoadType,
+        AlarmStartTime, AlarmEndTime, AlarmDuration, AlarmFilePath, FileAlarmStartPos, MainRoadPKID
+    ) VALUES (
+        itemID2, itemName2, alarmType2, soundCardNum2, soundCardName2, soundCardRoadNum2, compareRoadNum2, compareRoadName2, compareRoadType2,
+        alarmStartTime2, alarmEndTime2, alarmDuration2, alarmFilePath2, fileAlarmStartPos2, pkid
+    );
+END PROCEDURE;

+ 1 - 1
Server/DataStruct/AudioData.cpp

@@ -37,7 +37,7 @@ bool modifyFileName(const QString& fileName, const QString& newFileName)
     }
     if(!QFile::rename(fileName, newFileName))
     {
-        SPDLOG_ERROR("修改文件名失败: {} -> {}", fileName.toStdString(), newFileName.toStdString());
+        // SPDLOG_ERROR("修改文件名失败: {} -> {}", fileName.toStdString(), newFileName.toStdString());
         return false;
     }
 

+ 15 - 9
Server/ThreadCalculate/ConsistencyCompareThread.cpp

@@ -71,7 +71,7 @@ bool ConsistencyCompareThread::compareConsistencyData()
     if(m_wavFilePath1 == m_prevWavFilePath1 || m_wavFilePath2 == m_prevWavFilePath2)
     {
         // SPDLOG_LOGGER_INFO(m_logger, "{} 检测到文件路径未变化", m_logBase);
-        return true;
+        return false;
     }
     /*--------------------------------------------------------------
      * 开始比对计算,并保存计算结果
@@ -109,7 +109,7 @@ void ConsistencyCompareThread::task()
 
     SPDLOG_LOGGER_INFO(m_logger, " ★ {} 一致性对比线程(调用动态库)开始运行  ", m_logBase);
     
-    std::chrono::system_clock::time_point startTime = std::chrono::system_clock::now();
+    // std::chrono::system_clock::time_point startTime = std::chrono::system_clock::now();
     int nCompareCount = 0; // 计算次数
     bool isConsistency = true;
     while(m_isRunning)
@@ -139,27 +139,32 @@ void ConsistencyCompareThread::task()
             continue;
         }
         /* 计算一致性 */
-        compareConsistencyData();
+        if(!compareConsistencyData())
+        {
+            /* 没有新数据或者计算失败,继续等待 */
+            continue;
+        }
 
         /* 模拟不一致报警,启动检测五次开始报警,报警5次取消报警,间隔5次继续报警 */
         if(isConsistency)
         {
-            if(nCompareCount > 5)
+            if(nCompareCount > 3)
             {
                 isConsistency = false;
                 m_isConsistency = false;
                 m_isConsistencyWarning = true;
-                
+                nCompareCount = 0;
             }
         }else {
-            if(nCompareCount > 5)
+            if(nCompareCount > 3)
             {
                 isConsistency = true;
                 m_isConsistency = true;
                 m_isConsistencyWarning = false;
-
+                nCompareCount = 0;
             }
         }
+        nCompareCount++;
 
         /* 保存结果 */
         saveAlarmInfo();
@@ -342,7 +347,7 @@ void ConsistencyCompareThread::saveAlarmInfo()
             /* 之前在一致性报警中,这次一致,结束不一致性报警 */
             m_alarmConsistencyMain.isAlarm = false;
             m_alarmConsistencySub.isAlarm = false;
-            /* 结束时间向推1秒 */
+            /* 结束时间向推1秒 */
             m_alarmConsistencyMain.EndTime = m_wavFilePath1.endDateTime.addSecs(1);
             m_alarmConsistencySub.EndTime = m_wavFilePath2.endDateTime.addSecs(1);
             /* 结束录制报警音频 */
@@ -353,7 +358,8 @@ void ConsistencyCompareThread::saveAlarmInfo()
             AlarmManager.addAlarmInfo(m_alarmConsistencyMain, m_alarmConsistencySub);
 
             
-            SPDLOG_LOGGER_INFO(m_logger, "{}: 一致性报警结束", m_logBase);
+            SPDLOG_LOGGER_INFO(m_logger, "{}: 一致性报警结束,结束时间: {}", m_logBase, 
+                m_wavFilePath1.endDateTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
             /* 清除报警信息 */
             m_alarmConsistencyMain = AlarmInfo_t();
             m_alarmConsistencySub = AlarmInfo_t();

+ 15 - 17
Server/ThreadManager/ThreadAlarmManager.cpp

@@ -88,34 +88,32 @@ void ThreadAlarmManager::task()
         {
             /* 普通的报警数据写入数据库 */
             std::lock_guard<std::mutex> lock(m_mutexListAlarm);
-            if(m_listAlarm.empty())
+            if(!m_listAlarm.empty())
             {
-                continue; // 如果没有报警信息,继续循环
-            }
-            if(!m_fromWebAPI.insertAlarmInfo(m_listAlarm))
-            {
-                SPDLOG_LOGGER_ERROR(m_logger, "写入报警信息失败");
+                if(!m_fromWebAPI.insertAlarmInfo(m_listAlarm))
+                {
+                    SPDLOG_LOGGER_ERROR(m_logger, "写入报警信息失败");
+                }
+                /* 清空报警列表 */
+                m_listAlarm.clear();
             }
-            /* 清空报警列表 */
-            m_listAlarm.clear();
         }
 
         {
             /* 写入一致性报警信息 */
             std::lock_guard<std::mutex> lock(m_mutexListAlarmConsistency);
-            if(m_listAlarmConsistency.empty())
-            {
-                continue; // 如果没有一致性报警信息,继续循环
-            }
-            for(const auto& alarmPair : m_listAlarmConsistency)
+            if(!m_listAlarmConsistency.empty())
             {
-                if(!m_fromWebAPI.insertConsistencyAlarmInfo(alarmPair.first, alarmPair.second))
+                for(const auto& alarmPair : m_listAlarmConsistency)
                 {
-                    SPDLOG_LOGGER_ERROR(m_logger, "写入一致性报警信息失败");
+                    if(!m_fromWebAPI.insertConsistencyAlarmInfo(alarmPair.first, alarmPair.second))
+                    {
+                        SPDLOG_LOGGER_ERROR(m_logger, "写入一致性报警信息失败");
+                    }
                 }
+                /* 清空报警信息 */
+                m_listAlarmConsistency.clear();
             }
-            /* 清空报警信息 */
-            m_listAlarmConsistency.clear();
         }
 
     }

+ 62 - 38
Server/ThreadRecord/AssignSrcDataThread.cpp

@@ -148,14 +148,14 @@ void AssignSrcDataThread::task()
         /* 判断数据是否满足1s大小 */
         if(!isFullOneSecondData())
         {
-            continue; // 如果不满足1s大小,则继续等待
+            continue;
         }
         /* 处理数据,将其拼接成1s的数据 */
         processData();
 
-        /* 处理数据时间戳,计算开始时间 */
-        m_dispatchSrcData->startTime = previTime(m_dispatchSrcData->endTime, m_dispatchSrcData->dataSize);
-
+        // SPDLOG_LOGGER_TRACE(m_logger, "{} 开始分发数据,开始时间: {}, 结束时间: {}, 大小: {}", 
+        //         m_logBase, m_dispatchSrcData->startTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), 
+        //         m_dispatchSrcData->endTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), m_dispatchSrcData->dataSize);
         /*------------------------------------------------------------------------
          * 分派常规数据
          *------------------------------------------------------------------------*/
@@ -205,11 +205,11 @@ void AssignSrcDataThread::clearData()
         delete m_dispatchSrcData;
         m_dispatchSrcData = nullptr;
     }
-    if(m_pCurrentSrcData != nullptr)
-    {
-        delete m_pCurrentSrcData;
-        m_pCurrentSrcData = nullptr;
-    }
+    // if(m_pCurrentSrcData != nullptr)
+    // {
+    //     delete m_pCurrentSrcData;
+    //     m_pCurrentSrcData = nullptr;
+    // }
     
     
 }
@@ -300,7 +300,7 @@ bool AssignSrcDataThread::isFullOneSecondData() const
 {
     // QReadLocker locker(m_pRwLock);
     /* 判断缓存中的数据是否满足1秒大小 */
-    if(m_listDataSize + m_remainingDataSize >= m_oneSecondSize)
+    if(m_listDataSize + m_remainingData.size() >= m_oneSecondSize)
     {
         return true;
     }
@@ -312,51 +312,75 @@ bool AssignSrcDataThread::isFullOneSecondData() const
  * 将其拆分成1秒的数据,有一秒的数据后就退出循环,分派给其他线程 */
 bool AssignSrcDataThread::processData()
 {
-    
+    /* 处理数据 */
     m_dispatchSrcData->clear();
     while(true)
     {
-        if(m_remainingDataSize > 0)
+        if(m_remainingData.size() > 0)
         {
-            /* 如果剩余数据还有数据,则继续处理 */
-            int32_t nowIndex = m_pCurrentSrcData->dataSize - m_remainingDataSize; // 当前剩余数据的起始位置
-            auto copySize = m_dispatchSrcData->appendData(m_pCurrentSrcData->pData + nowIndex, m_remainingDataSize);
-            /* 更新结束时间 */
-            if(copySize == m_remainingDataSize)
+            /* 拷贝剩余数据 */
+            int32_t copySize = m_dispatchSrcData->appendData(m_remainingData.data(), m_remainingData.size());
+            if(copySize < m_remainingData.size())
             {
-                /* 如果拷贝的大小等于剩余数据大小,说明当前的数据缓冲区数据已经用完了,则直接使用当前数据的结束时间
-                 * 并删除这个缓冲区 */
-                m_dispatchSrcData->endTime = m_pCurrentSrcData->endTime;
-                delete m_pCurrentSrcData;
-                m_pCurrentSrcData = nullptr;
+                /* 剩余数据没拷贝完,可能已经满足一次了 */
+                m_remainingData = m_remainingData.mid(copySize);
+                m_dispatchSrcData->endTime = previTime(m_lastDataEndTime, m_remainingData.size());
+                m_dispatchSrcData->startTime = previTime(m_dispatchSrcData->endTime, m_dispatchSrcData->dataSize);
             }else {
-                /* 如果拷贝的大小小于剩余数据大小,则计算结束时间 */
-                m_dispatchSrcData->endTime = previTime(m_pCurrentSrcData->endTime, m_remainingDataSize - copySize);
+                /* 剩余数据拷贝完了,清空剩余数据 */
+                m_remainingData.clear();
+                m_dispatchSrcData->endTime = m_lastDataEndTime;
+                m_dispatchSrcData->startTime = previTime(m_dispatchSrcData->endTime, m_dispatchSrcData->dataSize);
+            }
+            if(m_dispatchSrcData->isFull())
+            {
+                /* 如果已经满足1秒大小,则退出循环 */
+                break;
             }
-            /* 更新剩余数据大小 */
-            m_remainingDataSize -= copySize;
-        } else 
+        }else 
         {
-            /* 取出最新的一个数据,这里只取出数据,不进行数据拷贝,数据处理进入下一个循环后再处理 */
-            m_pCurrentSrcData = m_listAudioSrcData.front();
+            /* 没有剩余数据了,拷贝全新的数据 */
+            auto pData = m_listAudioSrcData.front();
             m_listAudioSrcData.pop_front();
-            if(m_pCurrentSrcData == nullptr)
+            // SPDLOG_LOGGER_TRACE(m_logger, "{} 一条数据 大小: {}, 时间: {}", 
+            //     m_logBase, pData->dataSize, pData->endTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString());
+            if(pData == nullptr)
+            {
+                continue;
+            }
+            int copySize = m_dispatchSrcData->appendData(pData->pData, pData->dataSize);
+            if(m_dispatchSrcData->isFull())
             {
+                /* 判断有无剩余数据 */
+                if(copySize < pData->dataSize)
+                {
+                    m_remainingData = QByteArray(pData->pData + copySize, pData->dataSize - copySize);
+                    m_lastDataEndTime = pData->endTime;
+                } else {
+                    m_remainingData.clear();
+                    m_lastDataEndTime = QDateTime();
+                }
+                /* 更新结束时间 */
+                m_dispatchSrcData->endTime = pData->endTime;
+                /* 删除数据 */
+                delete pData;
+                pData = nullptr;
+                m_listDataSize -= copySize;
                 break;
             }
-            /* 更新队列中剩余的数据大小 */
-            m_listDataSize -= m_pCurrentSrcData->dataSize;
-            /* 更新剩余数据的大小 */
-            m_remainingDataSize = m_pCurrentSrcData->dataSize;
-        }
-        if(m_dispatchSrcData->isFull())
-        {
-            break;
+            delete pData;
+            pData = nullptr;
+            m_listDataSize -= copySize;
         }
     }
+
     /* 更新数据的开始时间 */
     m_dispatchSrcData->startTime = previTime(m_dispatchSrcData->endTime, m_dispatchSrcData->dataSize);
 
+    // SPDLOG_LOGGER_TRACE(m_logger, "{} 一秒的数据拼接完成, 开始时间: {}, 结束时间: {}, 大小: {}", 
+    //             m_logBase, m_dispatchSrcData->startTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), 
+    //             m_dispatchSrcData->endTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), m_dispatchSrcData->dataSize);
+
     return true;
 }
 

+ 6 - 4
Server/ThreadRecord/AssignSrcDataThread.h

@@ -66,7 +66,7 @@ private:
     /* 发送原始数据到Rtp中,实时发送,有新的就发送 */
     inline void sendSrcDataToRtp(const AudioSrcData& srcData);
 
-    
+
 private:
     /* 条件变量 */
     std::atomic_bool m_isDataUpdate = false;            /* 数据更新标志,数据更新时设置为true */
@@ -76,12 +76,14 @@ private:
     /* ---------------------- 数据缓存列表 ---------------------- */
     // QReadWriteLock m_pRwLock;                           /* 读写锁,保护数据的读写 */
     QList<AudioSrcData*> m_listAudioSrcData;            /* 数据缓存列表,这里使用QList,可以使用[]运算符 */
-    int32_t m_listDataSize = 0;                         /* 缓存中的数据是否满1秒大小 */
+    int32_t m_listDataSize = 0;                         /* 缓存中的数据大小 */
 
     AudioSrcData* m_dispatchSrcData = nullptr;          /* 分发的数据,1秒大小 */
 
-    AudioSrcData* m_pCurrentSrcData = nullptr;          /* 当前处理的数据 */
-    int32_t m_remainingDataSize = 0;                    /* 当前的AudioSrcData剩余可用数据的大小 */
+    // AudioSrcData* m_pCurrentSrcData = nullptr;          /* 当前处理的数据 */
+    // int32_t m_remainingDataSize = 0;                    /* 当前的AudioSrcData剩余可用数据的大小 */
+    QByteArray m_remainingData;                         /* 当前剩余数据的字节数组 */
+    QDateTime m_lastDataEndTime;                        /* 上次数据的结束时间 */
 
     /* ---------------------- 录音线程指针 ---------------------- */
     RecordThread* m_pThreadRecord = nullptr;            /* 录音线程 */

+ 9 - 3
Server/ThreadRecord/CreateRecordFileThread.cpp

@@ -364,6 +364,8 @@ bool CreateRecordFileThread::writeLongRecordFile()
     if(modifyFileName(m_wavFileName, newFileName))
     {
         m_wavFileName = newFileName;
+    }else {
+        SPDLOG_LOGGER_ERROR(m_logger, "{} 修改文件名失败: {} -> {}", m_logBase, m_wavFileName.toStdString(), newFileName.toStdString());
     }
     
     /* 判断是否过了整点 */
@@ -579,7 +581,7 @@ void CreateRecordFileThread::writeAlarmFile()
     const int newAlarmSeconds = 10;
     /* 新文件,从报警时间往前推10秒写入 */
     std::list<AudioSrcData*> newDataList;
-    /* 给已经写入的问价使用 */
+    /* 已经打开的文件写入数据 */
     std::list<AudioSrcData*> dataList;
     {
         /* 先判断环形队列中数据是否足够的秒数,不一定是每一秒都会写的 */
@@ -616,6 +618,7 @@ void CreateRecordFileThread::writeAlarmFile()
         }
     }
 
+    /* 创建新文件并写入数据 */
     std::lock_guard<std::mutex> lock(m_mutexAlarmFile);
     /* 将数据循环写入到文件中 */
     for(auto& alarmInfo : m_mapAlarmFile)
@@ -668,12 +671,15 @@ void CreateRecordFileThread::writeAlarmFile()
         AlarmValue_t& value = it->second;
         if(value.state == eRecordState::eAlarm_Stopped)
         {
-            /* 修改wav头文件,修改入的数据大小 */
+            /* 修改wav头文件,修改入的数据大小 */
             value.wavHeader.setDataSize(value.writtenSize);
             value.wavHeader.calculateDerivedFields();
             modifyWavFileHeader(value.fileName, value.wavHeader);
             /* 已经结束的报警,修改文件名 */
-            modifyFileName(value.fileName, value.fileNameEnd);
+            if(!modifyFileName(value.fileName, value.fileNameEnd))
+            {
+                SPDLOG_LOGGER_ERROR(m_logger, "修改文件名失败: {} -> {}", value.fileName.toStdString(), value.fileNameEnd.toStdString());
+            }
             /* 移除这个报警 */
             it = m_mapAlarmFile.erase(it);
         } else {

+ 36 - 24
Server/ThreadRecord/CreateWAVThread.cpp

@@ -49,11 +49,13 @@ bool CreateWAVThread::setData(const AudioSrcData& srcData)
             delete oldData;
             oldData = nullptr;
         }
-        m_queueWavSrcData.push(newData1);
-    } else 
-    {
-        m_queueWavSrcData.push(newData1);
     }
+    m_queueWavSrcData.push(newData1);
+
+    // SPDLOG_LOGGER_TRACE(m_logger, "{} 新的音频数据加入队列,开始时间: {}, 结束时间: {}, 大小: {}", 
+    // m_logBase, newData1->startTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), 
+    // newData1->endTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), newData1->dataSize);
+
     
 
     /* -------------------------- 入队LeftRight环形队列 ---------------------------- */
@@ -153,19 +155,6 @@ void CreateWAVThread::task()
             continue;
         }
 
-        /* 将文件名加入到新的队列中,给对比线程使用 */
-        WavFilePath wavFilePath;
-        wavFilePath.fileName = m_newFileName;
-        wavFilePath.startDateTime = m_newFileStartTime;
-        m_queueWavFileName->mutex.lock();
-        if(m_queueWavFileName->isFull())
-        {
-            auto wavFile = m_queueWavFileName->front_pop();
-            m_listDeleteFile.push_back(wavFile);
-        }
-        m_queueWavFileName->push(wavFilePath);
-        m_queueWavFileName->mutex.unlock();
-
         /*------------------------------------------------------------------------
          * 删除多余的文件,保留最新的60个文件
          *------------------------------------------------------------------------*/
@@ -267,8 +256,9 @@ void CreateWAVThread::clearData()
 bool CreateWAVThread::createWAVFile(int secondCount)
 {
     // SPDLOG_LOGGER_DEBUG(m_logger, "{} 开始生成WAV文件,秒数: {}", m_logBase, secondCount);
-    m_newFileName.clear();
-    m_newFileStartTime = QDateTime();
+    QString newFileName;
+    QDateTime newFileStartTime;
+    QDateTime newFileEndTime;
     /* 生成wav文件名 */
     AudioSrcData* audioData = m_queueWavSrcData.front();
     if(audioData == nullptr )
@@ -276,9 +266,10 @@ bool CreateWAVThread::createWAVFile(int secondCount)
         SPDLOG_LOGGER_WARN(m_logger, "{} 从环形队列中取出数据失败!", m_logBase);
         return false;
     }
+    newFileStartTime = audioData->startTime; // 获取开始时间
     QString strFileName = QString("WAV_%1-%2_%3.wav")
         .arg(m_threadInfo.cardRoadInfo.nSoundCardNum).arg(m_threadInfo.cardRoadInfo.roadInfo.nRoadNum)
-        .arg(audioData->startTime.toString("yyyyMMdd_hhmmss"));
+        .arg(newFileStartTime.toString("yyyyMMdd_hhmmss"));
     QString fileName = m_wavDir.filePath(strFileName);
 
     // SPDLOG_LOGGER_DEBUG(m_logger, "{} 开始打开文件", m_logBase);
@@ -299,7 +290,7 @@ bool CreateWAVThread::createWAVFile(int secondCount)
     tmpHeader.calculateDerivedFields();
     wavFile.write(reinterpret_cast<const char*>(&tmpHeader), sizeof(WavHeader));
 
-    // SPDLOG_LOGGER_DEBUG(m_logger, "{} 开始写入音频数据", m_logBase);
+    SPDLOG_LOGGER_DEBUG(m_logger, "{} 开始写入音频数据,当前队列大小: {}", m_logBase, m_queueWavSrcData.QueueSize());
     /* 写入音频数据 */
     for(int i = 0; i < secondCount; ++i)
     {
@@ -310,15 +301,36 @@ bool CreateWAVThread::createWAVFile(int secondCount)
             continue;
         }
         wavFile.write(data->pData, data->dataSize);
+        newFileEndTime = data->endTime;
+        // SPDLOG_LOGGER_TRACE(m_logger, "{} 写入音频数据,开始时间: {}, 结束时间: {}, 大小: {}", 
+        //     m_logBase, data->startTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), 
+        //     data->endTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), data->dataSize);
+        
+        /* 删除数据 */
         delete data;
         data = nullptr;
     }
     wavFile.close();
 
-    m_newFileName = fileName.toStdString();
-    m_newFileStartTime = audioData->startTime;
+    /* 将文件名加入到新的队列中,给对比线程使用 */
+    WavFilePath wavFilePath;
+    wavFilePath.fileName = fileName.toStdString();;
+    wavFilePath.startDateTime = newFileStartTime;
+    wavFilePath.endDateTime = newFileEndTime;
+
+    m_queueWavFileName->mutex.lock();
+    if(m_queueWavFileName->isFull())
+    {
+        auto wavFile = m_queueWavFileName->front_pop();
+        m_listDeleteFile.push_back(wavFile);
+    }
+    m_queueWavFileName->push(wavFilePath);
+    m_queueWavFileName->mutex.unlock();
 
-    // SPDLOG_LOGGER_DEBUG(m_logger, "{} 数据写入完成", m_logBase);
+    // SPDLOG_LOGGER_DEBUG(m_logger, "{} 数据写入完成,当前队列大小: {}", m_logBase, m_queueWavSrcData.QueueSize());
+    SPDLOG_LOGGER_DEBUG(m_logger, "{} 生成WAV文件成功: {}, 开始时间: {}, 结束时间: {}", 
+        m_logBase, wavFilePath.fileName, wavFilePath.startDateTime.toString("yyyy-MM-dd hh:mm:ss").toStdString(), 
+        wavFilePath.endDateTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
 
     return true;
 }

+ 3 - 2
Server/ThreadRecord/CreateWAVThread.h

@@ -66,8 +66,9 @@ private:
     
     std::list<WavFilePath> m_listDeleteFile;        /* 将要删除的文件名列表 */
 
-    std::string m_newFileName;                      /* 新文件名 */
-    QDateTime m_newFileStartTime;                   /* 新文件开始时间 */
+    // std::string m_newFileName;                      /* 新文件名 */
+    // QDateTime m_newFileStartTime;                   /* 新文件开始时间 */
+    // QDateTime m_newFileEndTime;                     /* 新文件结束时间 */
     int m_filePathNum = 60;                         /* wav小文件路径队列的容量,默认60个文件 */
     /* wav小文件路径队列,这个队列只给一致性检测线程用
      * 注意:这个队列可能会给多个一致性线程检测使用,队列中的元素由本线程管理删除,

+ 90 - 2
Server/ThreadRecord/RecordThread.cpp

@@ -3,8 +3,10 @@
 #include "GlobalInfo.h"
 #include "ThreadManager.h"
 #include "AssignSrcDataThread.h"
-#include "spdlog.h"
+#include "AudioData.h"
+
 #include <cstring>
+#include <QFile>
 
 
 RecordThread::RecordThread(RecordThreadInfo_t& threadInfo) : BaseRecordThread(threadInfo)
@@ -53,6 +55,9 @@ void RecordThread::task()
         return;
     }
 
+#if(RECORD_READFILE)
+    testOpenData();
+#else
     /* 打开录音通道 */
     if(m_audioRecordDesc.empty())
     {
@@ -64,6 +69,7 @@ void RecordThread::task()
         SPDLOG_LOGGER_ERROR(m_logger, "{} 打开声卡通道失败: {}", m_logBase, m_audioRecordDesc);
         return;
     }
+#endif /* RECORD_READFILE */
 
 
     while(m_assignThread == nullptr)
@@ -73,17 +79,23 @@ void RecordThread::task()
     }
     SPDLOG_LOGGER_INFO(m_logger, "{} 获取AssignSrcDataThread线程成功", m_logBase);
 
+    // m_testLastTime = std::chrono::steady_clock::now();
+
     m_isRunning = true;
     while(m_isRunning)
     {
         // std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
-        
+
         /* 获取音频数据,读取的帧数就是采样率,也就是一秒钟数据 */
+    #if(RECORD_READFILE)
+        testGetData(m_pRecordBuffer, m_recordBufferSize, m_oneRecordCount);
+    #else
         if(!m_audioRecord.recordAudio(m_pRecordBuffer, m_recordBufferSize, m_oneRecordCount))
         {
             SPDLOG_LOGGER_ERROR(m_logger, "{} 录音失败,可能是声卡被占用或其他错误", m_logBase);
             break;  /* 录音失败,退出循环 */
         }
+    #endif /* RECORD_READFILE */
 
         // std::chrono::steady_clock::time_point recordTime = std::chrono::steady_clock::now();
         // auto recordDuration = std::chrono::duration_cast<std::chrono::milliseconds>(recordTime - startTime);
@@ -169,3 +181,79 @@ AssignSrcDataThread* RecordThread::getAssignSrcDataThread()
     return nullptr;
 }
 
+/* 打开文件,文件名命名格式cardNum_cardRoad.wav */
+void RecordThread::testOpenData()
+{
+    QString strFileName = QString("%1-%2.wav")
+        .arg(m_threadInfo.cardRoadInfo.nSoundCardNum).arg(m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
+    QFile wavFile;
+    wavFile.setFileName(strFileName);
+    if(!wavFile.open(QIODevice::ReadOnly))
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "{} 打开测试文件失败: {}", m_logBase, strFileName.toStdString());
+        return;
+    }
+    /* 先读取前44个字节,获取文件信息 */
+    wavFile.seek(0);
+    WavHeader header;
+    wavFile.read(reinterpret_cast<char*>(&header), sizeof(WavHeader));
+    
+    m_testData = wavFile.readAll();
+    wavFile.close();
+
+    /* 打印头文件信息 */
+    SPDLOG_LOGGER_INFO(m_logger, "***********************************************");
+    SPDLOG_LOGGER_INFO(m_logger, "{} 测试文件头信息: ", m_logBase);
+    SPDLOG_LOGGER_INFO(m_logger, "  - 文件名: {}", strFileName.toStdString());
+    SPDLOG_LOGGER_INFO(m_logger, "  - 采样率: {}", header.sampleRate);
+    SPDLOG_LOGGER_INFO(m_logger, "  - 声道数: {}", header.numChannels);
+    SPDLOG_LOGGER_INFO(m_logger, "  - 位深度: {}", header.bitsPerSample);
+    SPDLOG_LOGGER_INFO(m_logger, "  - 数据大小: {}", header.fileSize);
+    SPDLOG_LOGGER_INFO(m_logger, "  - 数据大小: {}", header.fileSize);
+    SPDLOG_LOGGER_INFO(m_logger, "  - 文件格式: {}", header.audioFormat);
+    SPDLOG_LOGGER_INFO(m_logger, "***********************************************");
+}
+
+/* 测试数据,读取文件,模拟录音 */
+void RecordThread::testGetData(char* buffer, int32_t bufferSize, int32_t recordFrames)
+{
+    if(m_testData.size() < bufferSize)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "{} 测试数据不足,无法读取", m_logBase);
+        return;
+    }
+    if(m_testData.size() - m_testReadSize < bufferSize)
+    {
+        /* 剩下的不足100ms,直接扔了,从头开始读取 */
+        m_testReadSize = 0;
+    }
+    // m_testLastTime = std::chrono::steady_clock::now();
+    /* 读取测试数据 */
+    // memcpy(buffer, m_testData.mid(m_testReadSize).data(), bufferSize);
+    memcpy(buffer, m_testData.constData() + m_testReadSize, bufferSize);
+    m_testReadSize += bufferSize;
+
+    // auto nowTime = std::chrono::steady_clock::now();
+    // SPDLOG_LOGGER_TRACE(m_logger, "{} 测试数据读取完成,大小: {}, 已读取: {}, 耗时: {}us", 
+    //     m_logBase, bufferSize, m_testReadSize, 
+    //     std::chrono::duration_cast<std::chrono::microseconds>(nowTime - m_testLastTime).count());
+    // m_testLastTime = nowTime;
+
+    preciseSleepMs(31);
+}
+
+void RecordThread::preciseSleepMs(int ms)
+{
+    auto start = std::chrono::steady_clock::now();
+    auto end = start + std::chrono::milliseconds(ms);
+    while (std::chrono::steady_clock::now() < end)
+    {
+        auto now = std::chrono::steady_clock::now();
+        auto remain = std::chrono::duration_cast<std::chrono::milliseconds>(end - now).count();
+        if (remain > 2)
+            std::this_thread::sleep_for(std::chrono::milliseconds(remain - 1));
+        else
+            ; // busy-wait,最后1~2ms用空循环补偿
+    }
+}
+

+ 13 - 0
Server/ThreadRecord/RecordThread.h

@@ -12,6 +12,10 @@
 
 #include "spdlog/spdlog.h"
 
+
+#define RECORD_READFILE true
+
+
 class AssignSrcDataThread;
 
 
@@ -46,6 +50,10 @@ private:
     /* 获取AssignSrcDataThread线程 */
     AssignSrcDataThread* getAssignSrcDataThread();
 
+    /* 测试数据 */
+    void testOpenData();
+    void testGetData(char* buffer, int32_t bufferSize, int32_t recordFrames);
+    void preciseSleepMs(int ms);
 
 private:
     AudioRecord m_audioRecord;          /* 音频录制类 */
@@ -55,6 +63,11 @@ private:
     int32_t m_oneRecordCount = 0;       /* 每次录音的音频数据大小,单位音频帧,位深度 * 通道数 */
 
     AssignSrcDataThread* m_assignThread = nullptr; /* 分派数据线程指针 */
+
+    /* ---------------------- 测试数据 ---------------------- */
+    QByteArray m_testData;      /* 测试数据 */
+    int m_testReadSize = 0;     /* 已读取的数据大小 */
+    // std::chrono::steady_clock::time_point m_testLastTime; /* 上次读取数据的时间 */
 };
 
 

+ 2 - 1
common/Network/FromWebAPI.cpp

@@ -779,7 +779,7 @@ bool FromWebAPI::insertConsistencyAlarmInfo(const AlarmInfo_t& mainAlarm, const
     try
     {
         nJson json0;
-        json0["opName"] = "ACAS_InsertConsistencyAlarmInfo";
+        json0["opName"] = "ACAS_InsertTwoAlarmInfo";
         nJson json1;
         json1["itemID1"] = mainAlarm.CompareItemID;
         json1["itemName1"] = mainAlarm.strCompareItemName;
@@ -812,6 +812,7 @@ bool FromWebAPI::insertConsistencyAlarmInfo(const AlarmInfo_t& mainAlarm, const
         json1["fileAlarmStartPos2"] = subAlarm.AlarmStartPos;
 
         json0["paramList"] = json1;
+        // SPDLOG_LOGGER_DEBUG(m_logger, "写入一致性报警信息: {}", json0.dump(4));
         QString strSend = QString::fromStdString(json0.dump());
         QString strRet;
         int ret = m_httpApi->DBDoInterface(enDBOperatorType::EDBOT_Insert, strSend, strRet);

+ 13 - 1
show3/main.cpp

@@ -18,6 +18,7 @@ void test1();
 void test2();
 void test3();
 void test4(int argc, char** argv);
+void test5();
 
 int main(int argc, char* argv[]) 
 {
@@ -35,7 +36,10 @@ int main(int argc, char* argv[])
     // std::this_thread::sleep_for(std::chrono::seconds(2)); // 等待任务执行
 
     // signalstats_wrapper::finalize();
-    test4(argc, argv);
+    // test4(argc, argv);
+    test5();
+
+    std::this_thread::sleep_for(std::chrono::seconds(2));
 
     
     return 0;
@@ -212,3 +216,11 @@ void test4(int argc, char** argv)
     a.exec();
 }
 
+
+void test5()
+{
+    QString str1 = "Road2_Consistency-.wav";
+    QString str2 = str1.replace("-.wav", "-20250807_123456.wav");
+    SPDLOG_INFO("Old: {}, New: {}", str1.toStdString(), str2.toStdString());
+}
+