Android录音MediaRecorder使用和PCM转成wav

时间:2024-03-29 07:28:15

1 MediaRecorder介绍

https://developer.android.google.cn/reference/android/media/MediaRecorder

MediaRecorder可用于录制音频和视频,本篇只讲解MediaRecorder录音功能,录音控制是基于一个简单的状态机:
Android录音MediaRecorder使用和PCM转成wav

MediaRecorder要严格遵守各个状态之间的变化,否则会出错。
Initial:初始状态,创建一个新的MediaRecorder对象或者调用了reset()方法时,MediaRecorder对象处于Initial状态。通过调用reset()方法都可以使MediaRecorder进入Initial状态。在设定视频源或者音频源之后将转换为Initialized状态。

Initialized:已初始化状态,在Initial状态下调用setAudioSource()
或setVideoSource()方法会转变成Initialized状态。这个状态可以通过setOutputFormat()方法设置输出格式,此时MediaRecorder转换为DataSourceConfigured状态。

DataSourceConfigured:数据源配置状态,这个状态下可以设定编码方式、输出文件、屏幕旋转、预览显示等等。可以在Initialized状态通过setOutputFormat()方法进入该状态。这个状态下可以通过reset()方法回到Initial状态,或者通过prepare()方法到达Prepared状态。

Prepared:就绪状态,在DataSourceConfigured状态通过prepare()方法进入该状态。在这个状态可以通过start()进入录制状态。
Recording:录制状态,可以在Prepared状态通过调用start()方法进入该状态。它可以通过stop()方法或reset()方法回到Initial状态。

Released:释放状态也叫作Idle state空闲状态,可以通过在Initial状态调用release()方法来进入这个状态,这时将会释放所有和MediaRecorder对象绑定的资源。

Error:错误状态,当错误发生的时候进入这个状态,可以通过调用reset()方法进入Initial状态。

2 利用MediaRecorder录制音频的模板

android Developer 使用模板

MediaRecorder recorder = new MediaRecorder();
 recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
 recorder.setOutputFile(PATH_NAME);
 recorder.prepare();
 recorder.start();   // Recording is now started
 ...
 recorder.stop();
 recorder.reset();   // You can reuse the object by going back to setAudioSource() step
 recorder.release(); // Now the object cannot be reused

MediaRecorder构造函数:
MediaRecorder(),只有一个默认的无参构造函数。

** setAudioSource(int audio_source)**
设置声音来源,一般传入 MediaRecorder. AudioSource.MIC参数指定录制来自麦克风的声音,在AudioRecord中已经讲解。

void setOutputFormat(int output_format)
设置所录制的音视频文件的格式。
源码说明:

public final class OutputFormat {
  /* Do not change these values without updating their counterparts
   * in include/media/mediarecorder.h!
   */
    private OutputFormat() {}
    public static final int DEFAULT = 0;
    /** 3GPP media file format*/
    public static final int THREE_GPP = 1;
    /** MPEG4 media file format*/
    public static final int MPEG_4 = 2;

    /** The following formats are audio only .aac or .amr formats */

    /**
     * AMR NB file format
     * @deprecated  Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB
     */
    public static final int RAW_AMR = 3;

    /** AMR NB file format */
    public static final int AMR_NB = 3;

    /** AMR WB file format */
    public static final int AMR_WB = 4;

    /** @hide AAC ADIF file format */
    public static final int AAC_ADIF = 5;

    /** AAC ADTS file format */
    public static final int AAC_ADTS = 6;

    /** @hide Stream over a socket, limited to a single stream */
    public static final int OUTPUT_FORMAT_RTP_AVP = 7;

    /** H.264/AAC data encapsulated in MPEG2/TS */
    public static final int MPEG_2_TS = 8;

    /** VP8/VORBIS data in a WEBM container */
    public static final int WEBM = 9;
};

对于音频:THREE_GPP对应3gp,MPEG_4对应mp4,m4a,
RAW_AMR,AMR_NB,AMR_WB对应arm,AAC_ADIF,AAC_ADTS对应aac格式。

void setAudioChannels(int numChannels)
设置录制的音频通道数。

