捕获声卡数据的Java线程出现问题

时间:2010-10-25 12:57:52

标签: java multithreading javasound

我有一个程序可以创建一个线程,该线程从48KHz的声卡中捕获数据并将其写入缓冲区进行收集。线程代码的核心如下..

    public void run()   {
    // Run continously
    for (;;)    {
        // get data from the audio device.
        getSample();
    }
}

// Read in 2 bytes from the audio source combine them together into a single integer
// then write that into the sound buffer
private void getSample ()   {
    int sample,count,total=0,fsample;
    byte buffer[]=new byte[2];
    try {
            while (total<1) {
                count=Line.read(buffer,0,2);
                total=total+count;
                }
            } catch (Exception e)   {
                String err=e.getMessage();
            }
    sample=(buffer[0]<<8)+buffer[1];

            etc etc etc 
}

程序正常工作,但该过程似乎占用了CPU的100%时间。我认为这是因为线程正在等待数据到达Line.Read行。我已经尝试在线程中的各个点插入Thread.yield(),但似乎没有任何区别。

有人可以建议我可以减少此线程占用的CPU时间吗?

感谢您的时间

伊恩

3 个答案:

答案 0 :(得分:3)

确保线程阻止输入。

如果线程没有阻塞,则该线程占用100%的CPU时间。阻塞将导致线程进入睡眠状态,直到有一些外部刺激将其唤醒。每当你有一个专门的线程来处理输入时,你需要确保它在那个输入上阻塞,这样就会像这样睡觉,这是为了避免线程在其循环中占用100%的CPU时间。

在这种特定情况下,如果Linejavax.sound.sampled.TargetDataLine,那么read()方法就是您应该阻止的地方。根据API,“此方法将一直阻塞,直到读取了所需的数据量”,但“如果数据行在读取请求的数量之前关闭,停止,排空或刷新,则该方法不再阻塞,但是返回到目前为止读取的字节数。“

所以,有几种可能性。我没有看到您对Line的定义,因此您可能会在某些未包含的代码中刷新或排空该行。如果你这样做,你应该重构你的解决方案,不要使用这些方法。

另一种可能性是,因为你一次只能读取两个字节,所以你的阅读量不足以导致它被阻止。基本上,总有两个字节可用,因为处理你读取的两个字节需要很长时间,总有两个字节可用。尝试增加缓冲区的大小,一次读取更多像4kb。看看是否会导致循环运行频率降低,并且更频繁地阻塞。

答案 1 :(得分:1)

您需要使用远大于2的读缓冲区。在任何情况下,使用相当大的缓冲区大小几乎总是可取的,但由于某些原因,使用小缓冲区大小时javax.sound效率特别低。我在实现基于Java的VU计时学到了这一点。

答案 2 :(得分:0)

Thread.sleep(a few ms);置于无限循环中,或者每隔几毫秒使用java.util.Timer调用getSample()。