首页 > 解决方案 > Raspberry Pi 上的 Java Audio Clip#getFramePosition() 非常慢

问题描述

这个问题底部的代码片段在我的台式电脑上运行良好,调用时间为 1clip.getFramePosition()毫秒或更短。在我运行 Raspbian Stretch 和 JDK 8u191 的 Pi 3 Model B+ 上,调用相同的函数大约需要 900 毫秒。这似乎太慢了。

我实际上是在尝试通过 JLayer 播放 MP3 文件,但是 WAV 文件也会出现问题,并且使用 WAV 文件更容易重现,因为不需要外部依赖项,

CPU 和内存

运行代码时,Pi 报告的 CPU 和内存使用率top从不超过 10%。我还尝试将音频预加载到byte数组中并播放它而不是流。它有同样的问题,所以这似乎不是磁盘 I/O 瓶颈。

阻塞

在运行时,clip对象是 的一个实例com.sun.media.sound.DirectAudioDevice.DirectDL,它的getLongFramePosition()方法有一个调用native方法的同步块:

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

所以有可能是什么东西阻止了我的通话。但是,我认为Clip在播放时查询 的进度是合理的做法。

会是什么呢? 有人能解释一下这种缓慢吗?我是在滥用 API,还是这只是 Raspbian 的 Java 音频实现的问题?

更新#1:Ubuntu MATE + Liberica

我尝试使用 Liberica JRE 11 针对 Ubuntu MATE 运行代码,但仍然出现缓慢。

更新#2:外置声卡

我将外部 USB 声卡插入我的 pi 并通过它播放音频。我没想到它会解决这个问题,它没有。

更新#3:直接使用 JLayer

通过 JLayerAdvancedPlayer类而不是通过 Java Sound API 播放 MP3 会好一些。获得进度大约需要 50 毫秒而不是 900 毫秒,但这仍然非常缓慢。

更新 #4:使用 Pi 3 Model B

我有一个 Pi 3 Model B(不是 B+)。运行最新的 Raspbian 时也有同样的问题。使用 Raspbian Jessie (2016-03-18) 会更快一些(约 700 毫秒),但并不多。


示例代码

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);
        }
    }
}

标签: javaaudioraspberry-pi

解决方案


推荐阅读