Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java与SourceDataLine同时播放2字节缓冲区_Java_Audio_Playback_Synchronize - Fatal编程技术网

Java与SourceDataLine同时播放2字节缓冲区

Java与SourceDataLine同时播放2字节缓冲区,java,audio,playback,synchronize,Java,Audio,Playback,Synchronize,我正在尝试使用SourceDataLine编写两个不同的多线程缓冲区(缓冲区A和B),以同时播放声音。但它会在缓冲区A和缓冲区B之间不断切换,在将缓冲区写入SourceDataLine之前,我是否需要将它们合并在一起,还是有办法同步播放它们 class PlayThread extends Thread { byte[] buffer = new byte[2 * 1024]; @Override public void run() { try {

我正在尝试使用SourceDataLine编写两个不同的多线程缓冲区(缓冲区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();
        }
    }
}
我有两个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();
    }
}

谢谢。

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

123456...
123456...
可能成为

11234235656...
这就是发生在你身上的事

另一个问题是,当数据从网络传入时,您需要对其进行缓冲,否则可能会丢失数据。你至少需要两个线程——一个用于阅读,一个用于播放,这样才能工作。然而,在您的情况下,对于每个输入数据包流,您可能会有一个读取器线程。(请参阅我的演讲幻灯片:我特别有一张关于http流的幻灯片,这张幻灯片也与此相关)

因此,不要使用多个PlayThreads,而是使用多个ReaderThreads,它们等待数据,然后写入某种类型的缓冲区(
PipedInput
PipedOutStream
对Java很有效)。然后,需要另一个线程从缓冲区读取数据,然后将组合数据写入流

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


使用
DataInputStream
DataOutputStream
byte
short
的转换最容易完成,您绝对需要合并它们。想象一下,从两个线程将数字写入文件:

123456...
123456...
可能成为

11234235656...
这就是发生在你身上的事

另一个问题是,当数据从网络传入时,您需要对其进行缓冲,否则可能会丢失数据。你至少需要两个线程——一个用于阅读,一个用于播放,这样才能工作。然而,在您的情况下,对于每个输入数据包流,您可能会有一个读取器线程。(请参阅我的演讲幻灯片:我特别有一张关于http流的幻灯片,这张幻灯片也与此相关)

因此,不要使用多个PlayThreads,而是使用多个ReaderThreads,它们等待数据,然后写入某种类型的缓冲区(
PipedInput
PipedOutStream
对Java很有效)。然后,需要另一个线程从缓冲区读取数据,然后将组合数据写入流

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

使用
DataInputStream
DataOutputStream
最容易实现从
byte
short
的转换