I'm running Java 21 on a Raspberry Pi 3B (64-bit OS). Calling javax.sound.sampled.Clip#getFramePosition()
on a running audio clip takes up to 3 seconds per call, whereas it takes less than a millisecond on my PC.
I've come back to this over the years, trying:
But I've never been able to get sensible performance out of this call. Monitoring with top
while the code runs shows that the java
process never consumes more than 2% of CPU or 5% of RAM.
Avenues I've considered for a solution:
SourceDataLine
is a good fit for my use case.Here's a reproducible example (requires an external test.wav
file in the working directory):
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Date;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class Main {
public static void main(String[] args) throws Exception {
byte[] fileBytes = Files.readAllBytes(new File("./test.wav").toPath());
InputStream bais = new ByteArrayInputStream(fileBytes);
AudioInputStream ais = AudioSystem.getAudioInputStream(bais);
Clip clip = AudioSystem.getClip();
clip.open(ais);
clip.start();
for (int i = 0; i < 100; i++) {
long start = new Date().getTime();
long pos = clip.getFramePosition();
long duration = new Date().getTime() - start;
System.out.println("Pos: " + pos + ", duration: " + duration);
Thread.sleep(10);
}
}
}
Here is some sample output:
Pos: 0, duration: 0
Pos: 32778, duration: 645
Pos: 164690, duration: 2980
Pos: 262573, duration: 2207
Pos: 426196, duration: 3698
Pos: 458820, duration: 728
Pos: 524493, duration: 1479
Pos: 557127, duration: 729
Pos: 590678, duration: 749
Pos: 656352, duration: 1478
Pos: 721684, duration: 1469
Pos: 754290, duration: 728
Pos: 786924, duration: 729
Pos: 813348, duration: 588
A couple ideas. For one, I'm curious how AudioCue-maven might work on the Raspberry PI. It operates like a Clip
but is based upon a SourceDataLine
and might have the best aspects of each for your use case.
Another idea, with SourceDataLine
, you can count frames as they elapse. There's a code example in the audio tutorials, in the section "Reading Audio Files" where the number of frames being read is held. With a little modification you could make the variable readable by other threads, e.g., designate it as volatile.
It might be helpful to experiment with different buffer settings when you open
the Clip
. I'm curious also if you have a data example of the output from your laptop to show in contrast to the Raspberry output you show.