9

我正在使用 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 上有点工作。谁能帮我?

谢谢,

约翰

4

3 回答 3

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.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 )。

___: // 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");

在你的代码早期的某个地方。

希望这一切都适合你。

于 2011-06-07T09:43:41.907 回答
10

我是一名学生,他一直试图让 FreeTTS 在其 Ubuntu 上运行一周。最后我在这里找到了答案:非常感谢 hakvroot!

你的答案很完美,但你没有把你的实现,这花了我整整一个小时来理解 JavaStreamingAudioPlayer 类中发生了什么。为了帮助像我这样没有在完全未知的Java代码中“潜水”的人(我还是个学生),我将把我的代码放在这里,希望它可以帮助其他人:)。

首先,更详细的解释:在第 152 行附近,JavaStreamingAudioPlayer 打开了一个 Line。但是此操作可能需要一些时间,因此在使用它之前,它要检查它是否已打开。在当前的实现中,使用的解决方案是创建一个 LineListener 侦听此行然后休眠(使用线程的 wait() 方法)。

LineListener 将使用 notifyAll() “唤醒”主线程,并且仅当它接收到类型为“OPEN”的 LineEvent 时才会这样做,这将保证线路已打开。

但是,正如 hakvroot 在这里所解释的,问题是由于 Ubuntu 使用的 DataLine 的特定行为,通知永远不会发送。

因此,我删除了代码的同步、wait() 和 notifyAll() 部分,但作为 hakvroot,您的 JavaStreamingAudioPlayer 可能会在打开之前尝试使用您的 Line:您需要等待使用新机制的确认以停止 JavaStreamingAudioPlayer并在确认到达时将其唤醒。

因此,我使用了 havkroot 使用的 Semaphore(有关此锁系统的解释,请参见 Javadoc),该信号量由 1 个堆栈启动:

  • 当该行打开时,它会获得一个堆栈(所以 0 仍然存在)

  • 当它想使用这条线时,它会尝试获取另一条线(所以它被停止了)

  • 当侦听器收到我们正在寻找的事件时,它会释放信号量

  • 这释放了可以进行下一部分的 JavaStreamingAudioPlayer

  • 不要忘记再次释放信号量,这样它又有 1 个堆栈供下一行打开

这是我的代码:

声明一个信号量变量:

private Semaphore hackSemaphore;

在构造函数中启动它:

hackSemaphore = new Semaphore(1);

然后是要替换的第一部分(请参阅 hakvroot 以查看放置位置):

            line = (SourceDataLine) AudioSystem.getLine(info);
            line.addLineListener(new JavaStreamLineListener());

            line.open(format, AUDIO_BUFFER_SIZE);
            hackSemaphore.acquire(); 
            hackSemaphore.acquire(); 
            opened = true;
            hackSemaphore.release();

第二部分:

    public void update(LineEvent event) {
        if (event.getType().equals(LineEvent.Type.OPEN)) {
            hackSemaphore.release();
        }
    }
于 2012-07-17T01:17:02.070 回答
1

我猜在 Ubuntu 12.04/OpenJDK-6 上也有同样的问题,执行卡在 Voice.allocate() 中,没有错误也没有响应。我尝试使用 Oracle/Sun JDK-6 而不是 OpenJDK,效果很好。

PS 在 Ubuntu 上安装 SunJDK 并配置为默认值的好指南 http://www.devsniper.com/ubuntu-12-04-install-sun-jdk-6-7/

于 2012-07-03T16:45:39.727 回答