背景
项目中用到了图灵的语音翻译功能,实现了实时采集麦克风数据并asr以及翻译
解决方案
QT中有一个强大的音频处理的库,可以设置采集的参数,指定采集的设备等,这个强大的类就是QAudioInput,下面介绍如何通过这个类实现音频的设置,采集和保存
QAudioInput属于multimedia模块,故我们在pro文件需要 QT += multimedia
采集音频的参数设置通过QAudioFormat 来设置,告诉计算机应该以什么样的方式进行数据采集,如采样率、声道数量、编码方式等;采用QAudioInput获取声卡输出,即采集麦克风数据,重写iodevcie的 qint64 writeData(const char * data, qint64 maxSize)函数即可实现此功能
QIODevice类是Qt中所有I/O设备的抽象基类,为支持读写数据块的设备提供了通用实现和其他接口。由于是抽象类,因此使用时不能直接实例化,要使用其派生类,如QFile、QBuffer和QTcpSocket。
.h
class VoiceDataSource : public QIODevice
{
Q_OBJECT
public:
explicit VoiceDataSource(QObject *parent = nullptr);
static VoiceDataSource *GetInstance();
Q_INVOKABLE void startRecord();
Q_INVOKABLE void stopRecord();
Q_INVOKABLE void saveAsWavFile();
Q_INVOKABLE QByteArray getVoiceData();
Q_INVOKABLE QByteArray convertUlrData();
Q_INVOKABLE void setResJsonData(QJsonValue resultObj);
Q_INVOKABLE bool isStart();
Q_INVOKABLE QByteArray getSrcString();
Q_INVOKABLE QByteArray getDesString();
void addVoipData(const QByteArray &data)
{
emit sig_getVoipData(data);
}
signals:
void sig_getVoipData(const QByteArray &data);
protected:
qint64 readData(char * data, qint64 maxSize);
qint64 writeData(const char * data, qint64 maxSize);
private:
void startHrsc();
QScopedPointer<QAudioInput> m_audioInput;
WavFileHead m_wavFileHead;
QByteArray m_audioData;
QByteArray m_src;
QByteArray m_des;
};
.cpp 核心函数实现
qint64 VoiceDataSource::writeData(const char * data, qint64 maxSize)
{
#ifdef Q_OS_WINDOWS
m_audioData.append(data, maxSize);
if(TransWebSocket::GetInstance()->isReady())
{
TransWebSocket::GetInstance()->sendApiSpeechData(QByteArray(data,maxSize));
qDebug() << "write size =" << maxSize << m_audioData.size();
}
#endif
return maxSize;
}
void VoiceDataSource::startRecord()
{
#ifdef Q_OS_WINDOWS
m_audioData.clear();
#endif
bool b = open(QIODevice::WriteOnly);
qDebug() << "startRecord open res=" << b;
int sampleRate = 16000;
#ifdef Q_OS_LINUX
int channels = 3;
#endif
#ifdef Q_OS_WINDOWS
int channels = 1;
#endif
int sampleSize = 16;
QAudioFormat formatAudio;
formatAudio.setSampleRate(sampleRate);
formatAudio.setChannelCount(channels);
formatAudio.setSampleSize(sampleSize);
formatAudio.setCodec("audio/pcm");
formatAudio.setByteOrder(QAudioFormat::LittleEndian);
//formatAudio.setSampleType(QAudioFormat::UnSignedInt);
formatAudio.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo inputDevices = QAudioDeviceInfo::defaultInputDevice();
if (!inputDevices.isFormatSupported(formatAudio)) {
qWarning() << "Default format not supported - trying to use nearest";
formatAudio = inputDevices.nearestFormat(formatAudio);
}
m_audioInput.reset(new QAudioInput(inputDevices, formatAudio));
m_audioInput->start(this);
}
void VoiceDataSource::stopRecord()
{
if(m_audioInput->state() == QAudio::StoppedState)
{
return;
}
qDebug() << "VoiceDataSource::stopRecord()";
m_audioInput->stop();
}
void VoiceDataSource::saveAsWavFile()
{
QFile f("voice.pcm");
bool bisOk = f.open(QIODevice::WriteOnly);
if(bisOk == true)
{
#ifdef Q_OS_WINDOWS
f.write(m_audioData.data(), m_audioData.size());
#endif
f.close();
}else{
qDebug() << "voice file open failed";
}
#ifdef Q_OS_WINDOWS
m_audioData.clear();
#endif
}
扩展
由于采集的是pcm数据,所以发送的数据比较大,如果想进一步优化的话,可以对采集的到pcm数据进行编码,常用的编码opus 等
什么是PCM?
PCM(Pulse Code Modulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样、量化、编码转换成的标准数字音频数据。
描述PCM数据的6个参数:
Sample Rate : 采样频率。8kHz(电话)、44.1kHz(CD)、48kHz(DVD)。
Sample Size : 量化位数。通常该值为16-bit。
Number of Channels : 通道个数。常见的音频有立体声(stereo)和单声道(mono)两种类型,立体声包含左声道和右声道。另外还有环绕立体声等其它不太常用的类型。
Sign : 表示样本数据是否是有符号位,比如用一字节表示的样本数据,有符号的话表示范围为-128 ~ 127,无符号是0 ~ 255。
Byte Ordering : 字节序。字节序是little-endian还是big-endian。通常均为little-endian。字节序说明见第4节。
Integer Or Floating Point : 整形或浮点型。大多数格式的PCM样本数据使用整形表示,而在一些对精度要求高的应用方面,使用浮点类型表示PCM样本数据。
什么是WAV
WAV:wav是一种无损的音频文件格式,WAV符合 PIFF(Resource Interchange File Format)规范。所有的WAV都有一个文件头,这个文件头音频流的编码参数。WAV对音频流的编码没有硬性规定,除了PCM之外,还有几乎所有支持ACM规范的编码都可以为WAV的音频流进行编码。
WAV和PCM的关系
WAV可以使用多种音频编码来压缩其音频流,不过我们常见的都是音频流被PCM编码处理的WAV,但这不表示WAV只能使用PCM编码,MP3编码同样也可以运用在WAV中,和AVI一样,只要安装好了相应的Decode,就可以欣赏这些WAV了。在Windows平台下,基于PCM编码的WAV是被支持得最好的音频格式,所有音频软件都能完美支持,由于本身可以达到较高的音质的要求,因此,WAV也是音乐编辑创作的首选格式,适合保存音乐素材。因此,基于PCM编码的WAV被作为了一种中介的格式,常常使用在其他编码的相互转换之中,例如MP3转换成WMA。
简单来说:pcm是无损wav文件中音频数据的一种编码方式,但wav还可以用其它方式编码。