RecordThread.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include "RecordThread.h"
  2. #include "GlobalInfo.h"
  3. #include "ThreadManager.h"
  4. #include "AssignSrcDataThread.h"
  5. #include <cstring>
  6. RecordThread::RecordThread(RecordThreadInfo_t& threadInfo) : BaseRecordThread(threadInfo)
  7. {
  8. m_logger = spdlog::get("RecordAudio");
  9. if(m_logger == nullptr)
  10. {
  11. fmt::print("RecordThread: RecordAudio Logger not found.\n");
  12. return;
  13. }
  14. }
  15. RecordThread::~RecordThread()
  16. {
  17. }
  18. /* 设置声卡描述符 */
  19. void RecordThread::setAudioRecordDesc(const std::string& desc)
  20. {
  21. m_audioRecordDesc = desc;
  22. }
  23. /* 设置分派线程的指针 */
  24. void RecordThread::setAssignSrcDataThread(AssignSrcDataThread* pThread)
  25. {
  26. if(pThread == nullptr)
  27. {
  28. SPDLOG_LOGGER_ERROR(m_logger, "{} 分派数据线程指针为空", m_logBase);
  29. return;
  30. }
  31. m_assignThread = pThread;
  32. // SPDLOG_LOGGER_INFO(m_logger, "{} 设置分派数据线程成功", m_logBase);
  33. }
  34. /* 录制功能线程函数 */
  35. void RecordThread::task()
  36. {
  37. SPDLOG_LOGGER_INFO(m_logger, "{} 开始录音线程", m_logBase);
  38. /* 先初始化数据 */
  39. if(!initData())
  40. {
  41. SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase);
  42. return;
  43. }
  44. /* 打开录音通道 */
  45. if(m_audioRecordDesc.empty())
  46. {
  47. SPDLOG_LOGGER_ERROR(m_logger, "{} 声卡描述符为空,无法打开录音通道", m_logBase);
  48. return;
  49. }
  50. if(!m_audioRecord.openRecordChannel(m_audioRecordDesc))
  51. {
  52. SPDLOG_LOGGER_ERROR(m_logger, "{} 打开声卡通道失败: {}", m_logBase, m_audioRecordDesc);
  53. return;
  54. }
  55. while(m_assignThread == nullptr)
  56. {
  57. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  58. m_assignThread = getAssignSrcDataThread();
  59. }
  60. SPDLOG_LOGGER_INFO(m_logger, "{} 获取AssignSrcDataThread线程成功", m_logBase);
  61. m_isRunning = true;
  62. while(m_isRunning)
  63. {
  64. /* 获取音频数据,读取的帧数就是采样率,也就是一秒钟数据 */
  65. if(!m_audioRecord.recordAudio(m_pRecordBuffer, m_recordBufferSize, m_sampleRate))
  66. {
  67. SPDLOG_LOGGER_ERROR(m_logger, "{} 录音失败,可能是声卡被占用或其他错误", m_logBase);
  68. break; /* 录音失败,退出循环 */
  69. }
  70. QDateTime currentTime = QDateTime::currentDateTime();
  71. /* 将音频数据拷贝给分派数据的线程 */
  72. if(m_assignThread != nullptr)
  73. {
  74. m_assignThread->setSrcData(m_pRecordBuffer, m_recordBufferSize, currentTime);
  75. }
  76. memset(m_pRecordBuffer, 0, m_recordBufferSize); /* 清空缓存,准备下一次录音 */
  77. }
  78. SPDLOG_LOGGER_INFO(m_logger, "{} 结束录音", m_logBase);
  79. m_isRunning = false;
  80. }
  81. /* 设置数据 */
  82. bool RecordThread::setData(const AudioSrcData& srcData)
  83. {
  84. return true;
  85. }
  86. /* 初始化数据 */
  87. bool RecordThread::initData()
  88. {
  89. /* 获取全局数据 */
  90. m_sampleRate = GInfo.sampleRate(); /* 采样率 */
  91. m_numChannels = GInfo.numChannels(); /* 声道数 */
  92. m_bitsPerSample = GInfo.bitsPerSample(); /* 每个采样点的位数 */
  93. m_oneSecondSize = m_sampleRate * m_numChannels * (m_bitsPerSample / 8); /* 每秒钟的音频数据大小 */
  94. m_recordBufferSize = m_oneSecondSize; /* 每秒钟的音频数据大小 */
  95. m_pRecordBuffer = new char[m_recordBufferSize] {0}; /* 录音数据缓存 */
  96. /* 初始化录制类的参数 */
  97. m_audioRecord.setRecordParams(m_sampleRate, m_bitsPerSample, m_numChannels);
  98. /* 设置声卡描述符 */
  99. m_audioRecordDesc = fmt::format("hw:{},{}", m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
  100. return true;
  101. }
  102. /* 清除数据 */
  103. void RecordThread::clearData()
  104. {
  105. if(m_pRecordBuffer != nullptr)
  106. {
  107. delete[] m_pRecordBuffer;
  108. m_pRecordBuffer = nullptr;
  109. }
  110. m_recordBufferSize = 0;
  111. }
  112. /* 获取AssignSrcDataThread线程 */
  113. AssignSrcDataThread* RecordThread::getAssignSrcDataThread()
  114. {
  115. auto pThread = ThreadMan.findRecordThread(EThreadType::Type_AssignSrcData, m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
  116. if(pThread != nullptr)
  117. {
  118. return dynamic_cast<AssignSrcDataThread*>(pThread);
  119. }
  120. return nullptr;
  121. }