Android 錄製以及播放wav

不好找,我總結了一下代碼如下

錄製類:

開始

AudioRecordManager.getInstance().startRecord(wavFilePath , pcmFilePath);

停止

AudioRecordManager.getInstance().stopRecord();
package cn.amao.cleanhome.mvp.ui.activity;

import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Environment;
import android.support.annotation.RequiresApi;
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * @author vveng
 * @version version 1.0.0
 * @date 2018/7/24 16:03.
 * @email [email protected]
 * @instructions 說明
 * @descirbe 描述
 * @features 功能
 */
public class AudioRecordManager {

    private static AudioRecordManager mInstance;
    private AudioRecord recorder;
    //錄音源
    private static int audioSource = MediaRecorder.AudioSource.MIC;
    //錄音的採樣頻率
    private static int audioRate = 44100;
    //錄音的聲道,單聲道
    private static int audioChannel = AudioFormat.CHANNEL_IN_MONO;
    //量化的深度
    private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    //緩存的大小
    private static int bufferSize = AudioRecord.getMinBufferSize(audioRate,audioChannel,audioFormat);
    //記錄播放狀態
    private boolean isRecording = false;
    //數字信號數組
    private byte [] noteArray;
    //PCM文件
    private File pcmFile;
    //WAV文件
    private File wavFile;
    //文件輸出流
    private OutputStream os;

    private AudioRecordManager(){
        recorder = new AudioRecord(audioSource,audioRate,audioChannel,audioFormat,bufferSize);
    }

    public synchronized static AudioRecordManager getInstance(){
        if(mInstance == null){
            mInstance = new AudioRecordManager();
        }
        return mInstance;
    }

    //讀取錄音數字數據線程
    class WriteThread implements Runnable{
        public void run(){
            writeData();
        }
    }

    //開始錄音
    public void startRecord(String wavFilePath , String pcmFilePath){
        if(isRecording){
            return;
        }
        isRecording = true;
        cheackFile(wavFilePath , pcmFilePath);
        recorder.startRecording();
        recordData();
    }

    //停止錄音
    public void stopRecord(){
        isRecording = false;
        recorder.stop();
        convertWaveFile();
    }

    //將數據寫入文件夾,文件的寫入沒有做優化
    public void writeData(){
        noteArray = new byte[bufferSize];
        //建立文件輸出流
        try {
            os = new BufferedOutputStream(new FileOutputStream(pcmFile));
        }catch (IOException e){

        }
        while(isRecording == true){
            int recordSize = recorder.read(noteArray,0,bufferSize);
            if(recordSize>0){
                try{
                    os.write(noteArray);
                }catch(IOException e){

                }
            }
        }
        if (os != null) {
            try {
                os.close();
            }catch (IOException e){

            }
        }
    }

    // 這裏得到可播放的音頻文件
    public void convertWaveFile() {
        FileInputStream in = null;
        FileOutputStream out = null;
        long totalAudioLen = 0;
        long totalDataLen = totalAudioLen + 36;
        long longSampleRate = AudioRecordManager.audioRate;
        int channels = 1;
        long byteRate = 16 *AudioRecordManager.audioRate * channels / 8;
        byte[] data = new byte[bufferSize];
        try {
            in = new FileInputStream(pcmFile);
            out = new FileOutputStream(wavFile);
            totalAudioLen = in.getChannel().size();
            //由於不包括RIFF和WAV
            totalDataLen = totalAudioLen + 36;
            WriteWaveFileHeader(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate);
            while (in.read(data) != -1) {
                out.write(data);
            }
            in.close();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
    任何一種文件在頭部添加相應的頭文件才能夠確定的表示這種文件的格式,wave是RIFF文件結構,每一部分爲一個chunk,其中有RIFF WAVE chunk,
    FMT Chunk,Fact chunk,Data chunk,其中Fact chunk是可以選擇的,
     */
    private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen, long totalDataLen, long longSampleRate,
                                     int channels, long byteRate) throws IOException {
        byte[] header = new byte[44];
        header[0] = 'R'; // RIFF
        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';//WAVE
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        //FMT Chunk
        header[12] = 'f'; // 'fmt '
        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;
        //編碼方式 10H爲PCM編碼格式
        header[20] = 1; // format = 1
        header[21] = 0;
        //通道數
        header[22] = (byte) channels;
        header[23] = 0;
        //採樣率,每個通道的播放速度
        header[24] = (byte) (longSampleRate & 0xff);
        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
        //音頻數據傳送速率,採樣率*通道數*採樣深度/8
        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) (1 * 16 / 8);
        header[33] = 0;
        //每個樣本的數據位數
        header[34] = 16;
        header[35] = 0;
        //Data chunk
        header[36] = 'd';//data
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
        out.write(header, 0, 44);
    }

    //創建文件夾,首先創建目錄,然後創建對應的文件
    public void cheackFile(String wavFilePath , String pcmFilePath){
        pcmFile = new File(pcmFilePath);
        wavFile = new File(wavFilePath);
        if(pcmFile.exists()){
            pcmFile.delete();
        }
        if(wavFile.exists()){
            wavFile.delete();
        }
        try{
            pcmFile.createNewFile();
            wavFile.createNewFile();
        }catch(IOException e){

        }
    }

    //記錄數據
    public void recordData(){
        new Thread(new WriteThread()).start();
    }
}

播放

private void playWav(String path) {
        MediaPlayer mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource(path);
            mediaPlayer.prepare();
            mediaPlayer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章