Disclaimer: I’m currently only testing on my (kind of crappy) workstation and not on the lab computer - thus the “soundcard” is of quite dubious quality.
I’m keeping it simple and doing a straightforward test currently:
class DefaultLoudspeaker implements Loudspeaker, LineListener {
protected static final AudioFormat PCM_FORMAT = new AudioFormat(8000, /* Sample-rate */
16, /* Bit-depth */
1, /* Channels */
true, /* Signed */
false); /* Big-endian */
private SourceDataLine speaker;
private Logger log;
private int bufferSize;
public DefaultLoudspeaker(String name, int bufferTimeInMillis) {
log = Logger.getLogger(name);
int frameSize = PCM_FORMAT.getFrameSize();
float sampleRate = PCM_FORMAT.getSampleRate();
this.bufferSize = (int) (frameSize * sampleRate * bufferTimeInMillis / 1000);
}
public void init() throws LineUnavailableException {
speaker = AudioSystem.getSourceDataLine(PCM_FORMAT);
speaker.addLineListener(this);
speaker.open(PCM_FORMAT, bufferSize);
speaker.start();
log.info(this + ": Speaker is operational");
log.info(this + ": Speaker level: " + speaker.getLevel());
log.info(this + ": Speaker buffer-size: " + speaker.getBufferSize());
}
/**
* Responsible for sending data to a loudspeaker.
* @param data 8kHz sampled audio with 16 bits depth.
*/
public void output8kHz16bit(byte[] data, int offset, int length) {
speaker.write(data, offset, length);
}
public void update(LineEvent le) {
log.info(le.toString());
}
public void close() {
speaker.drain();
speaker.close();
speaker.removeLineListener(this);
log.info(this + ": Speaker is closed");
}
}
My initial conclusions is that the above code leads to an unusable speaker at buffer times <~ 500 ms. Is this result reasonable or do you think it’s the poor quality of the soundcard that is solely responsible?
Test code:
public class DefaultLoudspeakerUT {
private AudioInputStream data;
private File file = new File("H:/Code/Java/near_end.wav");
private Loudspeaker speaker;
@Before
public void setUp() throws Exception {
try {
assertTrue(file.exists());
data = AudioSystem.getAudioInputStream(file);
speaker = new DefaultLoudspeaker("Magic speaker", 500);
speaker.init();
} catch (RuntimeException re) {
re.printStackTrace();
fail(re.getMessage());
}
}
@After
public void tearDown() throws Exception {
data.close();
speaker.close();
}
@Test
public void testOutput8kHz16bit() {
System.out.printf("Reading data formatted as: %s\n", data.getFormat().toString());
try {
System.out.printf("Data available: %d\n", data.available());
byte[] buffer = new byte[160];
int totalRead = 0;
while (data.available() > 0) {
int read = data.read(buffer);
speaker.output8kHz16bit(buffer, 0, read);
totalRead += read;
}
System.out.printf("Data written: %d\n", totalRead);
} catch (IOException e) {
e.printStackTrace();
fail(e.getMessage());
}
}
}
I’ve tried various sizes of buffer and buffer-delay
Thanks in advance
/Anders
EDIT:
java version “1.7.0-ea”
Java™ SE Runtime Environment (build 1.7.0-ea-b07)
Java HotSpot™ Client VM (build 1.7.0-ea-b07, mixed mode)
I’ve tried a few different versions, including “stable” 1.6 etc