QT += multimedia
audioplay.h
cpp
/*************************************************************************
接口描述:原始音频播放类
拟制:
接口版本: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
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());
}
}