gpt4 book ai didi

c++ - 使用 QAudioOutput 进行实时流式传输

转载 作者:行者123 更新时间:2023-11-30 01:38:23 25 4
gpt4 key购买 nike

我正在开发一个 C++ 项目,使用它自己的 C++ API 从麦克风阵列系统读取/处理/播放原始音频。我正在使用 Qt 对软件进行编程。

来自这篇关于 Real Time Streaming With QAudioOutput (Qt) 的帖子,我想跟进并询问有关如果原始音频数据来自需要大约 1000 毫秒(1 秒)来处理的函数调用该怎么做的建议?我将如何仍然能够实现实时音频播放。

处理大约需要一秒钟,因为我在写入 QIODevice::QAudioFormat->start(); 时读过它;建议使用一个周期的字节值来防止缓冲区欠载/溢出。 http://cell0907.blogspot.sg/2012/10/qt-audio-output.html

我已经设置了一个 QByteArray 和 QDataStream 来流式传输从函数调用接收到的数据。

  • API 是 CcmXXX()
  • 从麦克风数组中读取数据返回一个 32 位整数数组
  • 32 位整数,24 位分辨率,8 位 LSB 补零。
  • 它具有 block 大小(设置为 1024 个样本)x 40 个麦克风
  • 每个chunk写入一个block,直到写入的字节数接近period size/free amount of bytes。

已测试:将我的插槽连接到大约 50 毫秒的通知,以写入一个周期的字节。循环缓冲区样式的 QByteArray。在读/写部分添加互斥锁定/解锁。

结果:实际播放的音频非常短,有很多抖动和未录制的声音。

请提供有关如何改进我的代码的反馈。

设置 QAudioFormat

void MainWindow::init_audio_format(){
m_format.setSampleRate(48000); //(8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 192000
m_format.setByteOrder(QAudioFormat::LittleEndian);
m_format.setChannelCount(1);
m_format.setCodec("audio/pcm");
m_format.setSampleSize(32); //(8, 16, 24, 32, 48, 64)
m_format.setSampleType(QAudioFormat::SignedInt); //(SignedInt, UnSignedInt, Float)

m_device = QAudioDeviceInfo::defaultOutputDevice();
QAudioDeviceInfo info(m_device);
if (!info.isFormatSupported(m_format)) {
qWarning() << "Raw audio format not supported by backend, cannot play audio.";
return;
}
}

初始化音频和 QByteArray/数据流

void MainWindow::init_audio_output(){   
m_bytearray.resize(65536);
mstream = new QDataStream(&m_bytearray,QIODevice::ReadWrite);
mstream->setByteOrder(QDataStream::LittleEndian);
audio = new QAudioOutput(m_device,m_format,this);
audio->setBufferSize(131072);
audio->setNotifyInterval(50);
m_audiodevice = audio->start();
connect(audio,SIGNAL(notify()),this,SLOT(slot_writedata()));
read_frames();
}

插槽:

void MainWindow::slot_writedata(){
QMutex mutex;
mutex.lock();
read_frames();
mutex.unlock();
}

阅读框架:

    void MainWindow::read_frames(){
qint32* buffer;
int frameSize, byteCount=0;
DWORD tdFrames, fdFrames;
float fvalue = 0;
qint32 q32value;

frameSize = 40 * mBlockSize; //40 mics
buffer = new int[frameSize];
int periodBytes = audio->periodSize();
int freeBytes = audio->bytesFree();
int chunks = qMin(periodBytes/mBlockSize,freeBytes/mBlockSize);

CcmStartInput();

while(chunks){
CcmReadFrames(buffer,NULL,frameSize,0,&tdFrames,&fdFrames,NULL,CCM_WAIT);
if(tdFrames==0){
break;
}
int diffBytes = periodBytes - byteCount;

if(diffBytes>=(int)sizeof(q32value)*mBlockSize){
for(int x=0;x<mBlockSize;x++){
q32value = (quint32)buffer[x]/256;
*mstream << (qint32)fvalue;
byteCount+=sizeof(q32value);
}
}
else{
for(int x=0;x<(diffBytes/(int)sizeof(q32value));x++){
q32value = (quint32)buffer[x]/256;
*mstream << (qint32) fvalue;
byteCount+=sizeof(q32value);
}
}
--chunks;
}
CcmStopInput();
mPosEnd = mPos + byteCount;
write_frames();
mPos += byteCount;
if(mPos >= m_bytearray.length()){
mPos = 0;
mstream->device()->seek(0); //change mstream pointer back to bytearray start
}
}

编写框架:

void MainWindow::write_frames()
{
int len = m_bytearray.length() - mPos;
int bytesWritten = mPosEnd - mPos;

if(len>=audio->periodSize()){
m_audiodevice->write(m_bytearray.data()+mPos, bytesWritten);
}
else{

w_data.replace(0,qAbs(len),m_bytearray.data()+mPos);
w_data.replace(qAbs(len),audio->periodSize()-abs(len),m_bytearray.data());
m_audiodevice->write(w_data.data(),audio->periodSize());
}
}

最佳答案

Qt 中的音频支持实际上非常初级。目标是以尽可能低的实现和维护成本进行媒体播放。这种情况在 Windows 上尤其糟糕,我认为古老的 MME API 仍然用于音频播放。

因此,Qt 音频 API 与实时性相去甚远,使其特别不适合此类应用程序。我建议使用 portaudio 或 rtaudio,如果愿意,您仍然可以将它们包装在 Qt 风格的 IO 设备中。这将使您能够以极低的延迟访问性能更好的平台音频 API 和更好的播放性能。

关于c++ - 使用 QAudioOutput 进行实时流式传输,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47986438/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com