느려요

진짜로

IT/Mobile

[Android/JAVA] 음성 녹음하여 wav파일로 저장

느이 2024. 1. 25. 16:06

음성을 녹음해서 파일로 저장해야 할 일이 있어서.. 

 

여기저기서 갈무리 했습니다... 많은 개발자 및 스택오버플로우 형님들께 감사를...

 

public class VoiceRecorder implements Runnable {

    Context _context;

    private final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
    private final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;  //안드로이드 녹음시 채널 상수값
    private final int WAVE_CHANNEL_MONO = 1;  //wav 파일 헤더 생성시 채널 상수값
    private final int HEADER_SIZE = 0x2c;
    private final int RECORDER_BPP = 16;
    private final int RECORDER_SAMPLERATE = 0xac44;
    private final int BUFFER_SIZE;
    private final String TEMP_FILE_NAME = "temp.bak";

    private AudioRecord mAudioRecord;
    private boolean mIsRecording;
    private String mFileName;
    private BufferedInputStream mBIStream;
    private BufferedOutputStream mBOStream;
    private int mAudioLen = 0;

    private OnVoiceRecordFinishedListener voiceRecordFinishedListener;

    public VoiceRecorder(Context context, String fileName) {
        super();
        _context = context;

        mFileName = fileName;
        BUFFER_SIZE = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);
        mIsRecording = false;
    }


    @Override
    public void run() {
         // 권한 체크
        if (ActivityCompat.checkSelfPermission(_context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDER_SAMPLERATE, RECORDER_CHANNELS,
                RECORDER_AUDIO_ENCODING, BUFFER_SIZE);
        mAudioRecord.startRecording();
        mIsRecording = true;
        writeAudioDataToFile();
    }

    private void writeAudioDataToFile() {
        byte[] buffer = new byte[BUFFER_SIZE];
        byte[] data = new byte[BUFFER_SIZE];
        File waveFile = new File(저장하고 싶은 경로+"/"+mFileName);
        File tempFile = new File(저장하고 싶은 경로+"/"+TEMP_FILE_NAME);

        try {
            mBOStream = new BufferedOutputStream(new FileOutputStream(tempFile));
        } catch (FileNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }


        if (null != mBOStream) {
            new Thread(() -> {
                int read = 0;
                try {
                    while (mIsRecording) {
                        read = mAudioRecord.read(data, 0, BUFFER_SIZE);
                        if (AudioRecord.ERROR_INVALID_OPERATION != read) {
                            mBOStream.write(data);
                        }
                    }

                    mAudioRecord.stop();
                    mAudioRecord.release();
                    mAudioRecord = null;

                    mBOStream.flush();
                    mAudioLen = (int)tempFile.length();
                    mBIStream = new BufferedInputStream(new FileInputStream(tempFile));
                    mBOStream.close();
                    mBOStream = new BufferedOutputStream(new FileOutputStream(waveFile));
                    mBOStream.write(getFileHeader());

                    while (mBIStream.read(buffer) != -1) {
                        mBOStream.write(buffer);
                    }
                    mBOStream.flush();
                    mBIStream.close();
                    mBOStream.close();

                    voiceRecordFinishedListener.onVoiceRecordFinishedListener(mFileName);
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }).start();
        }
    }

    private byte[] getFileHeader() {
        byte[] header = new byte[HEADER_SIZE];
        int totalDataLen = mAudioLen + 40;
        long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * WAVE_CHANNEL_MONO/8;
        header[0] = 'R';  // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f';  // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16;  // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = (byte)1;  // format = 1 (PCM방식)
        header[21] = 0;
        header[22] =  WAVE_CHANNEL_MONO;
        header[23] = 0;
        header[24] = (byte) (RECORDER_SAMPLERATE & 0xff);
        header[25] = (byte) ((RECORDER_SAMPLERATE >> 8) & 0xff);
        header[26] = (byte) ((RECORDER_SAMPLERATE >> 16) & 0xff);
        header[27] = (byte) ((RECORDER_SAMPLERATE >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) RECORDER_BPP * WAVE_CHANNEL_MONO/8;  // block align
        header[33] = 0;
        header[34] = RECORDER_BPP;  // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte)(mAudioLen & 0xff);
        header[41] = (byte)((mAudioLen >> 8) & 0xff);
        header[42] = (byte)((mAudioLen >> 16) & 0xff);
        header[43] = (byte)((mAudioLen >> 24) & 0xff);
        return header;
    }

    public void stopRecording() {
        if (null != mAudioRecord) {
            mIsRecording = false;
        }
    }

    public interface OnVoiceRecordFinishedListener {
        void onVoiceRecordFinishedListener(String fileName);
    }

    // OnItemClickListener 전달 메소드
    public void setOnVoiceRecordFinishedListener (OnVoiceRecordFinishedListener listener) {
        voiceRecordFinishedListener = listener;
    }
}

 

startRecording을 호출하면 녹음이 시작되고

stopRecording을 호출하면 녹음이 종료됨!

 

setOnVoiceRecordFinishedListener를 미리 설정해두면 녹음이 끝난 후에 이벤트를 캐치할 수 있음!

반응형