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开发者_如何学Python 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
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.
You need to use a read-buffer much larger than size 2. Using a reasonably large buffer size is almost always advisable in any situation, but for some reason javax.sound is particularly inefficient when using small buffer sizes. I learned this when implementing a Java-based VU-meter.
Put a Thread.sleep(a few ms);
in your infinite loop, or use a java.util.Timer
to call getSample() every few ms.
精彩评论