Joh*_*ohn 9 java audio text-to-speech javasound freetts
我使用Java 6运行Ubuntu 10.10并且无法获取FreeTTS来输出任何音频.我现在已经在3台不同的计算机上试过它,甚至要求我的一个伙伴在他的Ubuntu PC上试用它并且他遇到了同样的问题.绝对没有显示错误,在获得MBROLA后我甚至不再收到关于没有检测到MBROLA声音的警告.等等等等等等..
使用同一台计算机,我运行了一个虚拟盒并启动了Windows XP,我实际上能够在运行HelloWorld.jar和TTSHelloWorld.jar时获得音频,但是当我尝试输入自己的文本时,freetts.jar仍然是静默的.
我使用的命令.
java -jar lib/freetts.jar -text你好
当我按下Enter键时,它启动并用来给我丢失的MBROLA警告信息,但现在它只是坐在那里直到我按CTRL-C来阻止它.
我不明白我做错了什么以及为什么没有其他人遇到这个问题,当我在每台计算机上展示它时,它在Windows上有所作为.谁能帮我?
谢谢,
约翰
小智 10
我不确定你是否已经设法解决了这个问题,但我遇到了同样的问题(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的LineEvent,它与调用Line.open()的线程相同,或者在Line之后已打开(并且可以返回对Line.open()的调用).PulseAudioSourceDataLine不是这种情况; 它首先从PulseAudio事件Thread调用所有LineListener,等待所有LineListeners返回,然后从open调用返回.随着JavaStreamingAudioPlayer强制同步Line.open()的调用和特定LineListener的处理,该任务是查看Line是否实际打开,发生死锁.
我选择解决此问题的解决方法是实现没有此问题的AudioPlayer.我基本上复制了JavaStreamingAudioPlayer并修改了第196行和第646行的同步块(完整的参考资料来源: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: ...
Run Code Online (Sandbox Code Playgroud)
我删除了两个同步块,而不是确保两个部分相互排除,我使用信号量来表示Line实际上是打开的.当然,这并不是必需的,因为PulseAudioSourceDataLine已经保证在返回时打开,但是当在另一个平台上测试相同的代码时,它更有可能发挥得很好.我没有深入研究代码,足以说明当你多个线程同时打开/关闭/打开线路时会发生什么.如果您要这样做,您可能正在考虑更大的JavaStreamingAudioPlayer重写;).
最后,在创建新的AudioPlayer之后,您必须指示FreeTTS使用您的实现而不是默认的JavaStreamingAudioPlayer.这可以通过使用来完成
System.setProperty("com.sun.speech.freetts.voice.defaultAudioPlayer", "classpath.to.your.AudioPlayer");
Run Code Online (Sandbox Code Playgroud)
在代码的早期某处.
希望这一切都适合你.
Saa*_*raz 10
我是一名学生,他一直试图让FreeTTS在Ubuntu上工作一周.最后我在这里找到答案:非常感谢hakvroot!
你的答案是完美的,但你没有把你的实现,这花了我一个小时来了解JavaStreamingAudioPlayer类中发生了什么.为了帮助像我这样没有用于"潜水"的其他人在一个完全未知的Java代码(我仍然是学生),我会把我的代码放在这里,希望它能帮助其他人:).
首先,更详细的解释:在第152行附近,JavaStreamingAudioPlayer打开一个Line.但是,此操作可能需要一些时间,因此在使用之前,它需要检查它是否已打开.在当前实现中,使用的解决方案是创建一个LineListener,监听此行,然后进入休眠状态(使用线程的wait()方法).
LineListener将使用notifyAll()"唤醒"主线程,并且只有在收到类型为"OPEN"的LineEvent时才会这样做,这将保证线路已被打开.
但是正如hakvroot在这里解释的那样,问题是由于Ubuntu使用的DataLine的特定行为,因此永远不会发送通知.
所以我删除了代码的synchronized,wait()和notifyAll()部分但是作为hakvroot,那么你的JavaStreamingAudioPlayer可能会在它打开之前尝试使用你的Line:你需要等待使用新机制的确认来停止JavaStreamingAudioPlayer当确认到达时,将其唤醒.
所以我使用了havkroot使用的Semaphore(参见Javadoc对这个锁系统的解释)以1个堆栈启动:
当线被打开时,它获得一个堆栈(因此0保持不变)
当它想要使用它试图获取另一条线时(所以它被停止)
当监听器获取我们正在寻找的事件时,它会释放信号量
这将释放出可以用于下一部分的JavaStreamingAudioPlayer
不要忘记再次释放信号量,这样它又有1个堆栈,可以打开下一行
这是我的代码:
声明一个Semaphore变量:
private Semaphore hackSemaphore;
Run Code Online (Sandbox Code Playgroud)
在构造函数中启动它:
hackSemaphore = new Semaphore(1);
Run Code Online (Sandbox Code Playgroud)
然后第一部分要更换(参见hakvroot看看它放在哪里):
line = (SourceDataLine) AudioSystem.getLine(info);
line.addLineListener(new JavaStreamLineListener());
line.open(format, AUDIO_BUFFER_SIZE);
hackSemaphore.acquire();
hackSemaphore.acquire();
opened = true;
hackSemaphore.release();
Run Code Online (Sandbox Code Playgroud)
第二部分:
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.OPEN)) {
hackSemaphore.release();
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2474 次 |
最近记录: |