views:

53

answers:

2

Hello

I have a program which creates a thread that captures data from the soundcard at 48 KHz and writes it to a buffer for collection. The heart of the thread code is as follows ..

    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 
}

The program works except the process appears to take 100% of the CPU's time. I presume this is because the thread is sat waiting for data to arrive at the Line.Read line. I have tried inserting Thread.yield() at various points in the thread but it seems to make no difference.

Can anyone suggest ways I can reduce the amount of CPU time this thread takes ?

Thanks for your time

Ian

A: 

Put a Thread.sleep(a few ms); in your infinite loop, or use a java.util.Timer to call getSample() every few ms.

Landei
`Thread.sleep()` is a poor-man's way of blocking. It's useful as a debugging tool to adjust the timing of various calls to affect the results. It's a poor choice as part of a design. Mainly, I've used it with the EDT to give the system a moment to propogate a UI change before I check the status of something in the UI. Once I prove that it works, though, I set up some sort of event-notify loop to call back instead. I never let `Thread.sleep()` calls into production code unless there is an actual reason for sleeping for a specified period of time (like a Scheduler needs).
Erick Robertson
JavaDoc: "Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds. The thread does not lose ownership of any monitors." So you *have* the potential for dead-locks if you are not careful, but this is a general problem with Java's concurrency system, and other from that I see no problems with Thread.sleep()
Landei
+3  A: 

Make sure the thread is blocking for input.

The thread takes up 100% of the CPU time if it doesn't block. Blocking will cause the thread to go to sleep until there is some external stimulus to wake it up. Whenever you have a dedicated thread to process input, you need to make sure that it's blocking on that input so that it will sleep like this, exactly in order to avoid the thread taking up 100% of the CPU time in its loop.

In this specific case, if Line is a javax.sound.sampled.TargetDataLine, then the read() method is where you should be doing your blocking. According to the API, "This method blocks until the requseted amount of data has been read," but "if the data line is closed, stopped, drained, or flushed before the requested amount has been read, the method no longer blocks, but returns the number of bytes read thus far."

So, there are a couple of possibilities. I don't see your definition of Line, so it's possible that you are flushing or draining the line in some code that you didn't include. If you did that, you should refactor your solution to not use those methods.

The other possibility is that, since you're always reading only two bytes at a time, you're not reading enough to cause it to block. Basically, there are always two bytes available because it takes too long to process the two bytes you read, that there are always another two bytes available. Try increasing the size of the buffer to read more like 4kb at a time. See if that causes the loop to run less frequently, and block more frequently.

Erick Robertson
Thanks. I have modified getSample() to load 256 bytes at a time from the soundcard. The program works fine and the CPU loading is reduced to 52%.
IanW
A good maxim is to always read appropriate block sizes. Even a c program reading single bytes will be many times slower than reading blocks.(I can verify that experimentally)
Tim Williscroft
You should experiment with different sizes and find what works best for your application. I don't know, but it seems that 256 bytes is pretty small. As long as you get the results you want, find the size that produces the lowest CPU load.
Erick Robertson