有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

所以现在,据我所知,如果我大声呼喊。toByteArray();,我应该得到我刚从麦克风录制的声音的字节数组。(我在运行上述命令时没有发现错误,但无法证明它是否真的录制了,因为我不希望将其输出到文件,也没有这样做)

现在,如果以上是正确的,那么下面就是我遇到问题的地方: 现在我想播放我刚刚创建的字节数组。。。(在我的实际程序中,我会通过Javasocket将字节发送到我的“接收程序”,我已经能够做到这一点,但现在我只想制作一个小程序,记录麦克风并播放它)。为了播放字节数组中的声音信息,我遵循以下步骤:http://www.wikijava.org/wiki/Play_a_wave_sound_in_Java 并得出以下结论:(位于麦克风的正后方。从上面开始关闭()

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 byte array play sound

但它也没有得到回答(唯一的答案是将它保存到一个文件中,但我们都希望直接将其作为字节数组进行流式处理,而不使其成为一个文件)

我所知道的是:

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

通过使用AudioInputStream读取文件并使用SourceDataLine播放数据,可以将音频保存到文件并播放

如果我想写一个文件,我可以使用AudioSystem。写入(新音频输入流(麦克风),音频文件格式。类型WAVE,新文件(“recording.wav”)//我已经用这行代码替换了while循环进行了测试,它记录得很好(除非它永远不会停止,所以我必须手动终止它),但我不希望这样,因为输出到文件意味着不可能通过socket实时将它发送到另一端

我不知道的/我的问题:

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

提前感谢您的帮助或能为我指明正确方向的人。另外,如果有人知道一个更简单的方法,那么请告诉我,以及


共 (1) 个答案

  1. # 1 楼答案

    编辑: 下面是一个稍微好一点的版本,它将在您录制时直接播放

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