Java与SourceDataLine同时播放2字节缓冲区
我正在尝试使用SourceDataLine编写两个不同的多线程缓冲区(缓冲区A和B),以同时播放声音。但它会在缓冲区A和缓冲区B之间不断切换,在将缓冲区写入SourceDataLine之前,我是否需要将它们合并在一起,还是有办法同步播放它们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 {
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
的转换