【问题标题】:Get AudioInputStream of FloatBuffer获取 FloatBuffer 的 AudioInputStream
【发布时间】:2018-04-10 12:39:27
【问题描述】:

我有一个回调,它将传入的音频数据作为 FloatBuffer 包含 1024 个浮点数,每秒被调用多次。但我需要一个AudioInputStream,因为我的系统只适用于它们。

将浮点数转换为 16 位 PCM 签名音频数据不是问题,但我无法从中创建 InputStream。 AudioInputStream 构造函数只接受已知长度的数据,但我有一个恒定的流。如果我使用包含音频数据的 PipedInputStream 向AudioSystem.getAudioInputStream 提供“java.io.IOException: mark/reset not supported”,则会引发“java.io.IOException: mark/reset not supported”。

有什么想法吗?


这是我当前的代码:

Jack jack = Jack.getInstance();
JackClient client = jack.openClient("Test", EnumSet.noneOf(JackOptions.class), EnumSet.noneOf(JackStatus.class));
JackPort in = client.registerPort("in", JackPortType.AUDIO, EnumSet.of(JackPortFlags.JackPortIsInput));

PipedInputStream pin = new PipedInputStream(1024 * 1024 * 1024);
PipedOutputStream pout = new PipedOutputStream(pin);
client.setProcessCallback(new JackProcessCallback() {
public boolean process(JackClient client, int nframes) {
    FloatBuffer inData = in.getFloatBuffer();
    byte[] buffer = new byte[inData.capacity() * 2];
    for (int i = 0; i < inData.capacity(); i++) {
        int sample = Math.round(inData.get(i) * 32767);
        buffer[i * 2] = (byte) sample;
        buffer[i * 2 + 1] = (byte) (sample >> 8);
    }
    try {
        pout.write(buffer, 0, buffer.length);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return true;
}
});
client.activate();
client.transportStart();

Thread.sleep(10000);
client.transportStop();
client.close();

AudioInputStream audio = AudioSystem.getAudioInputStream(new BufferedInputStream(pin, 1024 * 1024 * 1024));
AudioSystem.write(audio, Type.WAVE, new File("test.wav"));

它使用 JnaJack 库,但数据来自哪里并不重要。顺便说一句,转换为字节很好:将该数据直接写入SourceDataLine 将正常工作。但我需要数据 AudioInputStream.

【问题讨论】:

  • 将 PipedInputStream 包装在 BufferedInputStream 中。
  • @VGR java.io.IOException: Resetting to invalid mark
  • 为什么你需要构造AudioInputStream,因为你可以通过调用AudioSystem.getAudioInputStream得到它?如果不支持markreset,请不要使用它们。
  • 我无法通过调用AudioSystem.getAudioInputStream 获得AudioInputStream,因为这会引发上述异常。我不需要标记和重置,但getAudioInputStream(InpuStream) 显然需要。
  • 原来the other constructor of AudioInputStream有答案:给构造函数的长度可以是AudioSystem.NOT_SPECIFIED

标签: java audio audioinputstream


【解决方案1】:

AudioSystem.getAudioInputStream 需要一个符合支持的AudioFileFormat 的流,这意味着它必须符合known type。来自the documentation

流必须指向有效的音频文件数据。

也来自该文档:

此方法的实现可能需要多个解析器检查流以确定它们是否支持它。这些解析器必须能够标记流,读取足够的数据以确定它们是否支持流,并将流的读取指针重置为其原始位置。如果输入流不支持这些操作,此方法可能会失败并返回 IOException

您可以使用三参数构造函数创建自己的 AudioInputStream。如果不知道长度,可以指定为AudioSystem.NOT_SPECIFIED。令人沮丧的是,构造函数文档和类文档都没有提到这一点,但 other constructor’s documentation 却提到了。

【讨论】:

  • 我需要至少 64kiB 的管道大小和至少 128MiB(!) 的缓冲区大小才能正常工作,否则我将听不到任何声音。知道为什么这需要这么大或如何减少缓冲区吗?我正在以 1024B/s 传输 48kHz
  • 您还在使用 AudioSystem.getAudioInputStream 吗?该方法需要一个缓冲区,但如果您避免使用该方法而直接构造一个 AudioInputStream,则根本不需要任何缓冲区。当然,需要注意的是,如果阅读停止,声音将不会干净地播放。但是你不应该得到任何例外。
猜你喜欢
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
  • 2012-05-02
  • 2017-05-10
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
相关资源
最近更新 更多