#include "audio_qt_capturer.h" #include "qaudio.h" #include #include #include AudioInfo::AudioInfo(const QAudioFormat& format) : m_format(format) { switch (m_format.sampleSize()) { case 8: switch (m_format.sampleType()) { case QAudioFormat::UnSignedInt: m_maxAmplitude = 255; break; case QAudioFormat::SignedInt: m_maxAmplitude = 127; break; default: break; } break; case 16: switch (m_format.sampleType()) { case QAudioFormat::UnSignedInt: m_maxAmplitude = 65535; break; case QAudioFormat::SignedInt: m_maxAmplitude = 32767; break; default: break; } break; case 32: switch (m_format.sampleType()) { case QAudioFormat::UnSignedInt: m_maxAmplitude = 0xffffffff; break; case QAudioFormat::SignedInt: m_maxAmplitude = 0x7fffffff; break; case QAudioFormat::Float: m_maxAmplitude = 0x7fffffff; // Kind of default: break; } break; default: break; } } void AudioInfo::start() { open(QIODevice::WriteOnly); } void AudioInfo::stop() { close(); } qint64 AudioInfo::readData(char* data, qint64 maxlen) { Q_UNUSED(data) Q_UNUSED(maxlen) return 0; } qint64 AudioInfo::writeData(const char* data, qint64 len) { if (m_maxAmplitude) { Q_ASSERT(m_format.sampleSize() % 8 == 0); const int channelBytes = m_format.sampleSize() / 8; const int sampleBytes = m_format.channelCount() * channelBytes; Q_ASSERT(len % sampleBytes == 0); const int numSamples = len / sampleBytes; quint32 maxValue = 0; const unsigned char* ptr = reinterpret_cast(data); for (int i = 0; i < numSamples; ++i) { for (int j = 0; j < m_format.channelCount(); ++j) { quint32 value = 0; if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::UnSignedInt) { value = *reinterpret_cast(ptr); } else if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::SignedInt) { value = qAbs(*reinterpret_cast(ptr)); } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::UnSignedInt) { if (m_format.byteOrder() == QAudioFormat::LittleEndian) value = qFromLittleEndian(ptr); else value = qFromBigEndian(ptr); } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::SignedInt) { if (m_format.byteOrder() == QAudioFormat::LittleEndian) value = qAbs(qFromLittleEndian(ptr)); else value = qAbs(qFromBigEndian(ptr)); } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::UnSignedInt) { if (m_format.byteOrder() == QAudioFormat::LittleEndian) value = qFromLittleEndian(ptr); else value = qFromBigEndian(ptr); } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::SignedInt) { if (m_format.byteOrder() == QAudioFormat::LittleEndian) value = qAbs(qFromLittleEndian(ptr)); else value = qAbs(qFromBigEndian(ptr)); } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::Float) { value = qAbs(*reinterpret_cast(ptr) * 0x7fffffff); // assumes 0-1.0 } maxValue = qMax(value, maxValue); ptr += channelBytes; } } maxValue = qMin(maxValue, m_maxAmplitude); m_level = qreal(maxValue) / m_maxAmplitude; } emit update(); return len; } QtAudioCapturer::QtAudioCapturer(QObject* parent) : QObject(parent) , m_deviceType(Microphone) , m_callback(nullptr) , m_userInfo(nullptr) , m_isRunning(false) , m_audioDevice(nullptr) { // 初始化缓冲区 m_buffer.open(QIODevice::ReadWrite); // 设置处理定时器 connect(&m_processTimer, &QTimer::timeout, this, &QtAudioCapturer::processAudioData); } QtAudioCapturer::~QtAudioCapturer() { Stop(); } bool QtAudioCapturer::Init(Type deviceType, CallBack callback, void* userInfo) { m_deviceType = deviceType; m_callback = callback; m_userInfo = userInfo; setupAudioFormat(); if (m_deviceType == Microphone) { return initMicrophone(); } else { return initSpeaker(); } } bool QtAudioCapturer::Start() { if (m_isRunning) { qDebug() << "QtAudioCapturer::Start - 已经在运行中"; return true; } if (!m_audioInput && m_deviceType == Microphone) { qWarning() << "QtAudioCapturer::Start - 音频输入未初始化"; return false; } qDebug() << "QtAudioCapturer::Start - 开始捕获音频,设备类型:" << (m_deviceType == Microphone ? "麦克风" : "扬声器"); if (m_deviceType == Microphone && m_audioInput) { // 设置更合理的缓冲区大小 // int bufferSize = 8192; // 或者使用计算值:m_qtAudioFormat.sampleRate() * m_qtAudioFormat.channelCount() * 2 / 5; // m_audioInput->setBufferSize(bufferSize); // qDebug() << "QtAudioCapturer::Start - 设置缓冲区大小:" << bufferSize; // qDebug() << "QtAudioCapturer::Start - 缓冲区大小:" << m_audioInput->bufferSize(); // 设置更短的通知间隔,提高响应性 // m_audioInput->setNotifyInterval(20); // 20毫秒 // 启动音频输入 m_audioDevice = m_audioInput->start(); if (!m_audioDevice) { qWarning() << "QtAudioCapturer::Start - 启动音频输入失败"; return false; } // qDebug() << "QtAudioCapturer::Start - 麦克风启动成功,缓冲区大小:" // << m_audioInput->bufferSize(); // 连接信号 connect(m_audioDevice, &QIODevice::readyRead, this, &QtAudioCapturer::handleReadyRead); // 添加一个定时器,定期检查音频状态 QTimer* statusTimer = new QTimer(this); connect(statusTimer, &QTimer::timeout, [this]() { // qDebug() << "QtAudioCapturer::StatusCheck - 音频输入状态:" << m_audioInput->state() // << "错误:" << m_audioInput->error() // << "处理字节数:" << m_audioInput->processedUSecs() // << "可用字节数:" << (m_audioDevice ? m_audioDevice->bytesAvailable() : 0); // 如果状态不是活动状态,尝试重新启动 if (m_audioInput->state() != QAudio::ActiveState) { qDebug() << "QtAudioCapturer::StatusCheck - 尝试重新启动音频输入"; m_audioInput->stop(); m_audioDevice = m_audioInput->start(); if (m_audioDevice) { connect(m_audioDevice, &QIODevice::readyRead, this, &QtAudioCapturer::handleReadyRead); } } }); statusTimer->start(2000); // 每2秒检查一次 } else if (m_deviceType == Speaker) { // 系统声音捕获的实现 qDebug() << "QtAudioCapturer::Start - 尝试启动扬声器捕获"; } m_isRunning = true; return true; } void QtAudioCapturer::Stop() { if (!m_isRunning) { return; } m_processTimer.stop(); if (m_audioDevice) { disconnect(m_audioDevice, &QIODevice::readyRead, this, &QtAudioCapturer::handleReadyRead); m_audioDevice = nullptr; } if (m_audioInput) { m_audioInput->stop(); } m_buffer.buffer().clear(); m_buffer.seek(0); m_isRunning = false; } const AudioFormat& QtAudioCapturer::GetFormat() const { return m_audioFormat; } void QtAudioCapturer::handleReadyRead() { // qDebug() << "handleReadyRead" << m_audioDevice << m_audioDevice->bytesAvailable(); if (m_audioDevice) { QByteArray data = m_audioDevice->readAll(); // qDebug() << "QtAudioCapturer::handleReadyRead - 收到数据大小:" << data.size() << "字节"; // 检查数据是否有效 if (data.size() > 0) { // 计算音量级别用于调试 // float volume = calculateVolume(data); // qDebug() << "QtAudioCapturer::handleReadyRead - 计算的音量级别:" << volume; // 确保回调被调用 if (m_callback) { m_callback(data.data(), data.size(), m_userInfo); } else { qWarning() << "QtAudioCapturer::handleReadyRead - 回调函数为空"; } } // 不再需要将数据写入缓冲区,因为已经直接处理了 // m_buffer.write(data); } else { // 减少日志输出频率,只在调试时启用 // qDebug() << "QtAudioCapturer::handleReadyRead - 没有可用数据"; } } void QtAudioCapturer::processAudioData() { QByteArray data = m_buffer.buffer(); if (data.size() > 0 && m_callback) { qDebug() << "QtAudioCapturer::processAudioData - 处理缓冲区数据,大小:" << data.size() << "字节"; // 如果没有在 handleReadyRead 中直接调用回调,则在这里调用 // m_callback(data.data(), data.size(), m_userInfo); // 清空缓冲区 m_buffer.buffer().clear(); m_buffer.seek(0); } } void QtAudioCapturer::onAudioNotify() { if (m_audioDevice && m_audioDevice->bytesAvailable() > 0) { handleReadyRead(); } else { // 尝试直接从 QAudioInput 读取数据 QByteArray buffer(m_audioInput->bufferSize() / 4, 0); qint64 len = buffer.size(); if (len > 0) { qDebug() << "QtAudioCapturer::onAudioNotify - 直接读取到数据,大小:" << len << "字节"; buffer.resize(len); // 调用回调函数 if (m_callback) { m_callback(buffer.data(), buffer.size(), m_userInfo); } } } } bool QtAudioCapturer::initMicrophone() { // 获取默认输入设备 QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultInputDevice(); qDebug() << "QtAudioCapturer::initMicrophone - 默认输入设备:" << deviceInfo.deviceName(); // 检查设备是否有效 if (deviceInfo.isNull()) { qWarning() << "QtAudioCapturer::initMicrophone - 没有可用的音频输入设备"; return false; } // 列出所有可用的音频输入设备 qDebug() << "QtAudioCapturer::initMicrophone - 可用的音频输入设备:"; for (const auto& device : QAudioDeviceInfo::availableDevices(QAudio::AudioInput)) { qDebug() << " " << device.deviceName(); } // 检查格式是否支持 if (!deviceInfo.isFormatSupported(m_qtAudioFormat)) { qWarning() << "QtAudioCapturer::initMicrophone - 默认格式不支持,尝试使用最接近的格式"; // 尝试几种常用格式 QList sampleRates = {44100, 48000, 16000, 8000}; QList channelCounts = {2, 1}; QList sampleSizes = {16, 8}; bool formatFound = false; for (int rate : sampleRates) { for (int channels : channelCounts) { for (int size : sampleSizes) { QAudioFormat format; format.setSampleRate(rate); format.setChannelCount(channels); format.setSampleSize(size); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); format.setSampleType(QAudioFormat::SignedInt); if (deviceInfo.isFormatSupported(format)) { m_qtAudioFormat = format; formatFound = true; qDebug() << "QtAudioCapturer::initMicrophone - 找到支持的格式:" << "采样率=" << rate << "通道数=" << channels << "采样大小=" << size; break; } } if (formatFound) break; } if (formatFound) break; } if (!formatFound) { // 使用设备支持的最接近的格式 m_qtAudioFormat = deviceInfo.nearestFormat(m_qtAudioFormat); qDebug() << "QtAudioCapturer::initMicrophone - 使用最接近的格式:" << "采样率=" << m_qtAudioFormat.sampleRate() << "通道数=" << m_qtAudioFormat.channelCount() << "采样大小=" << m_qtAudioFormat.sampleSize(); } // 更新 AudioFormat m_audioFormat = AudioFormat(m_qtAudioFormat.sampleRate(), m_qtAudioFormat.channelCount(), m_qtAudioFormat.sampleSize()); } // 创建音频输入 m_audioInput = std::make_unique(deviceInfo, m_qtAudioFormat, this); m_audioInfo.reset(new AudioInfo(m_qtAudioFormat)); m_audioInfo->start(); qDebug() << "QtAudioCapturer::initMicrophone - 音频输入创建成功,格式:" << "采样率=" << m_qtAudioFormat.sampleRate() << "通道数=" << m_qtAudioFormat.channelCount() << "采样大小=" << m_qtAudioFormat.sampleSize(); return true; } bool QtAudioCapturer::initSpeaker() { return false; } void QtAudioCapturer::setupAudioFormat() { // 设置Qt音频格式 m_qtAudioFormat.setSampleRate(44100); // 与原代码中的 DEFAULT_SAMPLE_RATE 保持一致 m_qtAudioFormat.setChannelCount(1); // 改为单声道,提高兼容性 m_qtAudioFormat.setSampleSize(16); // 与原代码中的 DEFAULT_BITS_PER_SAMPLE 保持一致 m_qtAudioFormat.setCodec("audio/pcm"); m_qtAudioFormat.setByteOrder(QAudioFormat::LittleEndian); m_qtAudioFormat.setSampleType(QAudioFormat::SignedInt); // 设置IAudioCapturer使用的格式 m_audioFormat = AudioFormat(m_qtAudioFormat.sampleRate(), m_qtAudioFormat.channelCount(), m_qtAudioFormat.sampleSize()); } float QtAudioCapturer::calculateVolume(const QByteArray& data) { // 计算音频数据的音量级别 if (data.isEmpty()) { return 0.0f; } // 假设数据是16位有符号整数 const int16_t* samples = reinterpret_cast(data.constData()); int sampleCount = data.size() / sizeof(int16_t); // 计算平均绝对值 float sum = 0.0f; for (int i = 0; i < sampleCount; ++i) { sum += std::abs(samples[i]); } // 归一化到0-1范围 float avgAmp = sum / (sampleCount * 32768.0f); return avgAmp; }