我正在实现一个应用程序,它使用JDK Version 8 Update 201实时记录和分析音频(或至少尽可能接近实时)。在执行模拟应用程序典型用例的测试时,我注意到了经过几个小时的连续录音,引入了一到两秒之间的突然延迟。到目前为止,没有明显的延迟。只有在这个延迟开始发生的几个小时的记录临界点之后。
为了检查我的音频样本录制时间代码是否错误,我评论了与时间相关的所有内容。这让我基本上得到了这个更新循环,它在准备好后立即取出音频样本(注意:Kotlin代码):
while (!isInterrupted) {
val audioData = read(sampleSize, false)
listener.audioFrameCaptured(audioData)
}
这是我的阅读方法:
fun read(samples: Int, buffered: Boolean = true): AudioData {
//Allocate a byte array in which the read audio samples will be stored.
val bytesToRead = samples * format.frameSize
val data = ByteArray(bytesToRead)
//Calculate the maximum amount of bytes to read during each iteration.
val bufferSize = (line.bufferSize / BUFFER_SIZE_DIVIDEND / format.frameSize).roundToInt() * format.frameSize
val maxBytesPerCycle = if (buffered) bufferSize else bytesToRead
//Read the audio data in one or multiple iterations.
var bytesRead = 0
while (bytesRead < bytesToRead) {
bytesRead += (line as TargetDataLine).read(data, bytesRead, min(maxBytesPerCycle, bytesToRead - bytesRead))
}
return AudioData(data, format)
}
然而,即使没有任何时间,我的问题也没有得到解决。因此,我继续进行实验,让应用程序使用不同的音频格式运行,这会导致非常混乱的结果(我将使用PCM签名的16位立体声音频格式,带有小端,采样率为44100.0 Hz默认情况下,除非另有说明):
这些结果让我得出的结论是,在此问题开始发生之前我可以录制音频的时间取决于运行应用程序的机器,并且取决于字节速率(即帧大小和采样率)。音频格式。这似乎是正确的(虽然我现在还不能完全证实这一点),因为如果我结合2和3中所做的更改,我会假设我可以记录四倍的音频样本(这可能介于两者之间) 26和27小时)在延迟开始出现之前使用我的“默认”音频格式。由于我没有时间让应用程序运行这么长时间,我只能说它确实运行了大约15个小时,因为时间限制我不得不停止它。因此,这一假设仍有待证实或否定。
根据项目符号13的结果,似乎整个问题仅在使用Windows时出现。因此,我认为它可能是javax.sound.sampled API的平台特定部分中的错误。
尽管我认为在这个问题开始发生时我可能已经找到了改变的方法,但我对结果并不满意。我可以定期关闭并重新打开该线,以避免问题开始出现。但是,这样做会导致一些任意的少量时间,我将无法捕获音频样本。此外,Javadoc声明有些线路在关闭后根本无法重新打开。因此,在我的情况下,这不是一个好的解决方案。
理想情况下,整个问题根本不应该发生。有没有我完全遗漏的东西,或者我遇到javax.sound.sampled API可能存在的限制?我怎么能摆脱这个问题呢?
编辑:通过Xtreme Biker和gidds的建议,我创建了一个小示例应用程序。你可以在这个Github repository里面找到它。
我有一个(相当)丰富的Java音频接口经验。以下几点可能有助于指导您找到合适的解决方案: