Java Audio Clip#getFramePosition() very slow on Raspberry Pi

Viewed 205

The code snippet at the bottom of this question runs fine on my desktop PC, calls to clip.getFramePosition() take 1ms or less. On my Pi 3 Model B+ running Raspbian Stretch and JDK 8u191, it takes around 900ms to call the same function. This seems way too slow.

I'm actually trying to play an MP3 file via JLayer, but the issue also occurs with WAV files and it's easier to reproduce with a WAV file as no external dependencies are needed,

CPU and Memory

The Pi's CPU and memory usage as reported by top are never greater than 10% when running the code. I've also tried preloading the audio into a byte array and playing that instead of the stream. It has the same issue, so this doesn't appear to be a disk I/O bottleneck.

Blocking

At runtime, the clip object is an instance of com.sun.media.sound.DirectAudioDevice.DirectDL, and its getLongFramePosition() method has a synchronized block that calls a native method:

synchronized(this.lockNative) {
    var1 = DirectAudioDevice.nGetBytePosition(this.id, this.isSournce, this.bytePosition);
}

So it's possible that something is blocking my call. However, I would have thought querying a Clip's progress while it's playing is a reasonable thing to do.

What could it be? Can anybody shed some light on this slowness? Am I misusing the API, or could this just be an issue with Raspbian's Java Audio implementation?

Update #1: Ubuntu MATE + Liberica

I tried running the code against Ubuntu MATE with Liberica JRE 11 and the slowness still occurred.

Update #2: External sound card

I plugged an external USB sound card into my pi and played the audio through that. I didn't expect it to fix the issue, and it didn't.

Update #3: Use JLayer directly

Playing an MP3 via the JLayer AdvancedPlayer class instead of through the Java Sound API is a bit better. It takes around 50ms to get the progress instead of 900ms, but that's still very slow.

Update #4: Use Pi 3 Model B

I have a Pi 3 Model B (not B+) laying around. It has the same issue when running the latest Raspbian. With Raspbian Jessie (2016-03-18) it's a bit faster (~700ms) but not much.


Sample Code

import java.io.File;
import java.io.InputStream;
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 {
        File file = new File("/home/pi/beat.wav");
        AudioInputStream ais = AudioSystem.getAudioInputStream(file);
        AudioFormat format = ais.getFormat();

        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);
        }
    }
}
0 Answers
Related