我在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;
}
答案 0 :(得分:3)
IDK为什么花了这么长时间(因为我不知道窗户),但我可以说你这是错误的方式。具体来说,您不应该对打开新流做任何时间预期。例如,我预计OS X会出现类似的问题(尽管程度要小得多)。
正确的实现方法是始终打开流,播放静音。然后,当您需要播放声音时,您可以立即播放。为了获得最佳延迟,您应该从文件中预加载前几个缓冲区,这样您就不需要在开始播放时访问磁盘。我不知道Windows打开流的确切开销是多少(我确定它取决于API),但在某些版本的OS X上,它是巨大的(整个内核交换机)如果之前没有运行音频,则进入抢先模式。)
那就是说,1.3秒是疯了。我建议在邮件列表上询问。请务必说出您正在使用的主机API,因为您没有在此处说过,而且对于Windows而言,这很重要。此外,什么版本的Windows。
答案 1 :(得分:1)
为了最大限度地减少此用例的启动延迟(即期望StartStream()提供最小的启动延迟),您应该使用paPrimeOutputBuffersUsingStreamCallback流标志。否则初始缓冲区将为零,声音到达DAC所需的时间将包括播放零的缓冲区长度(在Windows WMME或DirectSound上使用默认PA设置约为80ms)。