我正在使用Java 6运行Ubuntu 10.10,无法获取FreeTTS来输出任何音频。我现在已经在3台不同的计算机上进行了尝试,甚至让我的一个伙伴在他的Ubuntu PC上进行尝试,但他也遇到了同样的问题。在获得MBROLA之后,绝对不会显示任何错误,我什至再也不会收到有关未检测到MBROLA声音的警告。等等等等等等..
使用同一台计算机,我运行了一个虚拟盒子并启动了Windows XP,在运行HelloWorld.jar和TTSHelloWorld.jar时实际上可以获取音频,但是当我尝试输入自己的文本时,freetts.jar仍然保持沉默。
我使用的命令。
当我按下Enter键时,它会启动并用于向我提供缺少的MBROLA警告消息,但现在它一直坐在那里,直到我按下CTRL-C停止它为止。
我不明白自己在做错什么,为什么没有人遇到这个问题,当我在每台计算机上都遇到问题时,它在Windows上还是可以正常工作的。谁能帮我?
谢谢,
约翰
最佳答案
我不确定您是否已经解决了这个问题,但是遇到了同样的问题(Ubuntu 10.10/JavaSE6)。在对FreeTTS来源进行了一些调查之后,我在com.sun.speech.freetts.audio.JavaStreamingAudioPlayer中发现了死锁的罪魁祸首。当打开Line且Line的类型为org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine(在Java SE6的Ubuntu 10.10中可能是默认设置)时,会发生此死锁。由于您一直想打开线路以输出音频,因此总是会发生这种死锁。
造成这种僵局的原因在于,在JavaStreamingAudioPlayer中对Line进行了假设,即,将从与Line.open()相同的线程中或在Line之后向所有LineListener通知一个类型为open的LineEvent的LineEvent。已打开(并且对Line.open()的调用可以返回)。对于PulseAudioSourceDataLine则不是这种情况。它首先从PulseAudio事件线程中调用所有LineListener,然后等待它们全部返回,然后从打开的调用中返回。使用JavaStreamingAudioPlayer强制围绕Line.open()的调用进行同步,并处理特定的LineListener,该任务是查看Line是否真正打开,从而发生死锁。
我为解决此问题而选择的解决方法是实现一个没有此问题的AudioPlayer。我基本上复制了JavaStreamingAudioPlayer并更改了第196行和第646行的同步块(synchronized block)(供引用的完整源: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: ...
我删除了两个同步块(synchronized block),而不是确保两个部分都互斥,我使用了一个信号量来表示该线路实际上是开放的。当然,这并不是必须的,因为PulseAudioSourceDataLine已经保证在返回时将其打开,但是当在另一个平台上测试相同的代码时,它更有可能发挥作用。我没有深入研究代码,无法说明当您同时通过多个线程打开/关闭/打开该行时会发生什么。如果要执行此操作,则可能正在看对JavaStreamingAudioPlayer;)的较大重写。
最后,在创建了新的AudioPlayer之后,您将必须指示FreeTTS使用您的实现,而不是默认的JavaStreamingAudioPlayer。这可以通过使用
System.setProperty("com.sun.speech.freetts.voice.defaultAudioPlayer", "classpath.to.your.AudioPlayer");
在您代码的早期位置。
希望所有这些都对您有用。