gpt4 book ai didi

java - "Endless"来自套接字的 AudioInputStream

转载 作者:太空狗 更新时间:2023-10-29 22:58:30 27 4
gpt4 key购买 nike

我在从 Socket 创建 AudioInputStream 时遇到问题。以下是重要部分:

public class SoundStream extends Thread {
private int port;
private String IP;
private Socket socket;

private SoundObject soundObject;

private OpenAL openAL;
private Source source;

private boolean run = true;

public SoundStream(int port, String IP, SoundObject soundObject) {
this.soundObject = soundObject;
this.port = port;
this.IP = IP;
}

public void run() {
try {
this.socket = new Socket(this.IP, this.port);
this.openAL = new OpenAL();
} catch (Exception e) {
e.printStackTrace();
}
this.mainCycleMethod();
}

private void mainCycleMethod() {
while (run) {
this.soundObject.blockAndWait();
switch (this.soundObject.getAndResetEvent()) {
case 0:
this.run = false;
this.close();
break;
case 1:
this.setPitch();
break;
case 2:
this.closeSource();
this.play();
break;
case 3:
this.pause(true);
break;
case 4:
this.pause(false);
break;
}
}
}

private BufferedInputStream getInputStream() throws Exception {
return new BufferedInputStream(socket.getInputStream());
}

private void setPitch() {
if(this.source != null) {
try {
this.source.setPitch(this.soundObject.getPitch());
} catch (ALException e) {
e.printStackTrace();
}
}
}

private void play() {
try {
AudioInputStream audioInputStream = new AudioInputStream(this.getInputStream(), this.soundObject.getAudioFormat(), AudioSystem.NOT_SPECIFIED);
// AudioInputStream audioInputStream_tmp = AudioSystem.getAudioInputStream(this.getInputStream());
// AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(this.soundObject.getAudioFormat(), audioInputStream_tmp);
this.source = openAL.createSource(audioInputStream);
this.source.setGain(1f);
this.source.play();
} catch (Exception ex) {
ex.printStackTrace();
}
}

private void close() {
this.closeSource();
this.openAL.close();
try {
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

private void closeSource() {
if(this.source!=null) {
this.source.close();
}
}

private void pause(boolean pause) {
if(this.source != null) {
try {
if (pause) {
this.source.pause();
} else {
this.source.play();
}
} catch (ALException ex) {
ex.printStackTrace();
}
}
}
}


public class SoundObject extends AbstractEventObject {
public AudioFormat getAudioFormat() {
boolean signed = false;
//true,false
boolean bigEndian = false;
//true,false
return new AudioFormat(this.frequency, this.bits, this.channels, signed, bigEndian);
}
.
.
.
.
}

此代码在此行抛出 UnsupportedAudioFileException:

AudioInputStream audioInputStream_tmp = AudioSystem.getAudioInputStream(this.getInputStream());

但是当我使用这段代码时:

AudioInputStream audioInputStream = new AudioInputStream(this.getInputStream(), this.soundObject.getAudioFormat(), 100000);

它播放声音,但仅在将这 100000 个样本帧加载到音频输入流之后。播放完所有 100000 帧后。

我想如果我可以在第一次 AudioInputStream 初始化期间将 AudioFormat 作为参数直接传递,我会解决这个问题,但这似乎是不可能的。我正在从服务器接收音频格式规范。

我认为一种可能的解决方案是创建一条数据线,我可以将其作为参数传递给 AudioInputStream 构造函数。但是我不确定如何将数据从套接字直接获取到数据线。我知道一个使用无限循环的解决方案,它读取数据并将它们写入数据线。但这似乎很浪费。有没有更直接的方法?

我希望可以使用 java-openAL 库来解决,因为我需要改变速度,我希望我不必自己做。

谢谢

最佳答案

我终于解决了这个问题。事实证明,java-openAL 内置了流式支持,但它不在 GitHub 上的文档中,所以一开始我没有注意到。 Source类中有一个createOutputStream方法,返回的是OutputStream。您可以将字节直接写入 OutputStream。

这是我的代码:

在这段代码中,我初始化了 OpenAL:

public void run() {
try {
this.socket = new Socket(this.IP, this.port);
this.openAL = new OpenAL();
} catch (Exception ex) {
Log.severe(ex.toString());
}
this.mainCycleMethod();
}

这是我的播放方法,当 InputStream 可用时调用:

private void play() {
try {
this.source = openAL.createSource();
this.outputWriter = new OutputWriter(this.socket.getInputStream(), this.source, this.soundObject.getAudioFormat());
this.source.setGain(1f);
this.outputWriter.start();
} catch (Exception ex) {
Log.severe(ex.toString());
}
}

您必须使用不带参数的 createSource 方法,它返回 Source 的新实例。不要在源上调用 play 方法,它由 SourceOutputStream 类处理,该实例由 createOutputStream 方法返回。手动调用 play 方法没有错,但是当缓冲区为空时,我这样做的经历很糟糕。基本上,当您开始将数据流式传输到 OpenAL 时,它不会稍后开始播放。

这是我的 OutputWriter 代码,它负责将字节从 InputStream 传递到 OutputStream:

package cz.speechtech.sound;

import org.urish.openal.ALException;
import org.urish.openal.Source;

import javax.sound.sampled.AudioFormat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
* Created by honza on 16.12.15.
*/
public class OutputWriter extends Thread {
private InputStream inputStream;
private OutputStream outputStream;

private int STREAMING_BUFFER_SIZE = 24000;
private int NUMBER_OF_BUFFERS = 4;

private boolean run = true;

public OutputWriter(InputStream inputStream, Source source, AudioFormat audioFormat) {
this.inputStream = inputStream;
try {
this.outputStream = source.createOutputStream(audioFormat, this.NUMBER_OF_BUFFERS, 1024);
} catch (ALException e) {
e.printStackTrace();
}
}

public void run() {
byte[] buffer = new byte[this.STREAMING_BUFFER_SIZE];
int i;
try {
Thread.sleep(1000); // Might cause problems
while (this.run) {
i = this.inputStream.read(buffer);
if (i == -1) break;
outputStream.write(buffer, 0, i);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public synchronized void stopRunning() {
this.run = false;
try {
this.outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}

祝你有美好的一天。

关于java - "Endless"来自套接字的 AudioInputStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33744164/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com