#ifndef _CREATELONGFILETHREAD_H_ #define _CREATELONGFILETHREAD_H_ #include "BaseRecordThread.h" #include "AudioData.h" #include "GlobalVariable.h" #include "RingQueue.hpp" #include "RingQueueManualMutex.hpp" #include #include #include #include /** * @brief 录音状态 * */ enum class eRecordState { eAlarm_Init = 0, /* 初始化状态 */ eAlarm_Recording, /* 录音状态 */ eAlarm_Stopped, /* 停止状态 */ eAlarm_Error, /* 错误状态 */ }; /** 同一个对比项中多个一致性报警时,主通道的录音可能开始录音时间不同, 会有多个录音同时存在 */ struct AlarmKey_t { int compareItemID; /* 对比项ID */ int roadNum; /* 对比通道编号 */ EAlarmType alarmType; /* 报警类型 */ QDateTime startTime; /* 报警开始时间 */ AlarmKey_t(int id, int num, EAlarmType type, const QDateTime& time) : compareItemID(id), roadNum(num), alarmType(type), startTime(time) {} bool operator<(const AlarmKey_t& other) const { if(compareItemID != other.compareItemID) { return compareItemID < other.compareItemID; } if(roadNum != other.roadNum) { return roadNum < other.roadNum; } if(alarmType != other.alarmType) { return alarmType < other.alarmType; } return startTime < other.startTime; } }; /** 报警文件队列的值 */ struct AlarmValue_t { QString fileName; /* 报警文件名 */ QString fileNameEnd; /* 报警文件结束名,只有在报警结束时才有值 */ eRecordState state; /* 录音状态 */ QDateTime startTime; /* 录音开始时间 */ QDateTime endTime; /* 录音结束时间 */ int alarmStartPos = 0; /* 录音开始位置,单位:秒,报警问价的开始位置不一定是报警的开始位置 */ /* 对比项和通道信息*/ EAlarmType alarmType; /* 报警类型 */ int numConpareItemID; /* 对比项ID */ QString strCompareItemName; /* 对比项名称 */ CompareItemRoadInfo_t itemRoadInfo; /* 对比项通道信息 */ AlarmValue_t() : state(eRecordState::eAlarm_Init) {} AlarmValue_t(const QString& name, eRecordState s, const QDateTime& start, const QDateTime& end) : fileName(name), state(s), startTime(start), endTime(end) {} }; /** 这个线程类记录一个长的录音文件,1小时一个文件 功能1:记录一个长的录音文件,1小时一个文件 1、如果是刚开始录音,到下一个整点记录一个文件,后续都是满1小时一个文件 2、数据先放到缓冲区中,满1分钟写一次文件 功能2: 1、录制报警文件 2、由其他线程传来报警参数,开启录制,报警结束后,结束录制 3、由于静音、过载、反相、一致性报警、噪音报警条件是和对比项相关联的,因此这里可能回同时存在多个录音, 根据对比项ID和对比项通道以及报警类型来区分 4、报警文件的命名规则:Alarm_CompareItemID_RoadNum_AlarmType_yyyyMMdd_hhmmss-yyyyMMdd_hhmmss.wav 例如:Alarm_1_1_Silent_20250101_120000-20250101_120100.wav 文件夹路径格式: 1、长录音文件夹: Application/ACAServerData/Record/yyyy-MM-dd/SoundCardID-RoadNum/Record_yyyy-MM-dd-hh-mm-ss-yyyy-MM-dd-hh-mm-ss.wav 例如:Application/2025-01-01/SoundCard1-1/Record_2025-01-01-12-00-00-2025-01-01-12-01-00.wav 2、报警录音文件夹:Application/ACAServerData/AlarmWav/yyyy-MM-dd/CompareItemID-id/Alarm_RoadNum_AlarmType_yyyyMMdd_hhmmss-yyyyMMdd_hhmmss.wav 例如:Application/2025-01-01/1-1/Alarm_1_1_Silent_20250101_120000-20250101_120100.wav */ class CreateLongFileThread : public BaseRecordThread { public: CreateLongFileThread(RecordThreadInfo_t& threadInfo); ~CreateLongFileThread() override; /* 设置数据 */ bool setData(const AudioSrcData& srcData) override; /* 开启录制 */ bool startRecordAlarmFile(const AlarmInfo_t& alarmInfo); /* 停止录制,alarmInfo既是传入参数,也是传出参数,传出文件路径和开始位置 */ bool stopRecordAlarmFile(AlarmInfo_t& alarmInfo); private: /* 执行任务函数 */ void task() override; /* 初始化一些数据 */ bool initData() override; /* 清理数据 */ void clearData() override; /*===============================================================================*/ /* 写入长记录文件 */ bool writeLongRecordFile(); /* 设置今日目录 */ inline bool setTodayPath(bool isNewFile); /* 打开文件 */ bool openFile(QFile& wavFile, bool isNewFile); /* 写入音频数据到文件 */ bool writeAudioDataToFile(const AudioSrcData& audioData, const QString& fileName); /* 生成文件名 */ inline QString generateFileName(const QDateTime& startTime, const QDateTime& endTime) const; /* 判断是否过了整点 */ inline bool isOneHourPassed(); /*===============================================================================*/ /* 写入报警文件 */ void writeAlarmFile(); /* 生成报警文件名 */ inline QString generateAlarmFileName(const AlarmValue_t& value, bool isNewFile); /* 设置今日报警文件夹 */ bool setTodayAlarmPath(); /* 根据报警类型的枚举获取字符 */ QString getAlarmTypeString(EAlarmType type) const; private: /* 临时缓存数据, 一分钟写入一次,给这个分配2分钟的数据大小 */ std::mutex m_mutexBuffer; AudioSrcData m_bufferData; AudioSrcData m_srcData; /* 当前的音频数据 */ int32_t m_writeCriticalSize = 0; /* 写入文件的临界大小,单位:字节,缓存超过这个大小就写入文件 */ int32_t m_oneHourSize = 0; /* 一小时的音频数据大小 */ QDir m_todayDir; /* 今日目录 */ QDate m_todayDateRecord; /* 今日日期,记录长文件用 */ QString m_wavFileName; /* wav文件对象 */ int m_openFileErrorSize = 0; /* 打开文件错误次数 */ WavHeader m_wavHeader; /* 当前wav文件头信息 */ int64_t m_writtenSize = 0; /* 已经写入的数据大小 */ QDateTime m_writtenStartTime; /* 已经写入数据的开始时间点 */ QDateTime m_writtenNowTime; /* 已经写入数据的最后时间点 */ /*===============================================================================*/ /* 报警文件名,key是报警信息,value是文件信息 */ std::mutex m_mutexAlarmFile; std::map m_mapAlarmFile; QDir m_yesterdayDir; /* 昨日目录,用来给还未录制完成的报警文件使用的 */ QDir m_todayDirAlarm; /* 今日报警目录,这个目录只到日期,里面的子文件夹是对比项相关的 */ QDate m_todayDateAlarm; /* 今日日期,记录报警文件用 */ RingQueueManualMutex m_ringQueue; /* 环形队列,存储报警文件数据 */ QDateTime m_alarmWrittenTime; /* 报警文件中环形队列已写入文件的时间 */ int m_numNewAlarmSeconds = 0; /* 新的报警文件的秒数,新加入的报警文件的秒数,每次写完后清零 */ }; #endif // _CREATELONGFILETHREAD_H_