首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于QAudioOutput的实时流媒体(qt)

基于QAudioOutput的实时流媒体(qt)
EN

Stack Overflow用户
提问于 2015-08-17 12:06:05
回答 1查看 6.9K关注 0票数 7

我想播放实时的声音响应,没有明显的滞后于用户的交互。

为了降低延迟,我必须发送少量的pcm数据。我所做的是:

代码语言:javascript
复制
    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();

以及以后的

代码语言:javascript
复制
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。

这是正确的程序还是我遗漏了什么?

EN

回答 1

Stack Overflow用户

发布于 2015-08-17 14:30:33

这个问题是关于

代码语言:javascript
复制
void Enqueue(TYPESAMPLEPCM *data,int countBytes){
    while(qAudioOutput->bytesFree()<countBytes){
          Sleep(1);
    }
    qAudioDevice->write((char *)data,countBytes);
}

有点天真。

首先是Sleep(1);。你在窗户上。问题是,windows不是实时操作系统,它的时间分辨率应该在10 - 15 ms附近。,这意味着当没有接收音频的地方时,您将比预期的睡得更多。

第二.当音频输出无法消耗所提供的数据量时,您真的需要睡眠吗?您真正想要的是在音频输出消耗了一些音频之后提供一些音频。具体而言,这意味着:

  1. 设置QAudioOutput通知间隔 (系统将消耗音频数据并告诉您的时间)。
  2. 收到关于QAudioOutput正在消耗一些数据的通知。,它位于连接到QAudioOutput::notify()的插槽中。
  3. 缓冲数据块,这是来自您的高优先级线程时,音频输出是满的。

这意味着:

代码语言:javascript
复制
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免受并发访问。提供足够的互斥物。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32049950

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档