RecordThread.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. #include "RecordThread.h"
  2. #include "GlobalInfo.h"
  3. #include "ThreadManager.h"
  4. #include "AssignSrcDataThread.h"
  5. #include "AudioData.h"
  6. #include <cstring>
  7. #include <QFile>
  8. RecordThread::RecordThread(RecordThreadInfo_t& threadInfo) : BaseRecordThread(threadInfo)
  9. {
  10. }
  11. RecordThread::~RecordThread()
  12. {
  13. }
  14. /* 设置声卡描述符 */
  15. // void RecordThread::setAudioRecordDesc(const std::string& desc)
  16. // {
  17. // m_audioRecordDesc = desc;
  18. // }
  19. /* 设置分派线程的指针 */
  20. // void RecordThread::setAssignSrcDataThread(AssignSrcDataThread* pThread)
  21. // {
  22. // if(pThread == nullptr)
  23. // {
  24. // SPDLOG_LOGGER_ERROR(m_logger, "{} 分派数据线程指针为空", m_logBase);
  25. // return;
  26. // }
  27. // m_assignThread = pThread;
  28. // // SPDLOG_LOGGER_INFO(m_logger, "{} 设置分派数据线程成功", m_logBase);
  29. // }
  30. /* 录制功能线程函数 */
  31. void RecordThread::task()
  32. {
  33. SPDLOG_LOGGER_INFO(m_logger, "➢ {} 开始录音线程 ", m_logBase);
  34. /* 先初始化数据 */
  35. if(!initData())
  36. {
  37. SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase);
  38. return;
  39. }
  40. #if(RECORD_READFILE)
  41. testOpenData();
  42. #else
  43. /* 打开录音通道 */
  44. if(m_audioRecordDesc.empty())
  45. {
  46. SPDLOG_LOGGER_ERROR(m_logger, "{} 声卡描述符为空,无法打开录音通道", m_logBase);
  47. return;
  48. }
  49. /* 初始化录制类的参数 */
  50. m_audioRecord.setRecordParams(m_sampleRate, m_bitsPerSample, m_numChannels);
  51. if(!m_audioRecord.openRecordChannel(m_audioRecordDesc))
  52. {
  53. SPDLOG_LOGGER_ERROR(m_logger, "{} 打开声卡通道失败: {}", m_logBase, m_audioRecordDesc);
  54. return;
  55. }
  56. #endif /* RECORD_READFILE */
  57. /* 重连声卡的次数,超过5次就退出 */
  58. int reconnectSize = 0;
  59. /* 获取分派数据线程 */
  60. while(m_assignThread == nullptr)
  61. {
  62. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  63. m_assignThread = getAssignSrcDataThread();
  64. }
  65. SPDLOG_LOGGER_INFO(m_logger, "{} 获取AssignSrcDataThread线程成功", m_logBase);
  66. // m_testLastTime = std::chrono::steady_clock::now();
  67. m_isRunning = true;
  68. m_isStoped = false;
  69. while(m_isRunning)
  70. {
  71. // std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
  72. /* 获取音频数据,读取的帧数就是采样率,也就是一秒钟数据 */
  73. #if(RECORD_READFILE)
  74. testGetData(m_pRecordBuffer, m_recordBufferSize, m_oneRecordCount);
  75. #else
  76. int ret = m_audioRecord.recordAudio(m_pRecordBuffer, m_recordBufferSize, m_oneRecordCount);
  77. if(ret == -1)
  78. {
  79. SPDLOG_LOGGER_ERROR(m_logger, "{} 录音失败,可能是声卡被占用或其他错误", m_logBase);
  80. break; /* 录音失败,退出循环 */
  81. }else if(ret == -2)
  82. {
  83. SPDLOG_LOGGER_INFO(m_logger, "{} 关闭声卡录音通道,尝试重新打开", m_logBase);
  84. /* 断开的管道,重新初始化声卡通道 */
  85. m_audioRecord.closeRecordChannel();
  86. if(!m_audioRecord.openRecordChannel(m_audioRecordDesc))
  87. {
  88. SPDLOG_LOGGER_ERROR(m_logger, "{} 重新打开声卡通道失败: {}", m_logBase, m_audioRecordDesc);
  89. reconnectSize++;
  90. if(reconnectSize > 5)
  91. {
  92. break;
  93. }
  94. continue;
  95. }
  96. }
  97. reconnectSize = 0;
  98. #endif /* RECORD_READFILE */
  99. // std::chrono::steady_clock::time_point recordTime = std::chrono::steady_clock::now();
  100. // auto recordDuration = std::chrono::duration_cast<std::chrono::milliseconds>(recordTime - startTime);
  101. // SPDLOG_LOGGER_TRACE(m_logger, "{} 录音完成,数据大小: {}, 消耗时长:{}ms", m_logBase, m_recordBufferSize, recordDuration.count());
  102. QDateTime currentTime = QDateTime::currentDateTime();
  103. /* 将音频数据拷贝给分派数据的线程 */
  104. if(m_assignThread != nullptr)
  105. {
  106. m_assignThread->setSrcData(m_pRecordBuffer, m_recordBufferSize, currentTime);
  107. }
  108. // for(int i = 0; i < 30; ++i)
  109. // {
  110. // /* 这里可以添加对音频数据的处理,比如噪音检测等 */
  111. // fmt::print(" |{} {}, short: {}\n", static_cast<uint8_t>(*(m_pRecordBuffer + i*2)), static_cast<uint8_t>(*(m_pRecordBuffer + i*2+1)),
  112. // static_cast<int16_t>(*(m_pRecordBuffer + i * 2)));
  113. // }
  114. memset(m_pRecordBuffer, 0, m_recordBufferSize); /* 清空缓存,准备下一次录音 */
  115. // std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
  116. // auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - recordTime);
  117. // SPDLOG_LOGGER_TRACE(m_logger, "{} 分派数据耗时: {}us", m_logBase, duration.count());
  118. }
  119. /* 关闭录音通道 */
  120. m_audioRecord.closeRecordChannel();
  121. clearData();
  122. SPDLOG_LOGGER_WARN(m_logger, "➢ {} 结束录音", m_logBase);
  123. m_isRunning = false;
  124. m_isStoped = true;
  125. }
  126. /* 设置数据 */
  127. bool RecordThread::setData(const AudioSrcData& srcData)
  128. {
  129. return true;
  130. }
  131. /* 初始化数据 */
  132. bool RecordThread::initData()
  133. {
  134. /* 获取全局数据 */
  135. m_sampleRate = GInfo.sampleRate(); /* 采样率 */
  136. m_numChannels = GInfo.numChannels(); /* 声道数 */
  137. m_bitsPerSample = GInfo.bitsPerSample(); /* 每个采样点的位数 */
  138. m_oneSecondSize = m_sampleRate * m_numChannels * (m_bitsPerSample / 8); /* 每秒钟的音频数据大小 */
  139. /* 每次录音的音频数据大小,这里的大小是计算一个音量包所需要的大小 */
  140. m_recordBufferSize = m_oneSecondSize / VOLUME_INFO_NUM;
  141. m_oneRecordCount = m_sampleRate / VOLUME_INFO_NUM;
  142. m_pRecordBuffer = new char[m_recordBufferSize] {0}; /* 录音数据缓存 */
  143. /* 处理声卡名称 */
  144. m_audioRecordDesc = processPCMName(m_threadInfo.cardRoadInfo.pcmInfo.strPCMName);
  145. return true;
  146. }
  147. /* 清除数据 */
  148. void RecordThread::clearData()
  149. {
  150. if(m_pRecordBuffer != nullptr)
  151. {
  152. delete[] m_pRecordBuffer;
  153. m_pRecordBuffer = nullptr;
  154. }
  155. m_recordBufferSize = 0;
  156. }
  157. /* 处理声卡名称,对PCM通道名称进行处理,有些需要添加“plug”,有些需要添加“plug:” */
  158. std::string RecordThread::processPCMName(std::string srcPCMName)
  159. {
  160. std::string pcmName;
  161. /* 查找名称开头中是否包含plug */
  162. if("plughw:" == srcPCMName.substr(0, 7))
  163. {
  164. /* 如果包含plug,则直接使用 */
  165. pcmName = srcPCMName;
  166. }
  167. else if("hw:" == srcPCMName.substr(0, 3))
  168. {
  169. /* 否则,添加plug前缀 */
  170. pcmName = fmt::format("plug{}", srcPCMName);
  171. }
  172. else if("mic" == srcPCMName.substr(0, 3))
  173. {
  174. /* alpdaten声卡的通道 */
  175. pcmName = fmt::format("plug:{}", srcPCMName);
  176. }
  177. else {
  178. /* 其他情况直接使用 */
  179. pcmName = srcPCMName;
  180. }
  181. return pcmName;
  182. }
  183. /* 获取AssignSrcDataThread线程 */
  184. AssignSrcDataThread* RecordThread::getAssignSrcDataThread()
  185. {
  186. auto pThread = ThreadMan.findRecordThread(EThreadType::Type_AssignSrcData, m_threadInfo.cardRoadInfo.pcmInfo.strPCMName);
  187. if(pThread != nullptr)
  188. {
  189. return dynamic_cast<AssignSrcDataThread*>(pThread);
  190. }
  191. return nullptr;
  192. }
  193. /* 打开文件,文件名命名格式cardNum_cardRoad.wav */
  194. void RecordThread::testOpenData()
  195. {
  196. QString strFileName = QString("%1-%2.wav")
  197. .arg(QString::fromStdString(m_threadInfo.cardRoadInfo.strSoundCardName))
  198. .arg(QString::fromStdString(m_threadInfo.cardRoadInfo.pcmInfo.strPCMName));
  199. strFileName = GInfo.wavPath() + "/" + strFileName;
  200. QFile wavFile;
  201. wavFile.setFileName(strFileName);
  202. if(!wavFile.open(QIODevice::ReadOnly))
  203. {
  204. SPDLOG_LOGGER_ERROR(m_logger, "{} 打开测试文件失败: {}", m_logBase, strFileName.toStdString());
  205. return;
  206. }
  207. /* 先读取前44个字节,获取文件信息 */
  208. wavFile.seek(0);
  209. WavHeader header;
  210. wavFile.read(reinterpret_cast<char*>(&header), sizeof(WavHeader));
  211. m_testData = wavFile.readAll();
  212. wavFile.close();
  213. /* 打印头文件信息 */
  214. SPDLOG_LOGGER_INFO(m_logger, "***********************************************");
  215. SPDLOG_LOGGER_INFO(m_logger, "{} 测试文件头信息: ", m_logBase);
  216. SPDLOG_LOGGER_INFO(m_logger, " - 文件名: {}", strFileName.toStdString());
  217. SPDLOG_LOGGER_INFO(m_logger, " - 采样率: {}", header.sampleRate);
  218. SPDLOG_LOGGER_INFO(m_logger, " - 声道数: {}", header.numChannels);
  219. SPDLOG_LOGGER_INFO(m_logger, " - 位深度: {}", header.bitsPerSample);
  220. SPDLOG_LOGGER_INFO(m_logger, " - 数据大小: {}", header.fileSize);
  221. SPDLOG_LOGGER_INFO(m_logger, " - 数据大小: {}", header.fileSize);
  222. SPDLOG_LOGGER_INFO(m_logger, " - 文件格式: {}", header.audioFormat);
  223. SPDLOG_LOGGER_INFO(m_logger, "***********************************************");
  224. }
  225. /* 测试数据,读取文件,模拟录音 */
  226. void RecordThread::testGetData(char* buffer, int32_t bufferSize, int32_t recordFrames)
  227. {
  228. if(m_testData.size() < bufferSize)
  229. {
  230. SPDLOG_LOGGER_ERROR(m_logger, "{} 测试数据不足,无法读取", m_logBase);
  231. return;
  232. }
  233. if(m_testData.size() - m_testReadSize < bufferSize)
  234. {
  235. /* 剩下的不足100ms,直接扔了,从头开始读取 */
  236. m_testReadSize = 0;
  237. }
  238. // m_testLastTime = std::chrono::steady_clock::now();
  239. /* 读取测试数据 */
  240. // memcpy(buffer, m_testData.mid(m_testReadSize).data(), bufferSize);
  241. memcpy(buffer, m_testData.constData() + m_testReadSize, bufferSize);
  242. m_testReadSize += bufferSize;
  243. // auto nowTime = std::chrono::steady_clock::now();
  244. // SPDLOG_LOGGER_TRACE(m_logger, "{} 测试数据读取完成,大小: {}, 已读取: {}, 耗时: {}us",
  245. // m_logBase, bufferSize, m_testReadSize,
  246. // std::chrono::duration_cast<std::chrono::microseconds>(nowTime - m_testLastTime).count());
  247. // m_testLastTime = nowTime;
  248. preciseSleepMs(31);
  249. }
  250. void RecordThread::preciseSleepMs(int ms)
  251. {
  252. auto start = std::chrono::steady_clock::now();
  253. auto end = start + std::chrono::milliseconds(ms);
  254. while (std::chrono::steady_clock::now() < end)
  255. {
  256. auto now = std::chrono::steady_clock::now();
  257. auto remain = std::chrono::duration_cast<std::chrono::milliseconds>(end - now).count();
  258. if (remain > 2)
  259. std::this_thread::sleep_for(std::chrono::milliseconds(remain - 1));
  260. else
  261. ; // busy-wait,最后1~2ms用空循环补偿
  262. }
  263. }