我想播放实时的声音响应,没有明显的滞后于用户的交互。
为了降低延迟,我必须发送少量的pcm数据。我所做的是:
QAudioFormat format;
format.setSampleRate(22050);
format.setChannelCount(1);
format.setSampleSize(16);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (!info.isFormatSupported(format)) {
qWarning()<<"raw audio format not supported by backend, cannot play audio.";
return;
}
qAudioOutput = new QAudioOutput(format, NULL);
qAudioDevice=qAudioOutput->start();以及以后的
void Enqueue(TYPESAMPLEPCM *data,int countBytes){
while(qAudioOutput->bytesFree()<countBytes){
Sleep(1);
}
qAudioDevice->write((char *)data,countBytes);
}数据块为256个字节(128个样本将提供大约6毫秒的“粒度”)。
Enqueue是从提供数据块的具有高优先级的线程中的循环调用的。没有延迟,因为它调用的速度远远快于呈现音频数据。
但在我看来,有一种缓冲运行不足的情况,因为声音播放,但有一种“爆裂”的常规噪音。
如果我把块大小提高到256个样本,问题就几乎消失了。一开始只有一些裂纹(?)
平台是Windows和QT5.3。
这是正确的程序还是我遗漏了什么?
发布于 2015-08-17 14:30:33
这个问题是关于
void Enqueue(TYPESAMPLEPCM *data,int countBytes){
while(qAudioOutput->bytesFree()<countBytes){
Sleep(1);
}
qAudioDevice->write((char *)data,countBytes);
}有点天真。
首先是,Sleep(1);。你在窗户上。问题是,windows不是实时操作系统,它的时间分辨率应该在10 - 15 ms附近。,这意味着当没有接收音频的地方时,您将比预期的睡得更多。。
第二.当音频输出无法消耗所提供的数据量时,您真的需要睡眠吗?您真正想要的是在音频输出消耗了一些音频之后提供一些音频。具体而言,这意味着:
QAudioOutput正在消耗一些数据的通知。,它位于连接到QAudioOutput::notify()的插槽中。这意味着:
QByteArray samplebuffer;
//init code
{
qAudioOutput = new QAudioOutput(format, NULL);
...
qAudioOutput->setNotifyInterval(128); //play with this number
connect(qAudioOutput, SIGNAL(notify), someobject, SLOT(OnAudioNotify));
...
qAudioDevice=qAudioOutput->start();
}
void EnqueueLock(TYPESAMPLEPCM *data,int countBytes)
{
//lock mutex
samplebuffer.append((char *)data,countBytes);
tryWritingSomeSampleData();
//unlock mutex
}
//slot
void SomeClass::OnAudioNotify()
{
//lock mutex
tryWritingSomeSampleData()
//unlock mutex
}
void SomeClass::tryWritingSomeSampleData()
{
int towritedevice = min(qAudioOutput->bytesFree(), samplebuffer.size());
if(towritedevice > 0)
{
qAudioDevice->write(samplebuffer.data(),towritedevice);
samplebuffer.remove(0,towritedevice); //pop front what is written
}
}正如您所看到的,您需要保护samplebuffer免受并发访问。提供足够的互斥物。
https://stackoverflow.com/questions/32049950
复制相似问题