2

我在 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;
}
4

2 回答 2

3

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

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

也就是说,1.3 秒是疯狂的。我建议在邮件列表中询问。请务必说明您使用的是什么主机 API,因为您没有在这里说,而且对于 Windows,这很重要。还有,什么版本的windows。

于 2013-08-29T02:48:10.960 回答
1

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

于 2013-09-05T02:30:03.137 回答