Java录制麦克风到字节数组和播放声音

我想用Java制作一个现场语音聊天程序,但我对Java中的录音/播放声音一无所知,所以在Google的帮助下,我想我已经能够从我的麦克风录制到一个字节数组,其中包含以下内容:

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();,我应该得到一个我刚从麦克风录制的声音的字节数组。 (我没有运行上面的错误,但没有办法certificate它是否实际记录,因为我不希望将其输出到文件但没有这样做)

现在,如果以上是正确的,那么下面是我遇到问题的地方:我现在要播放我刚创建的字节数组…(在我的真实程序中,我会将字节发送到我的“接收”程序“通过我已经能够做的Java套接字,但是现在我只想创建一个记录麦克风并播放它的小程序”。 为了播放字节数组中的声音信息,我按照以下方式播放: http : //www.wikijava.org/wiki/Play_a_wave_sound_in_Java并提出以下内容:(这位于上面的microphone.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); ... 

其余的几乎是从playSound.java通过以下链接复制粘贴的: http : //www.wikijava.org/wiki/Play_a_wave_sound_in_Java

当我运行上面的代码…录音似乎工作正常,但我得到以下错误:

javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input stream

对于这一行audioInputStream = AudioSystem.getAudioInputStream(input);

从我有限的知识,我假设它是因为我以某种方式弄乱了录音方法,我需要某种“音频格式标题?” https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ (我以为我不需要那样的东西,因为我从来没有保存到文件中,只是把它全部保存为字节数组),或者我只是完全误解了java的AudioInputStream如何读取和解析数据……

这是我第一次使用Java中的任何声音相关的东西,所以我很抱歉,如果我完全误解和屠杀这些代码(是的,我知道代码看起来非常糟糕和无组织但我只是想让它工作)…我在Google / StackOverflow上尝试了多次搜索,并找到了一个非常相似的问题:

java字节数组播放声音

但它也没有答案(唯一的答案是将它保存到文件中,但我们都想要的是直接将其作为字节数组流式传输而不会成为文件)

我所知道的:

可以使用TargetDataLine录制音频,并录制麦克风,可以使用ByteArrayOutputStream将其输出到字节数组

音频可以保存到文件中并使用AudioInputStream读取文件和SourceDataLine来播放数据。

如果我想写一个文件,我可以使用AudioSystem.write(新的AudioInputStream(麦克风),AudioFileFormat.Type.WAVE,新文件(“recording.wav”); //我已经通过用这个替换while循环来测试它行和它记录正常(除了它永远不会停止所以我不得不手动终止它),但我不希望这样,因为输出到文件意味着它将无法通过套接字实时发送到另一侧。

我不知道/我的问题:

如何录制和流式传输从麦克风录制的音频到另一台计算机,该计算机可以尽可能少地延迟播放(非常类似于Skype的语音聊天)和Java。

提前感谢任何帮助或能指出我正确方向的人。 如果有人知道更简单的方法,那么请告诉我。

编辑:这是一个稍微好一点的相同想法的版本,将在您录制时直接播放

 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(); } 

忍受我,因为这真的很粗糙,但它通过扬声器播放录制的音频;

为了使声音更好,您需要添加线程,并优化输入/输出流。

http://www.developer.com/java/other/article.php/1579071/Java-Sound-Getting-Started-Part-2-Capture-Using-Specified-Mixer.htm

 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(); } } }