我在Linux上用PortAudio写了一个小型的声音库。 这是一个小游戏,所以有各种各样的事情发生时,有很多小声音。 我通过调用Pa_OpenStream()为每个wav文件打开一个stream。 在linux上,这个调用平均需要10ms左右。 但在Windows上,这通常需要40到70毫秒。 更糟的是,第一个电话需要1.3秒。 之后偶尔会再花费1.3秒。 除了每次第一次打电话时,我一直无法find任何与之相关的事情。 Wine的构build实际上运行良好。
我认为这与不同系统中使用的底层声音API的差异有关。 但奇怪的是,尽pipesearch量很大,我还是没有find任何信息。
这是我的播放function:
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; }
IDK为什么要花这么长时间(因为我不知道窗口),但我可以说你正在做这个错误的方式。 具体来说,你不应该打开一个新的流的时间期望值。 例如,我期望在OS X上有类似的问题(虽然程度较低)。
正确的实施将始终有一个流打开,播放沉默。 然后,当你需要播放声音时,你可以马上播放。 为了获得最佳延迟,您应该预先加载文件中的前几个缓冲区,以便在播放开始时不需要访问磁盘。 我不知道打开一个流的确切开销是多少(我确定它取决于API),但是在某些版本的OS X上,它是巨大的 (如果没有音频,整个内核就会切换到抢占模式之前运行)。
这就是说,1.3秒是疯了。 我建议在邮件列表上询问。 一定要说出你使用的是什么host-API,因为你没有在这里说过,而对于Windows而言,这很重要。 另外,什么版本的Windows。
为了最大限度地减少这种用例的启动延迟(即期待StartStream()使启动延迟最小化),您应该使用paPrimeOutputBuffersUsingStreamCallback流标志。 否则,初始缓冲区将为零,并且声音击中DAC所需的时间将包括缓冲区长度为0(在Windows WMME或DirectSound中使用默认的PA设置大约为80ms)。