web-dev-qa-db-ja.com

Android AudioRecorderで.Wavを録音する

AndroidのAudioRecorderに関するページをたくさん読みました。質問の下にそれらのリストが表示されます。

AudioRecorderでオーディオを録音しようとしていますが、うまく機能しません。

public class MainActivity extends Activity {

AudioRecord ar = null;
int buffsize = 0;

int blockSize = 256;
boolean isRecording = false;
private Thread recordingThread = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


}

public void baslat(View v)
{
            // when click to START 
    buffsize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
    ar = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, buffsize);

    ar.startRecording();

    isRecording = true;
    recordingThread = new Thread(new Runnable() {
        public void run() {
            writeAudioDataToFile();
        }
    }, "AudioRecorder Thread");
    recordingThread.start();
}
public void durdur(View v)
{
            // When click to STOP
    ar.stop();
    isRecording = false;
}

private void writeAudioDataToFile() {
    // Write the output audio in byte

    String filePath = "/sdcard/voice8K16bitmono.wav";
    short sData[] = new short[buffsize/2];

    FileOutputStream os = null;
    try {
        os = new FileOutputStream(filePath);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    while (isRecording) {
        // gets the voice output from microphone to byte format

        ar.read(sData, 0, buffsize/2);
        Log.d("eray","Short wirting to file" + sData.toString());
        try {
            // // writes the data to file from buffer
            // // stores the voice buffer
            byte bData[] = short2byte(sData);
            os.write(bData, 0, buffsize);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private byte[] short2byte(short[] sData) {
    int shortArrsize = sData.length;
    byte[] bytes = new byte[shortArrsize * 2];
    for (int i = 0; i < shortArrsize; i++) {
        bytes[i * 2] = (byte) (sData[i] & 0x00FF);
        bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
        sData[i] = 0;
    }
    return bytes;

}

それは.wavファイルを作成していますが、それを聴こうとすると、開いていません。 「ファイルがサポートされていません」というエラーが表示されます。かなりの数のメディアプレーヤーアプリケーションでファイルを再生しようとしました。

[〜#〜]ノート[〜#〜]:アプリが録音中に別のプロセスを実行するため、MediaRecorderの代わりにAudioRecorderを使用する必要があります(表示イコライザー)。

これは私がこの主題について読んだページのリストです:

  1. http://developer.Android.com/reference/Android/media/AudioRecord.html#read(short []、%20int、%20int)
  2. Android AudioRecordの例
  3. http://audiorecordandroid.blogspot.in
  4. AudioRecordオブジェクトが初期化されていません
  5. マイクからのwavファイルの録音Android-問題
  6. http://i-liger.com/article/Android-wav-audio-recording
  7. Android SDK を使用して生のPCMデータからWAVファイルを作成する
  8. Androidで周波数を分析および視覚化するためのサウンドのキャプチャ

これを行うにはさまざまな方法があります。私はそれらをたくさん試しましたが、何もうまくいきません。私はこの問題に約6時間取り組んできたので、決定的な答え、理想的にはいくつかのサンプルコードに感謝します。

12
Eray

PCMAudioHelper 問題を解決しました。この回答を変更して説明しますが、最初にこのクラスでいくつかのテストを行う必要があります。

9
Eray

昨日、これを行うための簡単な(専門的な基準ではなく、読む必要がある)クラスを作成しました。

        private class Wave
    {
    private final int LONGINT = 4; 
    private final int SMALLINT = 2;
    private final int INTEGER = 4;
    private final int ID_STRING_SIZE = 4;
    private final int WAV_RIFF_SIZE = LONGINT+ID_STRING_SIZE; 
    private final int WAV_FMT_SIZE = (4*SMALLINT)+(INTEGER*2)+LONGINT+ID_STRING_SIZE; 
    private final int WAV_DATA_SIZE = ID_STRING_SIZE+LONGINT;
    private final int WAV_HDR_SIZE = WAV_RIFF_SIZE+ID_STRING_SIZE+WAV_FMT_SIZE+WAV_DATA_SIZE;
    private final short PCM = 1;
    private final int SAMPLE_SIZE = 2;
    int cursor, nSamples;
    byte[] output;

        public Wave(int sampleRate, short nChannels, short[] data, int start, int end)
        {
            nSamples=end-start+1;
            cursor=0;
            output=new byte[nSamples*SMALLINT+WAV_HDR_SIZE];
            buildHeader(sampleRate,nChannels);
            writeData(data,start,end);
        }
        // ------------------------------------------------------------
        private void buildHeader(int sampleRate, short nChannels)
        {
            write("RIFF");
            write(output.length);
            write("WAVE");
            writeFormat(sampleRate, nChannels);
        }
        // ------------------------------------------------------------
        public void writeFormat(int sampleRate, short nChannels)
        {
            write("fmt ");
            write(WAV_FMT_SIZE-WAV_DATA_SIZE);
            write(PCM);
            write(nChannels);
            write(sampleRate);
            write(nChannels * sampleRate * SAMPLE_SIZE);
            write((short)(nChannels * SAMPLE_SIZE));
            write((short)16);
        }
        // ------------------------------------------------------------
        public void writeData(short[] data, int start, int end)
        {
            write("data");
            write(nSamples*SMALLINT);
            for(int i=start; i<=end; write(data[i++]));
        }
        // ------------------------------------------------------------
        private void write(byte b)
        {
            output[cursor++]=b;
        }
        // ------------------------------------------------------------
        private void write(String id)
        {
            if(id.length()!=ID_STRING_SIZE) Utils.logError("String "+id+" must have four characters.");
            else {
                for(int i=0; i<ID_STRING_SIZE; ++i) write((byte)id.charAt(i));
            }
        }
        // ------------------------------------------------------------
        private void write(int i)
        {
            write((byte) (i&0xFF)); i>>=8;
            write((byte) (i&0xFF)); i>>=8;
            write((byte) (i&0xFF)); i>>=8;
            write((byte) (i&0xFF));
        }
        // ------------------------------------------------------------
        private void write(short i)
        {
            write((byte) (i&0xFF)); i>>=8;
            write((byte) (i&0xFF));
        }
        // ------------------------------------------------------------
        public boolean wroteToFile(String filename)
        {
        boolean ok=false;

            try {
                File path=new File(getFilesDir(),filename);
                FileOutputStream outFile = new FileOutputStream(path);
                outFile.write(output);
                outFile.close();
                ok=true;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                ok=false;
            } catch (IOException e) {
                ok=false;
                e.printStackTrace();
            }
            return ok;
        }
    }

お役に立てれば

12
user3660664

これは [〜#〜] omrecorder [〜#〜].WAV形式の記録に役立ちます。

.aacが動作する場合は、これをチェックしてください WhatsappAudioRecorder

StartRecordingボタンをクリックします。

  1. 新しいスレッドを初期化します。
  2. .aac拡張子の付いたファイルを作成します。
  3. ファイルの出力ストリームを作成します。
  4. 出力を設定
  5. SetListenerと実行スレッド。

OnStopClick:

  1. スレッドを中断すると、オーディオがファイルに保存されます。

これは参考のための完全な要点です:

import Android.media.AudioFormat;
import Android.media.AudioRecord;
import Android.media.MediaCodec;
import Android.media.MediaCodecInfo;
import Android.media.MediaFormat;
import Android.media.MediaRecorder;
import Android.os.Build;
import Android.util.Log;

import Java.io.IOException;
import Java.io.OutputStream;
import Java.nio.ByteBuffer;

public class AudioRecordThread implements Runnable {

    private static final String TAG = AudioRecordThread.class.getSimpleName();

    private static final int SAMPLE_RATE = 44100;
    private static final int SAMPLE_RATE_INDEX = 4;
    private static final int CHANNELS = 1;
    private static final int BIT_RATE = 32000;

    private final int bufferSize;
    private final MediaCodec mediaCodec;
    private final AudioRecord audioRecord;
    private final OutputStream outputStream;

    private OnRecorderFailedListener onRecorderFailedListener;


    AudioRecordThread(OutputStream outputStream, OnRecorderFailedListener onRecorderFailedListener) throws IOException {

        this.bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
        this.audioRecord = createAudioRecord(this.bufferSize);
        this.mediaCodec = createMediaCodec(this.bufferSize);
        this.outputStream = outputStream;
        this.onRecorderFailedListener = onRecorderFailedListener;

        this.mediaCodec.start();

        try {
            audioRecord.startRecording();
        } catch (Exception e) {
            Log.w(TAG, e);
            mediaCodec.release();
            throw new IOException(e);
        }
    }

    @Override
    public void run() {
        if (onRecorderFailedListener != null) {
            Log.d(TAG, "onRecorderStarted");
            onRecorderFailedListener.onRecorderStarted();
        }
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        ByteBuffer[] codecInputBuffers = mediaCodec.getInputBuffers();
        ByteBuffer[] codecOutputBuffers = mediaCodec.getOutputBuffers();

        try {
            while (!Thread.interrupted()) {

                boolean success = handleCodecInput(audioRecord, mediaCodec, codecInputBuffers, Thread.currentThread().isAlive());
                if (success)
                    handleCodecOutput(mediaCodec, codecOutputBuffers, bufferInfo, outputStream);
            }
        } catch (IOException e) {
            Log.w(TAG, e);
        } finally {
            mediaCodec.stop();
            audioRecord.stop();

            mediaCodec.release();
            audioRecord.release();

            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    private boolean handleCodecInput(AudioRecord audioRecord,
                                     MediaCodec mediaCodec, ByteBuffer[] codecInputBuffers,
                                     boolean running) throws IOException {
        byte[] audioRecordData = new byte[bufferSize];
        int length = audioRecord.read(audioRecordData, 0, audioRecordData.length);

        if (length == AudioRecord.ERROR_BAD_VALUE ||
                length == AudioRecord.ERROR_INVALID_OPERATION ||
                length != bufferSize) {

            if (length != bufferSize) {
                if (onRecorderFailedListener != null) {
                    Log.d(TAG, "length != BufferSize calling onRecordFailed");
                    onRecorderFailedListener.onRecorderFailed();
                }
                return false;
            }
        }

        int codecInputBufferIndex = mediaCodec.dequeueInputBuffer(10 * 1000);

        if (codecInputBufferIndex >= 0) {
            ByteBuffer codecBuffer = codecInputBuffers[codecInputBufferIndex];
            codecBuffer.clear();
            codecBuffer.put(audioRecordData);
            mediaCodec.queueInputBuffer(codecInputBufferIndex, 0, length, 0, running ? 0 : MediaCodec.BUFFER_FLAG_END_OF_STREAM);
        }

        return true;
    }

    private void handleCodecOutput(MediaCodec mediaCodec,
                                   ByteBuffer[] codecOutputBuffers,
                                   MediaCodec.BufferInfo bufferInfo,
                                   OutputStream outputStream)
            throws IOException {
        int codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);

        while (codecOutputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
            if (codecOutputBufferIndex >= 0) {
                ByteBuffer encoderOutputBuffer = codecOutputBuffers[codecOutputBufferIndex];

                encoderOutputBuffer.position(bufferInfo.offset);
                encoderOutputBuffer.limit(bufferInfo.offset + bufferInfo.size);

                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
                    byte[] header = createAdtsHeader(bufferInfo.size - bufferInfo.offset);


                    outputStream.write(header);

                    byte[] data = new byte[encoderOutputBuffer.remaining()];
                    encoderOutputBuffer.get(data);
                    outputStream.write(data);
                }

                encoderOutputBuffer.clear();

                mediaCodec.releaseOutputBuffer(codecOutputBufferIndex, false);
            } else if (codecOutputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                codecOutputBuffers = mediaCodec.getOutputBuffers();
            }

            codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
        }
    }


    private byte[] createAdtsHeader(int length) {
        int frameLength = length + 7;
        byte[] adtsHeader = new byte[7];

        adtsHeader[0] = (byte) 0xFF; // Sync Word
        adtsHeader[1] = (byte) 0xF1; // MPEG-4, Layer (0), No CRC
        adtsHeader[2] = (byte) ((MediaCodecInfo.CodecProfileLevel.AACObjectLC - 1) << 6);
        adtsHeader[2] |= (((byte) SAMPLE_RATE_INDEX) << 2);
        adtsHeader[2] |= (((byte) CHANNELS) >> 2);
        adtsHeader[3] = (byte) (((CHANNELS & 3) << 6) | ((frameLength >> 11) & 0x03));
        adtsHeader[4] = (byte) ((frameLength >> 3) & 0xFF);
        adtsHeader[5] = (byte) (((frameLength & 0x07) << 5) | 0x1f);
        adtsHeader[6] = (byte) 0xFC;

        return adtsHeader;
    }

    private AudioRecord createAudioRecord(int bufferSize) {
        AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
                AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT, bufferSize * 10);

        if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
            Log.d(TAG, "Unable to initialize AudioRecord");
            throw new RuntimeException("Unable to initialize AudioRecord");
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            if (Android.media.audiofx.NoiseSuppressor.isAvailable()) {
                Android.media.audiofx.NoiseSuppressor noiseSuppressor = Android.media.audiofx.NoiseSuppressor
                        .create(audioRecord.getAudioSessionId());
                if (noiseSuppressor != null) {
                    noiseSuppressor.setEnabled(true);
                }
            }
        }


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            if (Android.media.audiofx.AutomaticGainControl.isAvailable()) {
                Android.media.audiofx.AutomaticGainControl automaticGainControl = Android.media.audiofx.AutomaticGainControl
                        .create(audioRecord.getAudioSessionId());
                if (automaticGainControl != null) {
                    automaticGainControl.setEnabled(true);
                }
            }
        }


        return audioRecord;
    }

    private MediaCodec createMediaCodec(int bufferSize) throws IOException {
        MediaCodec mediaCodec = MediaCodec.createEncoderByType("audio/mp4a-latm");
        MediaFormat mediaFormat = new MediaFormat();

        mediaFormat.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
        mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE);
        mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNELS);
        mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, bufferSize);
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
        mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);

        try {
            mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        } catch (Exception e) {
            Log.w(TAG, e);
            mediaCodec.release();
            throw new IOException(e);
        }

        return mediaCodec;
    }

    interface OnRecorderFailedListener {
        void onRecorderFailed();

        void onRecorderStarted();
    }
}
2
Nilesh Deokar

