| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 |
- #include "audio_qt_capturer.h"
- #include "qaudio.h"
- #include <QAudioDeviceInfo>
- #include <QDebug>
- #include <qendian.h>
- 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<const unsigned char*>(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<const quint8*>(ptr);
- } else if (m_format.sampleSize() == 8
- && m_format.sampleType() == QAudioFormat::SignedInt) {
- value = qAbs(*reinterpret_cast<const qint8*>(ptr));
- } else if (m_format.sampleSize() == 16
- && m_format.sampleType() == QAudioFormat::UnSignedInt) {
- if (m_format.byteOrder() == QAudioFormat::LittleEndian)
- value = qFromLittleEndian<quint16>(ptr);
- else
- value = qFromBigEndian<quint16>(ptr);
- } else if (m_format.sampleSize() == 16
- && m_format.sampleType() == QAudioFormat::SignedInt) {
- if (m_format.byteOrder() == QAudioFormat::LittleEndian)
- value = qAbs(qFromLittleEndian<qint16>(ptr));
- else
- value = qAbs(qFromBigEndian<qint16>(ptr));
- } else if (m_format.sampleSize() == 32
- && m_format.sampleType() == QAudioFormat::UnSignedInt) {
- if (m_format.byteOrder() == QAudioFormat::LittleEndian)
- value = qFromLittleEndian<quint32>(ptr);
- else
- value = qFromBigEndian<quint32>(ptr);
- } else if (m_format.sampleSize() == 32
- && m_format.sampleType() == QAudioFormat::SignedInt) {
- if (m_format.byteOrder() == QAudioFormat::LittleEndian)
- value = qAbs(qFromLittleEndian<qint32>(ptr));
- else
- value = qAbs(qFromBigEndian<qint32>(ptr));
- } else if (m_format.sampleSize() == 32
- && m_format.sampleType() == QAudioFormat::Float) {
- value = qAbs(*reinterpret_cast<const float*>(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<int> sampleRates = {44100, 48000, 16000, 8000};
- QList<int> channelCounts = {2, 1};
- QList<int> 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<QAudioInput>(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<const int16_t*>(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;
- }
|