【问题标题】:Java play 2 byte buffers at the same time with SourceDataLineJava 与 SourceDataLine 同时播放 2 字节缓冲区
【发布时间】:2012-11-05 21:17:03
【问题描述】:

我正在尝试使用 SourceDataLine 编写 2 个不同的缓冲区(缓冲区 A 和 B),以同时播放声音。但是它一直在缓冲区 A 和缓冲区 B 之间切换,我是否需要在将缓冲区写入我的 SourceDataLine 之前将它们合并在一起,或者有没有办法同步播放它们?

class PlayThread extends Thread {
    byte[] buffer = new byte[2 * 1024];

    @Override
    public void run() {
        try {
            while (true) {
                DatagramPacket receive = new DatagramPacket(buffer, buffer.length);
                mDatagramSocket.receive(receive);
                mSourceDataLine.write(receive.getData(), 0, receive.getData().length);

                System.out.println("Received!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

我有 2 个具有不同传入缓冲区的 PlayThread 实例。下面是初始化 SourceDataLine 的函数。

private void init() {
    try {
        DataLine.Info sourceDataLineInfo = new DataLine.Info(
                SourceDataLine.class, audioFormat);
        DataLine.Info targetDataLineInfo = new DataLine.Info(
                TargetDataLine.class, audioFormat);

        Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();

        Mixer mixer = AudioSystem.getMixer(mixerInfo[3]);
        mSourceDataLine = (SourceDataLine) AudioSystem
                .getLine(sourceDataLineInfo);
        mTargetDataLine = (TargetDataLine) mixer.getLine(targetDataLineInfo);

        mSourceDataLine.open(audioFormat, 2 * 1024);
        mSourceDataLine.start();

        mTargetDataLine.open(audioFormat, 2 * 1024);
        mTargetDataLine.start();
    } catch (LineUnavailableException ex) {
        ex.printStackTrace();
    }
}

谢谢。

【问题讨论】:

    标签: java audio playback synchronize


    【解决方案1】:

    您绝对必须合并它们。想象一下从两个线程将数字写入文件:

    123456...
    123456...
    

    可能变成

    11234235656...
    

    你发生了什么事。

    另一个问题是您需要缓冲来自网络的数据,否则您可能会丢弃它。您至少需要两个线程——一个用于阅读,一个用于播放以使其正常工作。但是,在您的情况下,每个输入数据包流使用一个读取器线程可能会更好。 (请参阅我的演讲幻灯片:http://blog.bjornroche.com/2011/11/slides-from-fundamentals-of-audio.html 我特别有一张关于从 http 流式传输的幻灯片,这也与此处相关)

    因此,不要使用多个 PlayThreads,而是创建多个 ReaderThreads,它们等待数据然后写入某种缓冲区(PipedInputPipedOutputStream 适用于 Java)。然后你需要另一个线程从缓冲区中读取数据,然后将组合数据写入流。

    这留下了您最初的问题,即如何组合数据。答案是没有单一的答案,但通常最简单的正确方法是逐个样本对数据进行平均。但是,具体如何执行取决于您的数据格式,您的代码不包含该格式。假设它是 big-endian 16 位整数,您需要将传入的原始数据转换为 short,平均 short,然后将平均 short 转换回字节。

    使用DataInputStreamDataOutputStream 最容易完成byteshort 的转换。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-12
      • 1970-01-01
      • 1970-01-01
      • 2011-10-31
      • 2013-11-22
      • 1970-01-01
      • 1970-01-01
      • 2014-07-09
      相关资源
      最近更新 更多