如何在Windows上有效使用PortAudio Pa_OpenStream()?

时间:2013-08-28 22:30:34

标签: c++ windows portaudio

我在Linux上用PortAudio写了一个小声音播放库。这是一个小游戏,所以当各种事情发生时,会有很多小声音。我通过调用Pa_OpenStream()为每个wav文件打开一个流。在Linux上,此调用平均需要大约10毫秒。但是在Windows上,这通常需要40到70毫秒。更糟糕的是,第一次通话需要1.3秒。然后在那之后它将再次需要1.3秒。我无法找到任何关于它为什么会挂起的一致性,除了每次第一次调用都会发生这种情况。 Windows构建实际上在Wine上运行良好。

我认为这与不同系统中使用的底层声音API的差异有关。但奇怪的是,尽管进行了广泛的搜索,我还是没有在任何地方找到任何信息。

这是我的游戏功能:

int play(const char * sN)
{
    float threshold = .01f;

    char * soundName = (char*)sN;
    float g = glfwGetTime();
    updatePlayer();
    float g2 = glfwGetTime();
    if (g2-g > threshold) printf("updatePlayer: %f/", g2 - g);
    if (!paused && (int)streams.size() < maxStreams && !mute)
    {
        streamStr * ss = new streamStr;

        g = glfwGetTime();
        if (g-g2 > threshold) printf("new stream: %f/", g - g2);
        PaError err;

        sfData * sdata = getData(soundName);
        ss->sfd = sdata;

        g2 = glfwGetTime();
        if (g2-g > threshold)printf("getData: %f/", g2 - g);
        err = Pa_OpenStream(&(ss->stream), 0, &sdata->outputParameters, sdata->sfInfo.samplerate, paFramesPerBufferUnspecified, paNoFlag, PaCallback, ss);
        if (err)
        {
            printf("PortAudio error opening output: %s\n", Pa_GetErrorText(err));
            delete ss;
            return 1;
        }

    g = glfwGetTime();
    if (g-g2 > threshold)
    printf("Pa_OpenStream: %f/", g - g2);

        Pa_StartStream(ss->stream);

    g2 = glfwGetTime();
    if (g2-g > threshold)printf("Pa_StartStream: %f/", g2 - g);
        addStreams(ss);

    g = glfwGetTime();
    if (g-g2 > threshold)printf("addStreams: %f", g - g2);
        //Pa_SetStreamFinishedCallback(ss, finishedCallback);
        printf("\n");
   }
    return 0;
}

2 个答案:

答案 0 :(得分:3)

IDK为什么花了这么长时间(因为我不知道窗户),但我可以说你这是错误的方式。具体来说,您不应该对打开新流做任何时间预期。例如,我预计OS X会出现类似的问题(尽管程度要小得多)。

正确的实现方法是始终打开流,播放静音。然后,当您需要播放声音时,您可以立即播放。为了获得最佳延迟,您应该从文件中预加载前几个缓冲区,这样您就不需要在开始播放时访问磁盘。我不知道Windows打开流的确切开销是多少(我确定它取决于API),但在某些版本的OS X上,它是巨大的(整个内核交换机)如果之前没有运行音频,则进入抢先模式。)

那就是说,1.3秒是疯了。我建议在邮件列表上询问。请务必说出您正在使用的主机API,因为您没有在此处说过,而且对于Windows而言,这很重要。此外,什么版本的Windows。

答案 1 :(得分:1)

为了最大限度地减少此用例的启动延迟(即期望StartStream()提供最小的启动延迟),您应该使用paPrimeOutputBuffersUsingStreamCallback流标志。否则初始缓冲区将为零,声音到达DAC所需的时间将包括播放零的缓冲区长度(在Windows WMME或DirectSound上使用默认PA设置约为80ms)。