QT += multimedia
audioplay.h
/*************************************************************************
接口描述:原始音频播放类
拟制:
接口版本:V1.0
时间:20220922
说明:
*************************************************************************/#ifndef AUDIOPLAY_H
#define AUDIOPLAY_H#include <QAudioFormat>
#include <QAudioOutput>
#include <QMutex>
#include <QThread>class AudioThread;
class AudioPlay : public QObject
{Q_OBJECT
public:explicit AudioPlay(QObject *parent = nullptr);~AudioPlay();public:void inputVoice(char *pcVoice, int nLen); //PCM数据输入void setSampleRate(int nSampleRate); //设置采样率void stop(); //停止播放signals:void sendDataSignal(QByteArray qbaData);void inputVoiceSignal(QByteArray qbaData);void setSampleRateSignal(int nSampleRate);void stopAudio();private slots:void audioStateChanged(QAudio::State state);private:QAudioFormat m_audioFormat;int m_nSampleRate;bool m_bAudioOpen;QAudioOutput *m_pAudioOutput;AudioThread *m_pAudioThread;QThread *m_pThread;private:void audioPlay();void setFormat();void releaseAudio();
};class AudioDevice : public QIODevice
{Q_OBJECT
public:explicit AudioDevice(QObject *parent = nullptr);public:void inputData(char *pcData, int nLen);void start();void stop();// QIODevice interface
protected:qint64 readData(char *data, qint64 maxlen);qint64 writeData(const char *data, qint64 len);qint64 bytesAvailable() const;private:QByteArray m_qbaAudioBuffer;
};class AudioThread : public QObject
{Q_OBJECT
public:explicit AudioThread(QAudioOutput *pAudioOutput, QObject *parent = nullptr);~AudioThread();public slots:void inputData(QByteArray qbaData);private:QAudioOutput *m_pAudioOutput;AudioDevice *m_pAudioDevice;
};#endif // AUDIOPLAY_H
audioplay.cpp
#include "audioplay.h"
#include <QDebug>static QMutex m_mutex;AudioPlay::AudioPlay(QObject *parent): QObject(parent)
{m_nSampleRate = 8000;m_bAudioOpen = false;m_pAudioOutput = nullptr;m_pAudioThread = nullptr;setFormat();m_pThread = new QThread;m_pThread->start();connect(this,&AudioPlay::inputVoiceSignal,this,[&](QByteArray qbaData) {if (!m_bAudioOpen) {audioPlay();}emit sendDataSignal(qbaData);},Qt::QueuedConnection);connect(this,&AudioPlay::setSampleRateSignal,this,[&](int nSampleRate) {if (m_nSampleRate != nSampleRate) {m_nSampleRate = nSampleRate;setFormat();}},Qt::QueuedConnection);connect(this, &AudioPlay::stopAudio, this, [&] {m_bAudioOpen = false;releaseAudio();});
}AudioPlay::~AudioPlay()
{releaseAudio();m_pThread->exit();if (m_pThread != nullptr) {m_pThread->deleteLater();m_pThread = nullptr;}
}void AudioPlay::inputVoice(char *pcVoice, int nLen)
{emit inputVoiceSignal(QByteArray(pcVoice, nLen));
}void AudioPlay::setSampleRate(int nSampleRate)
{emit setSampleRateSignal(nSampleRate);
}void AudioPlay::stop()
{emit stopAudio();
}void AudioPlay::audioStateChanged(QAudio::State state)
{switch (state) {case QAudio::IdleState:m_bAudioOpen = false;releaseAudio();setFormat();break;default:break;}
}void AudioPlay::audioPlay()
{QList<QAudioDeviceInfo> outputDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);if (outputDevices.size() <= 0) {return;}if (m_pAudioOutput == nullptr) {m_pAudioOutput = new QAudioOutput(m_audioFormat);connect(m_pAudioOutput, &QAudioOutput::stateChanged, this, &AudioPlay::audioStateChanged);if (m_pAudioThread) {m_pAudioThread->deleteLater();m_pAudioThread = nullptr;}m_pAudioThread = new AudioThread(m_pAudioOutput);m_pAudioThread->moveToThread(m_pThread);connect(this,&AudioPlay::sendDataSignal,m_pAudioThread,&AudioThread::inputData,Qt::QueuedConnection);}m_bAudioOpen = true;
}void AudioPlay::setFormat()
{if (m_pAudioOutput != nullptr) {m_pAudioOutput->reset();m_pAudioOutput->start();}//设置采样率m_audioFormat.setSampleRate(m_nSampleRate);//设置通道数m_audioFormat.setChannelCount(1);//设置采样大小,一般为8位或16位m_audioFormat.setSampleSize(16);//设置编码方式m_audioFormat.setCodec("audio/pcm");//设置字节序m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);//设置样本数据类型m_audioFormat.setSampleType(QAudioFormat::SignedInt);
}void AudioPlay::releaseAudio()
{if (m_pAudioThread != nullptr) {m_pAudioThread->deleteLater();m_pAudioThread = nullptr;}if (m_pAudioOutput != nullptr) {m_pAudioOutput->stop();m_pAudioOutput->deleteLater();m_pAudioOutput = nullptr;}
}AudioDevice::AudioDevice(QObject *parent): QIODevice(parent)
{QMutexLocker locker(&m_mutex);m_qbaAudioBuffer.clear();
}void AudioDevice::inputData(char *pcData, int nLen)
{QMutexLocker locker(&m_mutex);m_qbaAudioBuffer.append(pcData, nLen);
}void AudioDevice::start()
{if (!this->isOpen()) {open(QIODevice::ReadOnly);}
}void AudioDevice::stop()
{QMutexLocker locker(&m_mutex);m_qbaAudioBuffer.clear();this->close();
}qint64 AudioDevice::bytesAvailable() const
{QMutexLocker locker(&m_mutex);qint64 llReturn = m_qbaAudioBuffer.size() + QIODevice::bytesAvailable();return llReturn;
}qint64 AudioDevice::readData(char *data, qint64 maxlen)
{QMutexLocker locker(&m_mutex);memset(data, 0, maxlen);if (m_qbaAudioBuffer.size() < maxlen) {maxlen = m_qbaAudioBuffer.size();}if (maxlen > 0) {memcpy(data, m_qbaAudioBuffer.left(maxlen).data(), maxlen);m_qbaAudioBuffer.remove(0, maxlen);}return maxlen;
}qint64 AudioDevice::writeData(const char *data, qint64 len)
{Q_UNUSED(data);Q_UNUSED(len);return 0;
}AudioThread::AudioThread(QAudioOutput *pAudioOutput, QObject *parent): QObject(parent)
{m_pAudioOutput = nullptr;m_pAudioDevice = nullptr;m_pAudioDevice = new AudioDevice(this);m_pAudioDevice->start();m_pAudioOutput = pAudioOutput;m_pAudioOutput->start(m_pAudioDevice);
}AudioThread::~AudioThread()
{if (m_pAudioDevice != nullptr) {m_pAudioDevice->stop();m_pAudioDevice->deleteLater();m_pAudioDevice = nullptr;}
}void AudioThread::inputData(QByteArray qbaData)
{if (m_pAudioDevice != nullptr) {m_pAudioDevice->inputData(qbaData.data(), qbaData.size());}
}