123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- #include "RecordThread.h"
- #include "GlobalInfo.h"
- #include "ThreadManager.h"
- #include "AssignSrcDataThread.h"
- #include "AudioData.h"
- #include <cstring>
- #include <QFile>
- RecordThread::RecordThread(RecordThreadInfo_t& threadInfo) : BaseRecordThread(threadInfo)
- {
- m_logger = spdlog::get("RecordAudio");
- if(m_logger == nullptr)
- {
- fmt::print("RecordThread: RecordAudio Logger not found.\n");
- return;
- }
- }
- RecordThread::~RecordThread()
- {
- }
- /* 设置声卡描述符 */
- void RecordThread::setAudioRecordDesc(const std::string& desc)
- {
- m_audioRecordDesc = desc;
- }
- /* 设置分派线程的指针 */
- void RecordThread::setAssignSrcDataThread(AssignSrcDataThread* pThread)
- {
- if(pThread == nullptr)
- {
- SPDLOG_LOGGER_ERROR(m_logger, "{} 分派数据线程指针为空", m_logBase);
- return;
- }
- m_assignThread = pThread;
- // SPDLOG_LOGGER_INFO(m_logger, "{} 设置分派数据线程成功", m_logBase);
- }
- /* 录制功能线程函数 */
- void RecordThread::task()
- {
- SPDLOG_LOGGER_INFO(m_logger, "➢ {} 开始录音线程 ", m_logBase);
- /* 先初始化数据 */
- if(!initData())
- {
- SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase);
- return;
- }
- #if(RECORD_READFILE)
- testOpenData();
- #else
- /* 打开录音通道 */
- if(m_audioRecordDesc.empty())
- {
- SPDLOG_LOGGER_ERROR(m_logger, "{} 声卡描述符为空,无法打开录音通道", m_logBase);
- return;
- }
- if(!m_audioRecord.openRecordChannel(m_audioRecordDesc))
- {
- SPDLOG_LOGGER_ERROR(m_logger, "{} 打开声卡通道失败: {}", m_logBase, m_audioRecordDesc);
- return;
- }
- #endif /* RECORD_READFILE */
- while(m_assignThread == nullptr)
- {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- m_assignThread = getAssignSrcDataThread();
- }
- 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);
- // SPDLOG_LOGGER_TRACE(m_logger, "{} 录音完成,数据大小: {}, 消耗时长:{}ms", m_logBase, m_recordBufferSize, recordDuration.count());
- QDateTime currentTime = QDateTime::currentDateTime();
- /* 将音频数据拷贝给分派数据的线程 */
- if(m_assignThread != nullptr)
- {
- m_assignThread->setSrcData(m_pRecordBuffer, m_recordBufferSize, currentTime);
- }
- // for(int i = 0; i < 30; ++i)
- // {
- // /* 这里可以添加对音频数据的处理,比如噪音检测等 */
- // fmt::print(" |{} {}, short: {}\n", static_cast<uint8_t>(*(m_pRecordBuffer + i*2)), static_cast<uint8_t>(*(m_pRecordBuffer + i*2+1)),
- // static_cast<int16_t>(*(m_pRecordBuffer + i * 2)));
- // }
- memset(m_pRecordBuffer, 0, m_recordBufferSize); /* 清空缓存,准备下一次录音 */
- // std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
- // auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - recordTime);
- // SPDLOG_LOGGER_TRACE(m_logger, "{} 分派数据耗时: {}us", m_logBase, duration.count());
- }
- SPDLOG_LOGGER_WARN(m_logger, "➢ {} 结束录音", m_logBase);
- m_isRunning = false;
- }
- /* 设置数据 */
- bool RecordThread::setData(const AudioSrcData& srcData)
- {
- return true;
- }
- /* 初始化数据 */
- bool RecordThread::initData()
- {
- /* 获取全局数据 */
- m_sampleRate = GInfo.sampleRate(); /* 采样率 */
- m_numChannels = GInfo.numChannels(); /* 声道数 */
- m_bitsPerSample = GInfo.bitsPerSample(); /* 每个采样点的位数 */
- m_oneSecondSize = m_sampleRate * m_numChannels * (m_bitsPerSample / 8); /* 每秒钟的音频数据大小 */
- /* 每次录音的音频数据大小,这里的大小是计算一个音量包所需要的大小 */
- m_recordBufferSize = m_oneSecondSize / VOLUME_INFO_NUM;
- m_oneRecordCount = m_sampleRate / VOLUME_INFO_NUM;
- m_pRecordBuffer = new char[m_recordBufferSize] {0}; /* 录音数据缓存 */
- /* 初始化录制类的参数 */
- m_audioRecord.setRecordParams(m_sampleRate, m_bitsPerSample, m_numChannels);
- /* 设置声卡描述符 */
- // m_audioRecordDesc = fmt::format("hw:{},{}", m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
- m_audioRecordDesc = fmt::format("plughw:{},{}", m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
- return true;
- }
- /* 清除数据 */
- void RecordThread::clearData()
- {
- if(m_pRecordBuffer != nullptr)
- {
- delete[] m_pRecordBuffer;
- m_pRecordBuffer = nullptr;
- }
- m_recordBufferSize = 0;
- }
- /* 获取AssignSrcDataThread线程 */
- AssignSrcDataThread* RecordThread::getAssignSrcDataThread()
- {
- auto pThread = ThreadMan.findRecordThread(EThreadType::Type_AssignSrcData, m_threadInfo.cardRoadInfo.nSoundCardNum, m_threadInfo.cardRoadInfo.roadInfo.nRoadNum);
- if(pThread != nullptr)
- {
- return dynamic_cast<AssignSrcDataThread*>(pThread);
- }
- 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用空循环补偿
- }
- }
|