audio_qt_capturer.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. #include "audio_qt_capturer.h"
  2. #include "qaudio.h"
  3. #include <QAudioDeviceInfo>
  4. #include <QDebug>
  5. #include <qendian.h>
  6. AudioInfo::AudioInfo(const QAudioFormat& format)
  7. : m_format(format)
  8. {
  9. switch (m_format.sampleSize()) {
  10. case 8:
  11. switch (m_format.sampleType()) {
  12. case QAudioFormat::UnSignedInt:
  13. m_maxAmplitude = 255;
  14. break;
  15. case QAudioFormat::SignedInt:
  16. m_maxAmplitude = 127;
  17. break;
  18. default:
  19. break;
  20. }
  21. break;
  22. case 16:
  23. switch (m_format.sampleType()) {
  24. case QAudioFormat::UnSignedInt:
  25. m_maxAmplitude = 65535;
  26. break;
  27. case QAudioFormat::SignedInt:
  28. m_maxAmplitude = 32767;
  29. break;
  30. default:
  31. break;
  32. }
  33. break;
  34. case 32:
  35. switch (m_format.sampleType()) {
  36. case QAudioFormat::UnSignedInt:
  37. m_maxAmplitude = 0xffffffff;
  38. break;
  39. case QAudioFormat::SignedInt:
  40. m_maxAmplitude = 0x7fffffff;
  41. break;
  42. case QAudioFormat::Float:
  43. m_maxAmplitude = 0x7fffffff; // Kind of
  44. default:
  45. break;
  46. }
  47. break;
  48. default:
  49. break;
  50. }
  51. }
  52. void AudioInfo::start()
  53. {
  54. open(QIODevice::WriteOnly);
  55. }
  56. void AudioInfo::stop()
  57. {
  58. close();
  59. }
  60. qint64 AudioInfo::readData(char* data, qint64 maxlen)
  61. {
  62. Q_UNUSED(data)
  63. Q_UNUSED(maxlen)
  64. return 0;
  65. }
  66. qint64 AudioInfo::writeData(const char* data, qint64 len)
  67. {
  68. if (m_maxAmplitude) {
  69. Q_ASSERT(m_format.sampleSize() % 8 == 0);
  70. const int channelBytes = m_format.sampleSize() / 8;
  71. const int sampleBytes = m_format.channelCount() * channelBytes;
  72. Q_ASSERT(len % sampleBytes == 0);
  73. const int numSamples = len / sampleBytes;
  74. quint32 maxValue = 0;
  75. const unsigned char* ptr = reinterpret_cast<const unsigned char*>(data);
  76. for (int i = 0; i < numSamples; ++i) {
  77. for (int j = 0; j < m_format.channelCount(); ++j) {
  78. quint32 value = 0;
  79. if (m_format.sampleSize() == 8
  80. && m_format.sampleType() == QAudioFormat::UnSignedInt) {
  81. value = *reinterpret_cast<const quint8*>(ptr);
  82. } else if (m_format.sampleSize() == 8
  83. && m_format.sampleType() == QAudioFormat::SignedInt) {
  84. value = qAbs(*reinterpret_cast<const qint8*>(ptr));
  85. } else if (m_format.sampleSize() == 16
  86. && m_format.sampleType() == QAudioFormat::UnSignedInt) {
  87. if (m_format.byteOrder() == QAudioFormat::LittleEndian)
  88. value = qFromLittleEndian<quint16>(ptr);
  89. else
  90. value = qFromBigEndian<quint16>(ptr);
  91. } else if (m_format.sampleSize() == 16
  92. && m_format.sampleType() == QAudioFormat::SignedInt) {
  93. if (m_format.byteOrder() == QAudioFormat::LittleEndian)
  94. value = qAbs(qFromLittleEndian<qint16>(ptr));
  95. else
  96. value = qAbs(qFromBigEndian<qint16>(ptr));
  97. } else if (m_format.sampleSize() == 32
  98. && m_format.sampleType() == QAudioFormat::UnSignedInt) {
  99. if (m_format.byteOrder() == QAudioFormat::LittleEndian)
  100. value = qFromLittleEndian<quint32>(ptr);
  101. else
  102. value = qFromBigEndian<quint32>(ptr);
  103. } else if (m_format.sampleSize() == 32
  104. && m_format.sampleType() == QAudioFormat::SignedInt) {
  105. if (m_format.byteOrder() == QAudioFormat::LittleEndian)
  106. value = qAbs(qFromLittleEndian<qint32>(ptr));
  107. else
  108. value = qAbs(qFromBigEndian<qint32>(ptr));
  109. } else if (m_format.sampleSize() == 32
  110. && m_format.sampleType() == QAudioFormat::Float) {
  111. value = qAbs(*reinterpret_cast<const float*>(ptr) * 0x7fffffff); // assumes 0-1.0
  112. }
  113. maxValue = qMax(value, maxValue);
  114. ptr += channelBytes;
  115. }
  116. }
  117. maxValue = qMin(maxValue, m_maxAmplitude);
  118. m_level = qreal(maxValue) / m_maxAmplitude;
  119. }
  120. emit update();
  121. return len;
  122. }
  123. QtAudioCapturer::QtAudioCapturer(QObject* parent)
  124. : QObject(parent)
  125. , m_deviceType(Microphone)
  126. , m_callback(nullptr)
  127. , m_userInfo(nullptr)
  128. , m_isRunning(false)
  129. , m_audioDevice(nullptr)
  130. {
  131. // 初始化缓冲区
  132. m_buffer.open(QIODevice::ReadWrite);
  133. // 设置处理定时器
  134. connect(&m_processTimer, &QTimer::timeout, this, &QtAudioCapturer::processAudioData);
  135. }
  136. QtAudioCapturer::~QtAudioCapturer()
  137. {
  138. Stop();
  139. }
  140. bool QtAudioCapturer::Init(Type deviceType, CallBack callback, void* userInfo)
  141. {
  142. m_deviceType = deviceType;
  143. m_callback = callback;
  144. m_userInfo = userInfo;
  145. setupAudioFormat();
  146. if (m_deviceType == Microphone) {
  147. return initMicrophone();
  148. } else {
  149. return initSpeaker();
  150. }
  151. }
  152. bool QtAudioCapturer::Start()
  153. {
  154. if (m_isRunning) {
  155. qDebug() << "QtAudioCapturer::Start - 已经在运行中";
  156. return true;
  157. }
  158. if (!m_audioInput && m_deviceType == Microphone) {
  159. qWarning() << "QtAudioCapturer::Start - 音频输入未初始化";
  160. return false;
  161. }
  162. qDebug() << "QtAudioCapturer::Start - 开始捕获音频,设备类型:"
  163. << (m_deviceType == Microphone ? "麦克风" : "扬声器");
  164. if (m_deviceType == Microphone && m_audioInput) {
  165. // 设置更合理的缓冲区大小
  166. // int bufferSize = 8192;
  167. // 或者使用计算值:m_qtAudioFormat.sampleRate() * m_qtAudioFormat.channelCount() * 2 / 5;
  168. // m_audioInput->setBufferSize(bufferSize);
  169. // qDebug() << "QtAudioCapturer::Start - 设置缓冲区大小:" << bufferSize;
  170. // qDebug() << "QtAudioCapturer::Start - 缓冲区大小:" << m_audioInput->bufferSize();
  171. // 设置更短的通知间隔,提高响应性
  172. // m_audioInput->setNotifyInterval(20); // 20毫秒
  173. // 启动音频输入
  174. m_audioDevice = m_audioInput->start();
  175. if (!m_audioDevice) {
  176. qWarning() << "QtAudioCapturer::Start - 启动音频输入失败";
  177. return false;
  178. }
  179. // qDebug() << "QtAudioCapturer::Start - 麦克风启动成功,缓冲区大小:"
  180. // << m_audioInput->bufferSize();
  181. // 连接信号
  182. connect(m_audioDevice, &QIODevice::readyRead, this, &QtAudioCapturer::handleReadyRead);
  183. // 添加一个定时器,定期检查音频状态
  184. QTimer* statusTimer = new QTimer(this);
  185. connect(statusTimer, &QTimer::timeout, [this]() {
  186. // qDebug() << "QtAudioCapturer::StatusCheck - 音频输入状态:" << m_audioInput->state()
  187. // << "错误:" << m_audioInput->error()
  188. // << "处理字节数:" << m_audioInput->processedUSecs()
  189. // << "可用字节数:" << (m_audioDevice ? m_audioDevice->bytesAvailable() : 0);
  190. // 如果状态不是活动状态,尝试重新启动
  191. if (m_audioInput->state() != QAudio::ActiveState) {
  192. qDebug() << "QtAudioCapturer::StatusCheck - 尝试重新启动音频输入";
  193. m_audioInput->stop();
  194. m_audioDevice = m_audioInput->start();
  195. if (m_audioDevice) {
  196. connect(m_audioDevice,
  197. &QIODevice::readyRead,
  198. this,
  199. &QtAudioCapturer::handleReadyRead);
  200. }
  201. }
  202. });
  203. statusTimer->start(2000); // 每2秒检查一次
  204. } else if (m_deviceType == Speaker) {
  205. // 系统声音捕获的实现
  206. qDebug() << "QtAudioCapturer::Start - 尝试启动扬声器捕获";
  207. }
  208. m_isRunning = true;
  209. return true;
  210. }
  211. void QtAudioCapturer::Stop()
  212. {
  213. if (!m_isRunning) {
  214. return;
  215. }
  216. m_processTimer.stop();
  217. if (m_audioDevice) {
  218. disconnect(m_audioDevice, &QIODevice::readyRead, this, &QtAudioCapturer::handleReadyRead);
  219. m_audioDevice = nullptr;
  220. }
  221. if (m_audioInput) {
  222. m_audioInput->stop();
  223. }
  224. m_buffer.buffer().clear();
  225. m_buffer.seek(0);
  226. m_isRunning = false;
  227. }
  228. const AudioFormat& QtAudioCapturer::GetFormat() const
  229. {
  230. return m_audioFormat;
  231. }
  232. void QtAudioCapturer::handleReadyRead()
  233. {
  234. // qDebug() << "handleReadyRead" << m_audioDevice << m_audioDevice->bytesAvailable();
  235. if (m_audioDevice) {
  236. QByteArray data = m_audioDevice->readAll();
  237. // qDebug() << "QtAudioCapturer::handleReadyRead - 收到数据大小:" << data.size() << "字节";
  238. // 检查数据是否有效
  239. if (data.size() > 0) {
  240. // 计算音量级别用于调试
  241. // float volume = calculateVolume(data);
  242. // qDebug() << "QtAudioCapturer::handleReadyRead - 计算的音量级别:" << volume;
  243. // 确保回调被调用
  244. if (m_callback) {
  245. m_callback(data.data(), data.size(), m_userInfo);
  246. } else {
  247. qWarning() << "QtAudioCapturer::handleReadyRead - 回调函数为空";
  248. }
  249. }
  250. // 不再需要将数据写入缓冲区,因为已经直接处理了
  251. // m_buffer.write(data);
  252. } else {
  253. // 减少日志输出频率,只在调试时启用
  254. // qDebug() << "QtAudioCapturer::handleReadyRead - 没有可用数据";
  255. }
  256. }
  257. void QtAudioCapturer::processAudioData()
  258. {
  259. QByteArray data = m_buffer.buffer();
  260. if (data.size() > 0 && m_callback) {
  261. qDebug() << "QtAudioCapturer::processAudioData - 处理缓冲区数据,大小:" << data.size()
  262. << "字节";
  263. // 如果没有在 handleReadyRead 中直接调用回调,则在这里调用
  264. // m_callback(data.data(), data.size(), m_userInfo);
  265. // 清空缓冲区
  266. m_buffer.buffer().clear();
  267. m_buffer.seek(0);
  268. }
  269. }
  270. void QtAudioCapturer::onAudioNotify()
  271. {
  272. if (m_audioDevice && m_audioDevice->bytesAvailable() > 0) {
  273. handleReadyRead();
  274. } else {
  275. // 尝试直接从 QAudioInput 读取数据
  276. QByteArray buffer(m_audioInput->bufferSize() / 4, 0);
  277. qint64 len = buffer.size();
  278. if (len > 0) {
  279. qDebug() << "QtAudioCapturer::onAudioNotify - 直接读取到数据,大小:" << len << "字节";
  280. buffer.resize(len);
  281. // 调用回调函数
  282. if (m_callback) {
  283. m_callback(buffer.data(), buffer.size(), m_userInfo);
  284. }
  285. }
  286. }
  287. }
  288. bool QtAudioCapturer::initMicrophone()
  289. {
  290. // 获取默认输入设备
  291. QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultInputDevice();
  292. qDebug() << "QtAudioCapturer::initMicrophone - 默认输入设备:" << deviceInfo.deviceName();
  293. // 检查设备是否有效
  294. if (deviceInfo.isNull()) {
  295. qWarning() << "QtAudioCapturer::initMicrophone - 没有可用的音频输入设备";
  296. return false;
  297. }
  298. // 列出所有可用的音频输入设备
  299. qDebug() << "QtAudioCapturer::initMicrophone - 可用的音频输入设备:";
  300. for (const auto& device : QAudioDeviceInfo::availableDevices(QAudio::AudioInput)) {
  301. qDebug() << " " << device.deviceName();
  302. }
  303. // 检查格式是否支持
  304. if (!deviceInfo.isFormatSupported(m_qtAudioFormat)) {
  305. qWarning() << "QtAudioCapturer::initMicrophone - 默认格式不支持,尝试使用最接近的格式";
  306. // 尝试几种常用格式
  307. QList<int> sampleRates = {44100, 48000, 16000, 8000};
  308. QList<int> channelCounts = {2, 1};
  309. QList<int> sampleSizes = {16, 8};
  310. bool formatFound = false;
  311. for (int rate : sampleRates) {
  312. for (int channels : channelCounts) {
  313. for (int size : sampleSizes) {
  314. QAudioFormat format;
  315. format.setSampleRate(rate);
  316. format.setChannelCount(channels);
  317. format.setSampleSize(size);
  318. format.setCodec("audio/pcm");
  319. format.setByteOrder(QAudioFormat::LittleEndian);
  320. format.setSampleType(QAudioFormat::SignedInt);
  321. if (deviceInfo.isFormatSupported(format)) {
  322. m_qtAudioFormat = format;
  323. formatFound = true;
  324. qDebug() << "QtAudioCapturer::initMicrophone - 找到支持的格式:"
  325. << "采样率=" << rate << "通道数=" << channels
  326. << "采样大小=" << size;
  327. break;
  328. }
  329. }
  330. if (formatFound)
  331. break;
  332. }
  333. if (formatFound)
  334. break;
  335. }
  336. if (!formatFound) {
  337. // 使用设备支持的最接近的格式
  338. m_qtAudioFormat = deviceInfo.nearestFormat(m_qtAudioFormat);
  339. qDebug() << "QtAudioCapturer::initMicrophone - 使用最接近的格式:"
  340. << "采样率=" << m_qtAudioFormat.sampleRate()
  341. << "通道数=" << m_qtAudioFormat.channelCount()
  342. << "采样大小=" << m_qtAudioFormat.sampleSize();
  343. }
  344. // 更新 AudioFormat
  345. m_audioFormat = AudioFormat(m_qtAudioFormat.sampleRate(),
  346. m_qtAudioFormat.channelCount(),
  347. m_qtAudioFormat.sampleSize());
  348. }
  349. // 创建音频输入
  350. m_audioInput = std::make_unique<QAudioInput>(deviceInfo, m_qtAudioFormat, this);
  351. m_audioInfo.reset(new AudioInfo(m_qtAudioFormat));
  352. m_audioInfo->start();
  353. qDebug() << "QtAudioCapturer::initMicrophone - 音频输入创建成功,格式:"
  354. << "采样率=" << m_qtAudioFormat.sampleRate()
  355. << "通道数=" << m_qtAudioFormat.channelCount()
  356. << "采样大小=" << m_qtAudioFormat.sampleSize();
  357. return true;
  358. }
  359. bool QtAudioCapturer::initSpeaker()
  360. {
  361. return false;
  362. }
  363. void QtAudioCapturer::setupAudioFormat()
  364. {
  365. // 设置Qt音频格式
  366. m_qtAudioFormat.setSampleRate(44100); // 与原代码中的 DEFAULT_SAMPLE_RATE 保持一致
  367. m_qtAudioFormat.setChannelCount(1); // 改为单声道,提高兼容性
  368. m_qtAudioFormat.setSampleSize(16); // 与原代码中的 DEFAULT_BITS_PER_SAMPLE 保持一致
  369. m_qtAudioFormat.setCodec("audio/pcm");
  370. m_qtAudioFormat.setByteOrder(QAudioFormat::LittleEndian);
  371. m_qtAudioFormat.setSampleType(QAudioFormat::SignedInt);
  372. // 设置IAudioCapturer使用的格式
  373. m_audioFormat = AudioFormat(m_qtAudioFormat.sampleRate(),
  374. m_qtAudioFormat.channelCount(),
  375. m_qtAudioFormat.sampleSize());
  376. }
  377. float QtAudioCapturer::calculateVolume(const QByteArray& data)
  378. {
  379. // 计算音频数据的音量级别
  380. if (data.isEmpty()) {
  381. return 0.0f;
  382. }
  383. // 假设数据是16位有符号整数
  384. const int16_t* samples = reinterpret_cast<const int16_t*>(data.constData());
  385. int sampleCount = data.size() / sizeof(int16_t);
  386. // 计算平均绝对值
  387. float sum = 0.0f;
  388. for (int i = 0; i < sampleCount; ++i) {
  389. sum += std::abs(samples[i]);
  390. }
  391. // 归一化到0-1范围
  392. float avgAmp = sum / (sampleCount * 32768.0f);
  393. return avgAmp;
  394. }