Java录制麦克风到字节数组和播放声音
我想用Java制作一个现场语音聊天程序,但我对Java中的录音/播放声音一无所知,所以在谷歌的帮助下,我想我已经能够从我的麦克风录制到一个字节数组了以下内容:
I want to make a live voice chatting program in Java, but I know nothing about recording/playing sound in Java, so with the help of Google, I think I have been able to record from my mic to a byte array with the following:
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();
}
现在,根据我的理解,如果我调用out.toByteArray(); ,我应该得到一个我刚从麦克风录下的声音的字节数组。 (我没有运行上面的错误,但无法证明它是否实际记录,因为我不希望将其输出到文件但没有这样做)
So now, to my understanding, if I call out.toByteArray();, I should have gotten a byte array of the sound I just recorded from my microphone. (I got no errors running the above, but have no way to prove if it actually recorded because I do not wish to output it to a file and didn't do so)
现在,如果以上是正确的,那么下面是我遇到问题的地方:
我想现在播放我刚创建的字节数组...(在我的真实程序中,我会发送通过我已经能够做到的Java套接字到我的接收程序的字节,但是现在我只想创建一个记录麦克风并播放它的小程序。为了播放字节数组中的声音信息,我按照以下方式播放: http://www.wikijava.org/ wiki / Play_a_wave_sound_in_Java
并提出以下内容:(这位于上面的microphone.close()之后)
Now, if the above is correct, then below is where I run into my problem: I want to now play the byte array I just created... (In my real program, I would've sent the bytes over to my "receiving program" through a Java socket which I have already been able to do, but right now I just want to make a small program that records the mic and plays it back). In order to play the sound information from the byte array I followed this: http://www.wikijava.org/wiki/Play_a_wave_sound_in_Java And came up with the following: (this is located right after microphone.close() from the above)
try{
DataLine.Info info2 = DataLine.Info(SourceDataLine.class, format);
SourceDataLine dataLine = (SourceDataLine)AudioSystem.getLine(info2);
int bufferSize = 2200;
soundLine.open(format, bufferSize);
soundLine.start();
AudioInputStream audioInputStream = null;
InputStream input = new ByteArrayInputStream(out.toByteArray());
audioInputStream = AudioSystem.getAudioInputStream(input);
...
其余的几乎是从playSound复制粘贴的来自此链接的.java:
http://www.wikijava.org/wiki/Play_a_wave_sound_in_Java
The rest is pretty much copy pasted from the playSound.java from this link: http://www.wikijava.org/wiki/Play_a_wave_sound_in_Java
当我运行上面的代码时...录音似乎工作正常,但我收到以下错误:
When I run the above code... The recording seems to work all right, but I get the following error:
javax.sound.sampled.UnsupportedAudioFileException:无法从输入流中获取音频输入流
对于这一行 audioInputStream = AudioSystem.getAudioInputStream(输入);
从我有限的知识,我假设这是因为我以某种方式弄乱了录音方法,我需要某种音频格式标题? https://ccrma.stanford.edu/courses/422/projects/WaveFormat/(我假设我不需要这样的东西,因为我从来没有保存到文件中,只是把它全部保存为字节数组),或者我只是完全误解了java的AudioInputStream如何读取和解析数据......
From my limited knowledge, I'm assuming it's because I somehow messed up the recording method, I need some sort of "Audio Format Header?" https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ (I assumed I wouldn't need something like that because I never saved to a file and just kept it all as a byte array), or I just completely misunderstood how java's AudioInputStream reads and parses data...
这是我第一次使用Java中的任何声音相关的东西,所以我很抱歉,如果我完全误解和屠杀这些代码(是的,我知道代码看起来非常糟糕和无组织但我只是想让它工作)...我在Google / StackOverflow上尝试了多次搜索,并且能够找到一个非常相似的问题:
This is my first time working with any sound related things in Java, so I apologize if I am completely misunderstanding and butchering this code (yeah I know the code looks pretty bad and unorganized but I just want to get it to work)... I tried multiple searches on Google/StackOverflow, and was able to find a very similar question:
但它是也没有答案(唯一的答案是将其保存到文件中,但我们都想要的是直接将其作为字节数组流式传输它曾经成为一个档案)
but it was also unanswered (the only answer was to save it to a file, but what we both want is to stream it directly as a byte array without it ever becoming a file)
我所知道的:
可以使用TargetDataLine录制音频,并录制麦克风,可以使用ByteArrayOutputStream输出到字节数组
Audio can be recorded using a TargetDataLine, and recording the microphone, which can be outputted to a Byte Array using a ByteArrayOutputStream
音频可以保存到文件中并使用AudioInputStream播放以读取文件和SourceDataLine播放数据。
Audio can be saved to a file and played by using a AudioInputStream to read the file and a SourceDataLine to play the data.
如果我想写一个文件,我可以使用AudioSystem.write(新的AudioInputStream(麦克风),AudioFileFormat.Type.WAVE,新文件(recording.wav) ); //我已经通过用这一行替换while循环来测试这个并且它记录正常(除了它永远不会停止所以我不得不手动终止它),但我不希望这样,因为输出到文件意味着它将无法通过套接字实时发送到另一方。
If I wanted to write a file, I could use AudioSystem.write(new AudioInputStream(microphone), AudioFileFormat.Type.WAVE, new File("recording.wav"); //I have tested this by replacing the while loop with this line and it recorded fine (except it would never stop so I had to manually terminate it), but I don't want that, because outputting to a file means it will be impossible to send it over a socket to another side in real time.
我不知道/我的问题:
如何录制和流式传输从麦克风录制的音频到另一台计算机,该计算机可以用尽可能小的延迟播放(非常类似于Skype的语音聊天)和Java。
How to record and stream audio recorded from a mic to another computer that can be played with as little delay as possible (pretty much like a voice chat similar to Skype) with Java.
提前感谢任何帮助或者能指出正确方向的人。如果有人知道更简单的方法,那么请告诉我。
Thanks in advance for any help or someone who can point me in the correct direction. Also if someone knows a simpler method then please tell me that as well.
编辑:
这是一个稍微好一点的同一个想法如下所示,将在您录制时直接播放
Here's a slightly better version of the same idea as below that will playback directly as you record
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();
}
请耐心等待,因为这非常粗糙,但它会录制音频播放通过扬声器;
Bear with me because this is really rough, but it gets the recorded audio playing through speakers;
为了使声音更好,你需要添加线程,并优化输入/输出流。
In order to make it sound better, you will need to add threads, and optimize the input/output streams.
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();
}
}
}