web-dev-qa-db-ja.com

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();を呼び出すと、マイクから録音したばかりのサウンドのバイト配列を取得できたはずです。 (上記を実行してもエラーは発生しませんでしたが、ファイルに出力したくなかったため、実際に記録されたかどうかを証明する方法がありません。)

さて、上記が正しい場合は、以下が問題が発生した場所です。今作成したバイト配列を再生したいのですが(実際のプログラムでは、バイトを「受信プログラム」はJavaソケットを介して実行できますが、今はマイクを録音して再生する小さなプログラムを作成したいだけです)。バイト配列からサウンド情報を再生するために、私はこれに従いました: http://www.wikijava.org/wiki/Play_a_wave_sound_in_Java そして、以下を思いつきました:(これはマイクのすぐ後にあります。上記の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(new AudioInputStream(microphone)、AudioFileFormat.Type.WAVE、new File( "recording.wav"); // whileループをこれに置き換えてテストしました行とそれはうまく記録しました(ただし、停止することはないため、手動で終了する必要がありました)。ただし、ファイルに出力すると、ソケットを介してリアルタイムで別のサイドに送信することができないため、それは望ましくありません。

私が知らないこと/私の質問:

マイクから録音されたオーディオを、Javaで可能な限り遅延なしで再生できる別のコンピューター(Skypeに似たボイスチャットのようなもの)に録音およびストリーミングする方法。

私を正しい方向に向けてくれる助けや誰かに前もって感謝します。また、誰かがより簡単な方法を知っているなら、それも教えてください。

14
XQEWR

編集:以下は、録音と同時に直接再生される、同じアイデアのわずかに優れたバージョンです。

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