これをコメントとして追加しますが、まだ十分なStackoverflow repポイントがありません...

Opiatefuchsのリンク は、.wavファイルの作成に必要な正確なヘッダー形式を示すサンプルコードに移動します。私は自分でそのコードを終わらせてきました。非常に役立ちます。

0
UpLate

まず、wavファイルの形式がヘッダーであることを知っておく必要があります。したがって、純粋なデータを.wavファイルに書き込むことはできません。

第2に、wavファイルヘッダーにはファイルの長さが含まれます。そのため、記録後にヘッダーを書き込む必要があります。

私の解決策は、ユーザーAudioRecorderがpcmファイルを記録することです。

    byte[] audiodata = new byte[bufferSizeInBytes];

    FileOutputStream fos = null;
    int readsize = 0;
    try {
        fos = new FileOutputStream(pcmFileName, true);
    } catch (FileNotFoundException e) {
        Log.e("AudioRecorder", e.getMessage());
    }

    status = Status.STATUS_START;
    while (status == Status.STATUS_START && audioRecord != null) {
        readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
        if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) {

            if (readsize > 0 && readsize <= audiodata.length)
                    fos.write(audiodata, 0, readsize);
            } catch (IOException e) {
                Log.e("AudioRecorder", e.getMessage());
            }
        }
    }
    try {
        if (fos != null) {
            fos.close();
        }
    } catch (IOException e) {
        Log.e("AudioRecorder", e.getMessage());
    }

