【问题标题】:FreeTTS no audio linux ubuntu - no errorsFreeTTS no audio linux ubuntu - no errors
【发布时间】:2011-07-26 23:05:17
【问题描述】:

我正在使用 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 Hello

当我按 Enter 键时,它会启动并用于给我丢失的 MBROLA 警告消息,但现在它只是坐在那里,直到我 CTRL-C 停止它。

我不明白我做错了什么以及为什么没有其他人遇到这个问题,当我在每台计算机上体验它时,它在 Windows 上也能正常工作。谁能帮帮我?

谢谢,

约翰

【问题讨论】:

标签: java audio text-to-speech javasound freetts


【解决方案1】:

我不确定您是否已经设法解决了这个问题,但我遇到了同样的问题(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() 的同一线程中收到 open 类型的 LineEvent 的通知,或者在 Line 打开之后(并且对 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");

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

希望这一切都适合你。

【讨论】:

  • 当我看到这样的答案时,我只想死。上帝啊,这到底是为什么?为什么我没有这种聪明的头脑?谢谢你的精彩:-)
【解决方案2】:

我是一名学生,一周以来一直试图让 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();
        }
    }

【讨论】:

  • 非常感谢您提供如此清晰的解释。我已将您的修复加入到我的 FreeTTS 副本中。您可以在此处查看/使用该补丁:github.com/timabell/FreeTTS/commit/… - 学生现在是老师 :-) 我已经测试了 helloworld jar 文件,并且有了这个补丁,freeTTS 不再在 openJdk 下挂起。
  • @Tim 干得好。我已经向 Ubuntu here 报告了这个错误。请投票。
  • 完成! (如果我理解有时我不相信的启动板)。谢谢@HRJ
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 2012-12-09
    • 2022-12-26
    • 2021-12-09
    • 2017-12-01
    • 2014-10-03
    • 1970-01-01
    • 2015-05-08
    • 1970-01-01
    • 2021-11-05
    相关资源
    最近更新 更多