我不确定你是否已经解决了这个问题,但我遇到了同样的问题(Ubuntu 10.10 / JavaSE6)。经过对 FreeTTS 源代码的一些调查后,我发现了罪魁祸首,即 com.sun.speech.freetts.audio.JavaStreamingAudioPlayer 中的死锁。当打开 Line 并且该 Line 的类型为 org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine(这可能是 Ubuntu 10.10 w JavaSE6 中的默认值)时,会发生此死锁。由于您总是想打开一条线路来输出音频,因此这种死锁总是会发生。
造成这种死锁的原因在于,在 JavaStreamingAudioPlayer 中对 Line 做了一个假设,即所有 LineListener 都将在调用 Line.open() 时或在 Line 之后从同一线程收到 open 类型的 LineEvent 通知。已打开(并且对 Line.open() 的调用可以返回)。 PulseAudioSourceDataLine 的情况并非如此;它首先从 PulseAudio 事件线程调用所有 LineListener,等待它们全部返回,然后从 open 调用返回。由于 JavaStreamingAudioPlayer 强制对 Line.open() 的调用进行同步并处理特定的 LineListener(其任务是查看 Line 是否实际打开),因此会发生死锁。
我选择解决此问题的解决方法是实现一个不存在此问题的 AudioPlayer。我基本上复制了 JavaStreamingAudioPlayer 并更改了第 196 行和第 646 行的同步块(完整源代码供参考:http://www.javadocexamples.com/java_source/com/sun/speech/freetts/audio/JavaStreamingAudioPlayer.java.html http://www.javadocexamples.com/java_source/com/sun/speech/freetts/audio/JavaStreamingAudioPlayer.java.html ).
___: // This is the actual JavaStreamAudioPlayer source, not the fix
195: ...
196: synchronized (openLock) {
197: line.open(format, AUDIO_BUFFER_SIZE); // Blocks due to line 646
198: try {
199: openLock.wait();
200: } catch (InterruptedException ie) {
201: ie.printStackTrace();
202: }
203: ...
643: ...
644: public void update(LineEvent event) {
645: if (event.getType().equals(LineEvent.Type.OPEN)) {
646: synchronized (openLock) { // Blocks due to line 196
647: openLock.notifyAll();
648: }
649: }
650: }
651: ...
我删除了两个同步块,而不是确保两个部分相互排斥,而是使用信号量来表示线路实际上已打开。当然,这并不是真正必要的,因为 PulseAudioSourceDataLine 已经保证在返回时打开,但在另一个平台上测试相同的代码时它更有可能发挥良好的作用。我没有深入研究代码足够长的时间来说明当您同时通过多个线程打开/关闭/打开该行时会发生什么。如果您打算这样做,您可能会考虑对 JavaStreamingAudioPlayer 进行更大的重写;)。
最后,创建新的 AudioPlayer 后,您必须指示 FreeTTS 使用您的实现而不是默认的 JavaStreamingAudioPlayer。这可以通过使用来完成
System.setProperty("com.sun.speech.freetts.voice.defaultAudioPlayer", "classpath.to.your.AudioPlayer");
在代码早期的某个地方。
希望这一切对你有用。