次に、それをwavファイルに変換します。

    byte buffer[] = null;
    int TOTAL_SIZE = 0;
    File file = new File(pcmPath);
    if (!file.exists()) {
        return false;
    }
    TOTAL_SIZE = (int) file.length();

    WaveHeader header = new WaveHeader();

    header.fileLength = TOTAL_SIZE + (44 - 8);
    header.FmtHdrLeth = 16;
    header.BitsPerSample = 16;
    header.Channels = 1;
    header.FormatTag = 0x0001;
    header.SamplesPerSec = 8000;
    header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);
    header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
    header.DataHdrLeth = TOTAL_SIZE;

    byte[] h = null;
    try {
        h = header.getHeader();
    } catch (IOException e1) {
        Log.e("PcmToWav", e1.getMessage());
        return false;
    }

    if (h.length != 44) 
        return false;


    File destfile = new File(destinationPath);
    if (destfile.exists())
        destfile.delete();


    try {
        buffer = new byte[1024 * 4]; // Length of All Files, Total Size
        InputStream inStream = null;
        OutputStream ouStream = null;

        ouStream = new BufferedOutputStream(new FileOutputStream(
                destinationPath));
        ouStream.write(h, 0, h.length);
        inStream = new BufferedInputStream(new FileInputStream(file));
        int size = inStream.read(buffer);
        while (size != -1) {
            ouStream.write(buffer);
            size = inStream.read(buffer);
        }
        inStream.close();
        ouStream.close();
    } catch (FileNotFoundException e) {
        Log.e("PcmToWav", e.getMessage());
        return false;
    } catch (IOException ioe) {
        Log.e("PcmToWav", ioe.getMessage());
        return false;
    }
    if (deletePcmFile) {
        file.delete();
    }
    Log.i("PcmToWav", "makePCMFileToWAVFile  success!" + new SimpleDateFormat("yyyy-MM-dd hh:mm").format(new Date()));
    return true;
0
Joyie