#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_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) { m_deviceType = deviceType; 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) { m_audioDevice = m_audioInput->start(); if (!m_audioDevice) { qWarning() << "QtAudioCapturer::Start - 启动音频输入失败"; return false; } qDebug() << "QtAudioCapturer::Start - QAudioInput state:" << m_audioInput->state(); qDebug() << "QtAudioCapturer::Start - QAudioInput error:" << m_audioInput->error(); connect(m_audioDevice, &QIODevice::readyRead, this, &QtAudioCapturer::handleReadyRead); } 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 called, m_audioDevice:" << m_audioDevice; if (m_audioDevice) { QByteArray data = m_audioDevice->readAll(); //qDebug() << "handleReadyRead: read data size:" << data.size(); if (data.size() > 0) { QMutexLocker locker(&m_mutex); m_dataBuffer.append(data); //qDebug() << "Audio data appended, buffer size now:" << m_dataBuffer.size(); } } } int QtAudioCapturer::readAudioData(char* buf, int maxLen) { QMutexLocker locker(&m_mutex); int toRead = qMin(maxLen, m_dataBuffer.size()); // qDebug() << "readAudioData called, buffer size:" << m_dataBuffer.size() << ", toRead:" << toRead; if (toRead > 0) { memcpy(buf, m_dataBuffer.constData(), toRead); m_dataBuffer.remove(0, toRead); } return toRead; } void QtAudioCapturer::processAudioData() { QByteArray data = m_buffer.buffer(); if (data.size() > 0) { // qDebug() << "QtAudioCapturer::processAudioData - 处理缓冲区数据,大小:" << data.size() // << "字节"; // 清空缓冲区 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() { qDebug() << "QtAudioCapturer::initMicrophone - 默认输入设备: " << QAudioDeviceInfo::defaultInputDevice().deviceName(); QList availableDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); qDebug() << "QtAudioCapturer::initMicrophone - 可用的音频输入设备:"; for (const QAudioDeviceInfo& deviceInfo : availableDevices) { qDebug() << " " << deviceInfo.deviceName(); } AudioFormat defaultFormat = IAudioCapturer::GetDefaultFormat(); QAudioFormat format; format.setSampleRate(defaultFormat.sampleRate); format.setChannelCount(defaultFormat.channels); format.setSampleSize(defaultFormat.bitsPerSample); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); format.setSampleType(QAudioFormat::SignedInt); QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultInputDevice(); if (!deviceInfo.isFormatSupported(format)) { qWarning() << "QtAudioCapturer::initMicrophone - 默认格式不支持,尝试使用最接近的格式"; format = deviceInfo.nearestFormat(format); } m_qtAudioFormat = format; 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; } 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; }