| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- #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_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<QAudioDeviceInfo> 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<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;
- }
- 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;
- }
|