CreateDBThread.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. #include "CreateDBThread.h"
  2. #include "GlobalVariable.h"
  3. #include "GlobalInfo.h"
  4. #include "CalculateAudio.h"
  5. CreateDBThread::CreateDBThread(RecordThreadInfo_t& threadInfo)
  6. : BaseRecordThread(threadInfo)
  7. {
  8. }
  9. CreateDBThread::~CreateDBThread()
  10. {
  11. }
  12. /* 设置数据 */
  13. bool CreateDBThread::setData(const AudioSrcData& srcData)
  14. {
  15. if(srcData.pData == nullptr || srcData.dataSize == 0)
  16. {
  17. SPDLOG_LOGGER_ERROR(m_logger, "{} 设置数据失败,srcData为空或dataSize为0", m_logBase);
  18. return false;
  19. }
  20. /* 创建一个新的AudioSrcData对象 */
  21. AudioSrcData* audioData = new AudioSrcData(srcData);
  22. if(audioData == nullptr)
  23. {
  24. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建AudioSrcData对象失败", m_logBase);
  25. return false;
  26. }
  27. /* 判断环形队列是否满 */
  28. if(m_queueAudioData.isFull())
  29. {
  30. /* 出队一个最早的元素 */
  31. AudioSrcData* oldData = m_queueAudioData.front_pop();
  32. SPDLOG_LOGGER_WARN(m_logger, "{} 环形队列已满,出队一个元素,时间: {}, 大小: {}",
  33. m_logBase, oldData->startTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), oldData->dataSize);
  34. if(oldData != nullptr){
  35. delete oldData;
  36. oldData = nullptr;
  37. }
  38. }
  39. /* 入队新的数据 */
  40. if(!m_queueAudioData.push_noBlock(audioData))
  41. {
  42. SPDLOG_LOGGER_ERROR(m_logger, "{} 数据加入环形队列失败", m_logBase);
  43. delete audioData; // 入队失败,释放内存
  44. audioData = nullptr;
  45. return false;
  46. }
  47. return true;
  48. }
  49. /* 设置实时数据 */
  50. bool CreateDBThread::setRealTimeData(const AudioSrcData& srcData)
  51. {
  52. auto oldData = m_queueRealTimeData.push_pop(new AudioSrcData(srcData));
  53. if(oldData != nullptr)
  54. {
  55. /* 这里一般不会满,会被实时消耗,如果满了,说明出现问题了 */
  56. SPDLOG_LOGGER_WARN(m_logger, "{} 实时数据环形队列已满,出队一个元素,时间: {}, 大小: {}",
  57. m_logBase, oldData->startTime.toString("yyyy-MM-dd hh:mm:ss.zzz").toStdString(), oldData->dataSize);
  58. delete oldData;
  59. oldData = nullptr;
  60. }
  61. return true;
  62. }
  63. /* 获取最新的结果,根据时间进行对比,最新的时间比传入的晚,就是有新的数据了 */
  64. bool CreateDBThread::getLatestResult(OneSecondData& resultData)
  65. {
  66. if(resultData.startTime.isNull())
  67. {
  68. // SPDLOG_LOGGER_ERROR(m_logger, "{} 获取最新结果失败,传入的时间戳为空", m_logBase);
  69. return false;
  70. }
  71. std::lock_guard<std::mutex> lock(m_queueResultData->mutex);
  72. auto lastSecondData = m_queueResultData->back();
  73. if(lastSecondData == nullptr)
  74. {
  75. SPDLOG_LOGGER_ERROR(m_logger, "{} 获取最新结果失败,结果队列为空", m_logBase);
  76. return false;
  77. }
  78. /* 比较时间戳 */
  79. if(lastSecondData->startTime <= resultData.startTime)
  80. {
  81. return false;
  82. }
  83. resultData = *lastSecondData;
  84. return true;
  85. }
  86. /* 获取最新的结果,让整个环形队列相等 */
  87. bool CreateDBThread::getLatestResult(RingQueueManualMutex<OneSecondData*>& resultQueue)
  88. {
  89. std::lock_guard<std::mutex> lock(m_queueResultData->mutex);
  90. if(m_queueResultData->isEmpty())
  91. {
  92. // SPDLOG_LOGGER_TRACE(m_logger, "{} 获取最新数据,数据队列为空", m_logBase);
  93. return false;
  94. }
  95. /* 目标队列为空,全部拷贝 */
  96. if(resultQueue.isEmpty())
  97. {
  98. SPDLOG_LOGGER_DEBUG(m_logger, "{} 获取最新数据,目标队列为空,拷贝整个结果队列", m_logBase);
  99. for(int i = 0; i < m_queueResultData->QueueSize(); ++i)
  100. {
  101. OneSecondData* data = m_queueResultData->at(i);
  102. if(data != nullptr)
  103. {
  104. OneSecondData* newData = new OneSecondData(*data); // 深拷贝
  105. resultQueue.push(newData);
  106. }
  107. }
  108. return true;
  109. }
  110. /* 队列不为空,查找队列中相等的位置,拷贝后面的数据,不拷贝整个队列,减少开销
  111. * 这里直接从最新的数据往前找 */
  112. auto itBack = resultQueue.back();
  113. int index = m_queueResultData->QueueSize() - 1;
  114. while(index >= 0)
  115. {
  116. OneSecondData* data = m_queueResultData->at(index);
  117. if(data == nullptr)
  118. {
  119. --index;
  120. continue;
  121. }
  122. /* 找到相等的位置 */
  123. if(data->startTime == itBack->startTime)
  124. {
  125. break;
  126. }
  127. --index;
  128. }
  129. if(index < 0)
  130. {
  131. SPDLOG_LOGGER_WARN(m_logger, "{} 获取最新数据失败,未找到相等的时间戳,将清空队列,拷贝全部数据", m_logBase);
  132. SPDLOG_LOGGER_WARN(m_logger, "队列大小: {}, 目标队列大小: {}", m_queueResultData->QueueSize(), resultQueue.QueueSize());
  133. /* 清空目标队列,将所有的数据全部拷贝 */
  134. while(!resultQueue.isEmpty())
  135. {
  136. OneSecondData* data = resultQueue.front_pop();
  137. if(data != nullptr)
  138. {
  139. delete data;
  140. data = nullptr;
  141. }
  142. }
  143. /* 拷贝全部数据 */
  144. for(int i = 0; i < m_queueResultData->QueueSize(); ++i)
  145. {
  146. OneSecondData* data = m_queueResultData->at(i);
  147. if(data != nullptr)
  148. {
  149. OneSecondData* newData = new OneSecondData(*data); // 深拷贝
  150. resultQueue.push(newData);
  151. }
  152. }
  153. return true;
  154. }
  155. else if(index == m_queueResultData->QueueSize() - 1)
  156. {
  157. // 已经是最新的数据了,不需要拷贝
  158. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 获取最新数据,已经是最新的数据了", m_logBase);
  159. return false;
  160. }
  161. /* 拷贝数据 */
  162. for(; index < m_queueResultData->QueueSize(); ++index)
  163. {
  164. OneSecondData* data = m_queueResultData->at(index);
  165. if(data == nullptr)
  166. {
  167. continue;
  168. }
  169. OneSecondData* newData = new OneSecondData(*data); // 深拷贝
  170. auto fornt = resultQueue.push(newData);
  171. if(fornt != nullptr)
  172. {
  173. delete fornt; // 出队的元素是之前的结果,释放内存
  174. fornt = nullptr;
  175. }
  176. }
  177. return true;
  178. }
  179. /**
  180. * @brief 获取最新的音量包结果
  181. *
  182. * @param listData
  183. * @param count 等于负数是获取所有数据,等于正数,如果暂时没有这么多数据,则返回false
  184. * @return true 获取成功
  185. * @return false 无数据或者数据不足
  186. */
  187. bool CreateDBThread::getLatestRealTimeResult(std::list<OneDBData>& listData, int count)
  188. {
  189. std::lock_guard<std::mutex> lock(m_mutexRealTimeResult);
  190. if(m_listRealTimeResult.empty())
  191. {
  192. // SPDLOG_LOGGER_TRACE(m_logger, "{} 最新实时音量数据为空", m_logBase);
  193. return false;
  194. }
  195. if(count <= 0)
  196. {
  197. count = m_listRealTimeResult.size();
  198. }
  199. if(count > static_cast<int>(m_listRealTimeResult.size()))
  200. {
  201. // SPDLOG_LOGGER_WARN(m_logger, "{} 最新实时音量数据不足,要求: {}, 实际: {}", m_logBase, count, m_listRealTimeResult.size());
  202. return false;
  203. }
  204. /* 获取最新的count个数据 */
  205. for(int i = 0; i < count; ++i)
  206. {
  207. listData.push_back(m_listRealTimeResult.front());
  208. m_listRealTimeResult.pop_front();
  209. }
  210. return true;
  211. }
  212. /* 获取一个最新音量值 */
  213. bool CreateDBThread::getLatestRealTimeResult(OneDBData& resultData)
  214. {
  215. std::lock_guard<std::mutex> lock(m_mutexRealTimeResult);
  216. if(m_listRealTimeResult.empty())
  217. {
  218. // SPDLOG_LOGGER_TRACE(m_logger, "{} 最新实时音量数据为空", m_logBase);
  219. return false;
  220. }
  221. resultData = m_listRealTimeResult.front();
  222. m_listRealTimeResult.pop_front();
  223. return true;
  224. }
  225. /* 计算音量和反相的线程函数 */
  226. void CreateDBThread::task()
  227. {
  228. SPDLOG_LOGGER_INFO(m_logger, "➢ {} 开始计算音量线程", m_logBase);
  229. /* 初始化一些数据 */
  230. if(!initData())
  231. {
  232. SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase);
  233. return;
  234. }
  235. while(m_isRunning)
  236. {
  237. /*--------------------------------------------------------------
  238. * 计算实时音量值(这个数据量很小,大概只有33ms,所以阻塞在这里)
  239. *--------------------------------------------------------------*/
  240. /* 判断实时数据列表是否有数据,没有数据则阻塞,直到有数据 */
  241. auto rtData = m_queueRealTimeData.front();
  242. if(rtData == nullptr)
  243. {
  244. SPDLOG_LOGGER_DEBUG(m_logger, "{} 实时数据队列为空,等待数据", m_logBase);
  245. continue;
  246. }
  247. // std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
  248. /* 计算实时音量值 */
  249. calculateRealTimeVolume();
  250. // std::chrono::steady_clock::time_point rtEndTime = std::chrono::steady_clock::now();
  251. // std::chrono::microseconds rtDuration = std::chrono::duration_cast<std::chrono::microseconds>(rtEndTime - startTime);
  252. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 计算实时音量包完成,耗时: {} 微秒", m_logBase, rtDuration.count());
  253. /*--------------------------------------------------------------
  254. * 计算常规音量值,1秒计算一次
  255. *--------------------------------------------------------------*/
  256. /* 判断是否够一秒的数据 */
  257. if(m_queueAudioData.isEmpty())
  258. {
  259. continue;
  260. }
  261. auto audioData = m_queueAudioData.front_pop();
  262. if(audioData == nullptr)
  263. {
  264. SPDLOG_LOGGER_WARN(m_logger, "{} 从环形队列中取出数据失败,可能是队列为空", m_logBase);
  265. // std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 等待一段时间再尝试
  266. continue;
  267. }
  268. /* 计算音量和反相,结果存储在m_result */
  269. if(!CreateDBPhase(audioData))
  270. {
  271. SPDLOG_LOGGER_ERROR(m_logger, "{} 计算音量和反相失败", m_logBase);
  272. }
  273. /* 将结果放入结果队列 */
  274. if(m_result != nullptr)
  275. {
  276. std::lock_guard<std::mutex> lock(m_queueResultData->mutex);
  277. auto result = m_queueResultData->push(m_result);
  278. if(result != nullptr)
  279. {
  280. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 队列已满,出队一个元素", m_logBase);
  281. delete result; // 出队的元素是之前的结果,释放内存
  282. result = nullptr;
  283. }
  284. m_result = nullptr; // 清空结果指针,等待下一次使用
  285. }
  286. delete audioData; // 释放内存
  287. audioData = nullptr;
  288. // std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
  289. // std::chrono::microseconds duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - rtEndTime);
  290. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 计算1秒的音量包完成,耗时: {} 微秒", m_logBase, duration.count());
  291. }
  292. /* 清理数据 */
  293. clearData();
  294. SPDLOG_LOGGER_WARN(m_logger, "➢ {} 计算音量线程结束 ", m_logBase);
  295. }
  296. /* 初始化一些数据 */
  297. bool CreateDBThread::initData()
  298. {
  299. int queueSize = GInfo.queueElementCount();
  300. /* 初始化一些数据 */
  301. m_queueAudioData.clearQueue();
  302. m_queueAudioData.setQueueCapacity(queueSize);
  303. m_queueRealTimeData.setQueueCapacity(queueSize);
  304. m_sampleRate = GInfo.sampleRate(); /* 采样率 */
  305. m_numChannels = GInfo.numChannels(); /* 声道数 */
  306. m_bitsPerSample = GInfo.bitsPerSample(); /* 每个采样点的位数 */
  307. /* 一秒钟数据大小,单位:字节 */
  308. m_oneSecondSize = m_sampleRate * m_numChannels * (m_bitsPerSample / 8);
  309. /* 计算每个音量值需要的数据大小,单位数据单位: short,一个通道的大小 */
  310. m_oneDBLengthOfSrcData = m_sampleRate / VOLUME_INFO_NUM;
  311. m_singleDataLength = m_oneSecondSize / m_numChannels;
  312. /* 计算音量和反相的环形队列元素数目,默认是180个,即180秒 */
  313. // m_queueAudioDataCapacity = queueSize;
  314. m_queueResultData = new RingQueueManualMutex<OneSecondData*>(queueSize);
  315. m_queueResultData->mutex.lock();
  316. m_queueResultData->setDefaultValue(nullptr);
  317. m_queueResultData->mutex.unlock();
  318. return true;
  319. }
  320. /* 清理数据 */
  321. void CreateDBThread::clearData()
  322. {
  323. /* 清理环形队列 */
  324. while(!m_queueAudioData.isEmpty())
  325. {
  326. AudioSrcData* data = m_queueAudioData.front_pop();
  327. if(data != nullptr)
  328. {
  329. delete data;
  330. data = nullptr;
  331. }
  332. }
  333. // if(m_remainData != nullptr)
  334. // {
  335. // delete m_remainData;
  336. // m_remainData = nullptr;
  337. // }
  338. }
  339. /* 计算音量和反相 */
  340. bool CreateDBThread::CreateDBPhase(AudioSrcData* audioData)
  341. {
  342. short* pWaveVu = reinterpret_cast<short*>(audioData->pData);
  343. /* 一秒钟平分30个音量值,每个音量值占有的长度 */
  344. const int oneDBSize = m_oneDBLengthOfSrcData;
  345. StAudioNum audioInfo;
  346. audioInfo.roadInfo = m_threadInfo.cardRoadInfo; // 设置通道信息
  347. audioInfo.nTotal = m_singleDataLength;
  348. int iCurPos = 0;
  349. /* 存储结果 */
  350. m_result = new OneSecondData();
  351. /* 计算音量和反相的计算类 */
  352. CAudio2ChanCorrelator audioCor;
  353. /* 音量值计算,好多个字节计算出一个最大音量值 */
  354. for(int i = 0; i < VOLUME_INFO_NUM; ++i)
  355. {
  356. // 采样点最大值
  357. short sMaxA, sMaxB, sRMSA, sRMSB;
  358. audioCor.CorrelateChunks(pWaveVu + iCurPos, (pWaveVu + iCurPos + 1), oneDBSize, &sMaxA, &sMaxB, &sRMSA, &sRMSB, audioInfo);
  359. /* 这里乘2是要增加两个通道的数据大小 */
  360. iCurPos += (oneDBSize * 2);
  361. m_result->aryLeftDB[i] = calculateDB(sMaxA);
  362. m_result->aryRightDB[i] = calculateDB(sMaxB);
  363. // fmt::print("音量计算: sMaxA: {}, sMaxB: {}, sRMSA: {}, sRMSB: {}, LDB:{}, RDB:{}\n", sMaxA, sMaxB, sRMSA, sRMSB,
  364. // m_result->aryLeftDB[i], m_result->aryRightDB[i]);
  365. // 获取反相值,-100 到 100;反相是左右声道比对得到的值,所以只有一个
  366. int iReversed = audioCor.GetCorrelationLevel();
  367. if(iReversed > REVERSED_MAX_VALUE || iReversed < REVERSED_MIN_VALUE)
  368. {
  369. iReversed = 0;
  370. }
  371. // 和反相阈值比较,来判定是否为反相
  372. float dReversed = iReversed / 100.00;
  373. m_result->aryPhase[i] = dReversed;
  374. }
  375. /* 设置时间戳 */
  376. m_result->startTime = audioData->startTime;
  377. m_result->endTime = audioData->endTime;
  378. return true;
  379. }
  380. /* 计算实时音量值 */
  381. bool CreateDBThread::calculateRealTimeVolume()
  382. {
  383. /* 一秒钟平分30个音量值,每个音量值占有的长度 */
  384. const int oneDBSize = m_oneDBLengthOfSrcData;
  385. while(!m_queueRealTimeData.isEmpty())
  386. {
  387. /* 取出一个数据,没有数据则阻塞住 */
  388. AudioSrcData* audioData = m_queueRealTimeData.front_pop_noBlock();
  389. if(audioData == nullptr)
  390. {
  391. continue;
  392. }
  393. /* 计算音量和反相的计算类 */
  394. CAudio2ChanCorrelator audioCor;
  395. StAudioNum audioInfo;
  396. audioInfo.roadInfo = m_threadInfo.cardRoadInfo; // 设置通道信息
  397. audioInfo.nTotal = m_singleDataLength;
  398. short* pData = reinterpret_cast<short*>(audioData->pData);
  399. // 采样点最大值
  400. short sMaxA, sMaxB, sRMSA, sRMSB;
  401. audioCor.CorrelateChunks(pData, pData + 1, oneDBSize, &sMaxA, &sMaxB, &sRMSA, &sRMSB, audioInfo);
  402. /* 这里乘2是要增加两个通道的数据大小 */
  403. int leftDB = calculateDB(sMaxA);
  404. int rightDB = calculateDB(sMaxB);
  405. // fmt::print("音量计算: sMaxA: {}, sMaxB: {}, sRMSA: {}, sRMSB: {}, LDB:{}, RDB:{}\n", sMaxA, sMaxB, sRMSA, sRMSB,
  406. // m_result->aryLeftDB[i], m_result->aryRightDB[i]);
  407. // 获取反相值,-100 到 100;反相是左右声道比对得到的值,所以只有一个
  408. int iReversed = audioCor.GetCorrelationLevel();
  409. if(iReversed > REVERSED_MAX_VALUE || iReversed < REVERSED_MIN_VALUE)
  410. {
  411. iReversed = 0;
  412. }
  413. // 和反相阈值比较,来判定是否为反相
  414. float dReversed = iReversed / 100.00;
  415. OneDBData oneDBData;
  416. oneDBData.leftDB = leftDB;
  417. oneDBData.rightDB = rightDB;
  418. oneDBData.phase = dReversed;
  419. oneDBData.startTime = audioData->startTime;
  420. oneDBData.endTime = audioData->endTime;
  421. /* 保存结果 */
  422. std::lock_guard<std::mutex> lock(m_mutexRealTimeResult);
  423. m_listRealTimeResult.push_back(oneDBData);
  424. }
  425. return true;
  426. }