void setAudioEncoder(int audio_encoder)
设置所录制的声音的编码格式。

包括:
AAC(AAC低复杂度(AAC-LC)音频编解码器)
AAC_ELD(增强型低延迟AAC(AAC-ELD)音频编解码器)
AMR_NB(AMR(窄带)音频编解码器)
AMR_WB(AMR(宽带)音频编解码器)
DEFAULT
HE_AAC(高效率AAC(HE-AAC)音频编解码器)
VORBIS(Ogg Vorbis音频编解码器

void setAudioEncodingBitRate(int bitRate)
设置所录制的声音的编码位率,音频一秒钟包含多少数据位。

void setAudioSamplingRate(int samplingRate)
设置所录制的声音的采样率,例如44100。

void setMaxDuration(int max_duration_ms)
设置录制会话的最长持续时间(以ms为单位)。

void setMaxFileSize(long max_filesize_bytes)
设置录制文件的最大文件大小。

void setOnErrorListener(MediaRecorder.OnErrorListener l)
注册一个用于记录录制时出现的错误的监听器。

void setOutputFile(FileDescriptor fd)
设置录制的音频文件的保存位置。
void setOutputFile(String path)
设置录制的音频文件的保存位置。

final static int getAudioSourceMax()
获取音频源的最大值。

int getMaxAmplitude()
获取在前一次调用此方法之后录音中出现的最大振幅,主要用于设置录音时的一些波形动画。

void prepare()
准备录制。

void release()
释放资源。

void reset()
将MediaRecorder设为空闲状态,即Initial状态。

void start()
开始录制。

void stop()
停止录制。

3 简单使用

public void  startRecord2(){
    try {
        //创建MediaRecorder
        mMediaRecorder = new MediaRecorder();
        //创建录音文件
        File mRecorderFile = new File(voicePath+armvoiceName);
        if (!mRecorderFile.getParentFile().exists()) mRecorderFile.getParentFile().mkdirs();
        mRecorderFile.createNewFile();
        //从麦克风采集
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        //最终的保存文件为arm格式
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
        //所有android系统都支持的适中采样的频率
        mMediaRecorder.setAudioSamplingRate(44100);
        //通用的ARM编码格式
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        //设置音质频率
        mMediaRecorder.setAudioEncodingBitRate(1024*1024);
        //设置文件录音的位置
        mMediaRecorder.setOutputFile(mRecorderFile.getAbsolutePath());
        //开始录音
        mMediaRecorder.prepare();
        mMediaRecorder.start();

    } catch (Exception e) {

    }

}

public void stopMediarecorder(){
    if (mMediaRecorder != null){
        mMediaRecorder.stop();
        mMediaRecorder.release();
        mMediaRecorder = null;
    }
}

Android录音MediaRecorder使用和PCM转成wav

4 如何把PCM转化为WAV

来自:https://www.cnblogs.com/tyjsjl/p/3695122.html感谢作者
只需要在PCM格式文件的头部添加WAV格式的声明:
// 这里得到可播放的音频文件

 private void swapPCMToWaveFile(String inFilename, String outFilename) {  
        FileInputStream in = null;  
        FileOutputStream out = null;  
        long totalAudioLen = 0;  
        long totalDataLen = totalAudioLen + 36;  
        long longSampleRate = AudioFileFunc.AUDIO_SAMPLE_RATE;  
        int channels = 2;  
        long byteRate = 16 * AudioFileFunc.AUDIO_SAMPLE_RATE * channels / 8;  
        byte[] data = new byte[bufferSizeInBytes];  
        try {  
            in = new FileInputStream(inFilename);  
            out = new FileOutputStream(outFilename);  
            totalAudioLen = in.getChannel().size();  
            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();  
        }  
    }  
   
   //添加头部信息
    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/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] = 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);  
        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) (2 * 16 / 8); // block align  
        header[33] = 0;  
        header[34] = 16; // bits per sample  
        header[35] = 0;  
        header[36] = 'd';  
        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);  
    }  
}

至于如何把PCM转变成aac,arm就要用到MediaCodec了后面会讲。