Java录制麦克风到字节阵列并播放声音
我想用Java制作一个实时语音聊天程序,但我对用Java录制/播放声音一无所知,因此在Google的帮助下,我想我已经能够通过以下方式从麦克风录制到字节数组:Java录制麦克风到字节阵列并播放声音,java,sockets,audio,microphone,Java,Sockets,Audio,Microphone,我想用Java制作一个实时语音聊天程序,但我对用Java录制/播放声音一无所知,因此在Google的帮助下,我想我已经能够通过以下方式从麦克风录制到字节数组: AudioFormat format = new AudioFormat(8000.0f, 16, 1, true, true); TargetDataLine microphone; try{ microphone = AudioSystem.getTargetDataLine(format); DataLine.In
AudioFormat format = new AudioFormat(8000.0f, 16, 1, true, true);
TargetDataLine microphone;
try{
microphone = AudioSystem.getTargetDataLine(format);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
microphone = (TargetDataLine)AudioSystem.getLine(info);
microphone.open(format);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int numBytesRead;
byte[] data = new byte[microphone.getBufferSize()/5];
microphone.start();
int bytesRead =0;
try{
while(bytesRead<100000){ //Just so I can test if recording my mic works...
numBytesRead = microphone.read(data, 0, data.length);
bytesRead = bytesRead + numBytesRead;
// System.out.println(bytesRead);
out.write(data, 0, numBytesRead);
}
catch(Exception e){
e.printStackTrace();
}
microphone.close();
catch(LineUnavailibleException e){
e.printStackTrace();
}
其余的几乎都是从playSound.java中从以下链接粘贴的副本:
当我运行上面的代码时。。。录音似乎正常,但我发现以下错误:
javax.sound.sampled.UnsupportedAudioFileException:无法从输入流获取音频输入流
对于此行audioInputStream=AudioSystem.getAudioInputStream(输入)代码>
根据我有限的知识,我假设这是因为我不知怎么搞砸了录音方法,我需要某种“音频格式头?”(我假设我不需要这样的东西,因为我从未保存到文件中,只是将其作为字节数组保存),或者我完全误解了java的AudioInputStream是如何读取和解析数据的
这是我第一次在Java中处理任何与声音相关的东西,因此如果我完全误解并破坏了这段代码,我深表歉意(是的,我知道代码看起来很糟糕,没有条理,但我只是想让它正常工作)。。。我在Google/StackOverflow上尝试了多次搜索,发现了一个非常类似的问题:
但它也没有得到回答(唯一的答案是将它保存到一个文件中,但我们都希望直接将其作为字节数组进行流式处理,而不使其成为一个文件)
我所知道的是:
可以使用TargetDataLine录制音频,并录制麦克风,麦克风可以使用ByteArrayOutputStream输出到字节数组
通过使用AudioInputStream读取文件并使用SourceDataLine播放数据,可以将音频保存到文件并播放
如果我想写一个文件,我可以使用AudioSystem.write(新的AudioInputStream(麦克风)、AudioFileFormat.Type.WAVE、新文件(“recording.wav”);//我用这一行替换while循环进行了测试,它录得很好(除非它永远不会停止,所以我不得不手动终止它),但我不希望这样,因为输出到文件意味着不可能通过套接字将其实时发送到另一端
我不知道的/我的问题:
如何使用Java将从麦克风录制的音频录制并流式传输到另一台可以尽可能少延迟播放的计算机(非常类似于Skype的语音聊天)
提前感谢您的帮助或能为我指出正确方向的人。如果有人知道更简单的方法,请告诉我。编辑:
下面是一个稍微好一点的版本,它将在您录制时直接播放
AudioFormat format = new AudioFormat(8000.0f, 16, 1, true, true);
TargetDataLine microphone;
SourceDataLine speakers;
try {
microphone = AudioSystem.getTargetDataLine(format);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
microphone = (TargetDataLine) AudioSystem.getLine(info);
microphone.open(format);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int numBytesRead;
int CHUNK_SIZE = 1024;
byte[] data = new byte[microphone.getBufferSize() / 5];
microphone.start();
int bytesRead = 0;
DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
speakers = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
speakers.open(format);
speakers.start();
while (bytesRead < 100000) {
numBytesRead = microphone.read(data, 0, CHUNK_SIZE);
bytesRead += numBytesRead;
// write the mic data to a stream for use later
out.write(data, 0, numBytesRead);
// write mic data to stream for immediate playback
speakers.write(data, 0, numBytesRead);
}
speakers.drain();
speakers.close();
microphone.close();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
AudioFormat格式=新的AudioFormat(8000.0f,16,1,true,true);
目标数据线话筒;
数据线扬声器;
试一试{
麦克风=AudioSystem.getTargetDataLine(格式);
DataLine.Info=newdataline.Info(TargetDataLine.class,格式);
麦克风=(TargetDataLine)AudioSystem.getLine(信息);
麦克风。打开(格式);
ByteArrayOutputStream out=新建ByteArrayOutputStream();
int numBytesRead;
int CHUNK_SIZE=1024;
byte[]data=新字节[micromic.getBufferSize()/5];
麦克风。开始();
int字节读取=0;
DataLine.Info dataLineInfo=新的DataLine.Info(SourceDataLine.class,格式);
扬声器=(SourceDataLine)AudioSystem.getLine(dataLineInfo);
发言者:公开(格式);
扬声器。开始();
而(字节数<100000){
numBytesRead=麦克风读取(数据,0,块大小);
字节读取+=字节读取数;
//将麦克风数据写入流以供以后使用
out.write(数据,0,numbytes读取);
//将麦克风数据写入流以便立即播放
扬声器。写入(数据,0,numBytesRead);
}
扬声器。排水管();
扬声器。关闭();
麦克风关闭();
}捕获(LineUnavailableException e){
e、 printStackTrace();
}
容忍我,因为这真的很粗糙,但它通过扬声器播放录制的音频
为了让它听起来更好,您需要添加线程,并优化输入/输出流
package音频;
导入java.io.ByteArrayInputStream;
导入java.io.ByteArrayOutputStream;
导入java.io.IOException;
导入java.io.InputStream;
导入javax.sound.sampled.AudioFormat;
导入javax.sound.sampled.AudioInputStream;
导入javax.sound.sampled.AudioSystem;
导入javax.sound.sampled.DataLine;
导入javax.sound.sampled.LineUnavailableException;
导入javax.sound.sampled.SourceDataLine;
导入javax.sound.sampled.TargetDataLine;
公开课听力测试{
公共静态void main(字符串[]args){
AudioFormat格式=新的AudioFormat(8000.0f,16,1,true,true);
目标数据线话筒;
音频输入流音频输入流;
SourceDataLine SourceDataLine;
试一试{
麦克风=AudioSystem.getTargetDataLine(格式);
DataLine.Info=newdataline.Info(TargetDataLine.class,格式);
麦克风=(TargetDataLine)AudioSystem.getLine(信息);
麦克风。打开(格式);
ByteArrayOutputStream out=新建ByteArrayOutputStream();
int numBytesRead;
int CHUNK_SIZE=1024;
byte[]data=新字节[micromic.getBufferSize()/5];
麦克风。开始();
int字节读取=0;
试一试{
而(bytesRead<100000){//,这样我就可以测试是否录制了
//我的麦克风工作。。。
numBytesRead=麦克风读取(数据,0,块大小);
字节读取=字节读取+字节读取;
系统输出打印LN(字节)
AudioFormat format = new AudioFormat(8000.0f, 16, 1, true, true);
TargetDataLine microphone;
SourceDataLine speakers;
try {
microphone = AudioSystem.getTargetDataLine(format);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
microphone = (TargetDataLine) AudioSystem.getLine(info);
microphone.open(format);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int numBytesRead;
int CHUNK_SIZE = 1024;
byte[] data = new byte[microphone.getBufferSize() / 5];
microphone.start();
int bytesRead = 0;
DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
speakers = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
speakers.open(format);
speakers.start();
while (bytesRead < 100000) {
numBytesRead = microphone.read(data, 0, CHUNK_SIZE);
bytesRead += numBytesRead;
// write the mic data to a stream for use later
out.write(data, 0, numBytesRead);
// write mic data to stream for immediate playback
speakers.write(data, 0, numBytesRead);
}
speakers.drain();
speakers.close();
microphone.close();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
package audio;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;
public class AudioTest {
public static void main(String[] args) {
AudioFormat format = new AudioFormat(8000.0f, 16, 1, true, true);
TargetDataLine microphone;
AudioInputStream audioInputStream;
SourceDataLine sourceDataLine;
try {
microphone = AudioSystem.getTargetDataLine(format);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
microphone = (TargetDataLine) AudioSystem.getLine(info);
microphone.open(format);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int numBytesRead;
int CHUNK_SIZE = 1024;
byte[] data = new byte[microphone.getBufferSize() / 5];
microphone.start();
int bytesRead = 0;
try {
while (bytesRead < 100000) { // Just so I can test if recording
// my mic works...
numBytesRead = microphone.read(data, 0, CHUNK_SIZE);
bytesRead = bytesRead + numBytesRead;
System.out.println(bytesRead);
out.write(data, 0, numBytesRead);
}
} catch (Exception e) {
e.printStackTrace();
}
byte audioData[] = out.toByteArray();
// Get an input stream on the byte array
// containing the data
InputStream byteArrayInputStream = new ByteArrayInputStream(
audioData);
audioInputStream = new AudioInputStream(byteArrayInputStream,format, audioData.length / format.getFrameSize());
DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
sourceDataLine.open(format);
sourceDataLine.start();
int cnt = 0;
byte tempBuffer[] = new byte[10000];
try {
while ((cnt = audioInputStream.read(tempBuffer, 0,tempBuffer.length)) != -1) {
if (cnt > 0) {
// Write data to the internal buffer of
// the data line where it will be
// delivered to the speaker.
sourceDataLine.write(tempBuffer, 0, cnt);
}// end if
}
} catch (IOException e) {
e.printStackTrace();
}
// Block and wait for internal buffer of the
// data line to empty.
sourceDataLine.drain();
sourceDataLine.close();
microphone.close();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
}