Java将麦克风录制到字节数组并播放声音
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25798200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Record Mic to Byte Array and Play sound
提问by XQEWR
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:
我想用 Java 制作一个实时语音聊天程序,但我对用 Java 录制/播放声音一无所知,所以在谷歌的帮助下,我想我已经能够从我的麦克风录制到一个字节数组,如下所示:
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();
}
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)
所以现在,据我所知,如果我调用 out.toByteArray();,我应该得到我刚刚从我的麦克风录制的声音的字节数组。(我在运行上面没有任何错误,但无法证明它是否真的记录了,因为我不想将它输出到文件中并且没有这样做)
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_JavaAnd came up with the following: (this is located right after microphone.close() from the above)
现在,如果以上是正确的,那么下面就是我遇到问题的地方:我现在想播放我刚刚创建的字节数组......(在我的实际程序中,我会将字节发送到我的“接收程序”通过我已经能够做到的Java套接字,但现在我只想制作一个小程序来记录麦克风并播放它)。为了播放字节数组中的声音信息,我遵循了这个:http: //www.wikijava.org/wiki/Play_a_wave_sound_in_Java并提出了以下内容:(这位于上面的mic.close()之后)
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);
...
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
其余的几乎是从这个链接的 playSound.java 复制粘贴的: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: could not get audio input stream from input stream
javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input stream
for this line audioInputStream = AudioSystem.getAudioInputStream(input);
对于这条线 audioInputStream = AudioSystem.getAudioInputStream(input);
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...
根据我有限的知识,我假设这是因为我以某种方式弄乱了录音方法,我需要某种“音频格式标题?” https://ccrma.stanford.edu/courses/422/projects/WaveFormat/(我假设我不需要这样的东西,因为我从来没有保存到文件中,只是把它保存为一个字节数组),或者我只是完全误解了 java 的 AudioInputStream 如何读取和解析数据...
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:
这是我第一次在 Java 中处理任何与声音相关的事情,所以如果我完全误解和扼杀了这段代码,我深表歉意(是的,我知道代码看起来很糟糕而且没有组织,但我只是想让它工作)......我在 Google/StackOverflow 上尝试了多次搜索,并找到了一个非常相似的问题:
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)
但它也没有得到答复(唯一的答案是将其保存到文件中,但我们都希望将其作为字节数组直接流式传输,而不会成为文件)
What I do know:
我所知道的:
Audio can be recorded using a TargetDataLine, and recording the microphone, which can be outputted to a Byte Array using a ByteArrayOutputStream
可以使用 TargetDataLine 录制音频,并录制麦克风,可以使用 ByteArrayOutputStream 将其输出到 Byte Array
Audio can be saved to a file and played by using a AudioInputStream to read the file and a SourceDataLine to play the data.
可以将音频保存到文件中并通过使用 AudioInputStream 读取文件和使用 SourceDataLine 播放数据来播放。
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.
如果我想写一个文件,我可以使用 AudioSystem.write(new AudioInputStream(microphone), AudioFileFormat.Type.WAVE, new File("recording.wav"); //我已经通过用这个替换while循环来测试这个行并且它记录得很好(除非它永远不会停止,所以我不得不手动终止它),但我不希望那样,因为输出到文件意味着不可能通过套接字将它实时发送到另一端.
What I don't know / My Question:
我不知道的/我的问题:
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.
如何使用 Java 录制从麦克风录制的音频并将其流式传输到另一台可以以尽可能少的延迟播放的计算机(非常类似于类似于 Skype 的语音聊天)。
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.
在此先感谢您的帮助或可以为我指明正确方向的人。另外,如果有人知道更简单的方法,也请告诉我。
采纳答案by Nick
EDIT: 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();
}
}
}