AudioRecord 录制播放PCM音频

AudioRecord 与 MediaRecorder 区别 AudioRecord 基于字节流录制,输出的是pcm数据,未进行压缩,直接保存的pcm文件不能被播放器识别播放。 可以对音频文件进行实时处理,直播类中对录制的声音进行变声编辑。 MediaRecorder 是基于AudioRecord之上,进行了封装,使用简单,由于本身对录制的音频进行压缩,编码,无法对音频进行实时处理编辑。适用于普通的音频录制。 配合MediaPlayer 进行播放。
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes)
AudioRecord 构造函数 AudioSource  音频源, 常用MediaRecorder.AudioSource.MIC(麦克风音频源) SampleRateInHz  采样率,(采样率用赫兹表示。44100Hz是目前唯一的*保证适用于所有设备的费率) ChannelConfig  音频声道 AudioFormat  返回音频数据格式 BufferSizeInBytes 缓冲区大小 录制流程:
  • 构造AudioRecord 对象
  • startRecording() 开始采集
  • 在线程中将采集数据写入pcm文件
  • stop() 停止采集
    public void record(){
        mAudioRecord.startRecording();
    new Thread(new Runnable() {
        @Override
        public void run() {
                FileOutputStream fileOutputStream=new FileOutputStream(recordFile);
                byte[] buffer=new byte[mBufferSizeInBytes];
                while(isRecording){
                    int read=mAudioRecord.read(buffer,0,mBufferSizeInBytes);
                    if(AudioRecord.ERROR_INVALID_OPERATION!=read){
                        fileOutputStream.write(buffer);
                    }
                }
                fileOutputStream.close();
            }
        }).start();
    
    }
    public void stopRecord(){
        isRecording=false;
        if(mAudioRecord.getState()==AudioRecord.RECORDSTATE_RECORDING){
            mAudioRecord.stop();
         }
         mAudioRecord.release();
    }
    使用AudioTrack播放
    • 构造AudioTrack
    • play() 
    • 在线程中write() 写入pcm文件流
    • release()回收资源
    与MediaPlayer的区别 MediaPlayer可以播放多种格式的声音文件,例如MP3,AAC,WAV,OGG,MIDI等。MediaPlayer会在framework层创建对应的音频解码器。而AudioTrack只能播放已经解码的PCM流,如果对比支持的文件格式的话则是AudioTrack只支持wav格式的音频文件,因为wav格式的音频文件大部分都是PCM流。AudioTrack不创建解码器,只能播放不需要解码的wav文件 构造函数
    public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
    int mode, int sessionId)
    mAudioTrack.play();
    new Thread(new Runnable(){
        @Override
        public void run() {
            
    try {
    FileInputStream fileInputStream=new FileInputStream(filePath);
    byte[] tempBuffer=new byte[mWriteMinBufferSize];
    while (fileInputStream.available()>0){
    int readCount= fileInputStream.read(tempBuffer);
    if (readCount== AudioTrack.ERROR_INVALID_OPERATION||readCount==AudioTrack.ERROR_BAD_VALUE){
    continue;
    }
    if (readCount!=0&&readCount!=-1){
    mAudioTrack.write(tempBuffer,0,readCount);
    }
    }
    Log.e("TAG","end");
    } catch (Exception e) {
    e.printStackTrace();
    }
    
        }
    }).start();

    实例:使用AudioRecord 采集PCM,AudioTrack 播放

    package com.rexkell.mediaapplication;
    
    import android.media.AudioAttributes;
    import android.media.AudioFormat;
    import android.media.AudioManager;
    import android.media.AudioRecord;
    import android.media.AudioTrack;
    import android.media.MediaRecorder;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    import com.rexkell.mediaapplication.media.MediaConfig;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.concurrent.Executors;
    
    /**
    * author: rexkell
    * date: 2019/7/22
    * explain:
    */
    public class AudioRecordActivity extends AppCompatActivity {
        boolean isRecording=false;
        //音频源 MIC指的是麦克风
        private final int mAudioSource= MediaRecorder.AudioSource.MIC;
        //(MediaRecoder 的采样率通常是8000Hz AAC的通常是44100Hz。 设置采样率为44100,目前为常用的采样率,官方文档表示这个值可以兼容所有的设置)
        private final int SampleRateInHz=44100; //采样率
        //输入声道
        private final int channelInMono= AudioFormat.CHANNEL_CONFIGURATION_MONO;
        private final int channelOutMono=AudioFormat.CHANNEL_OUT_MONO;
        //指定音频量化位数 ,在AudioFormaat类中指定了以下各种可能的常量。通常我们选择ENCODING_PCM_16BIT和ENCODING_PCM_8BIT PCM代表的是脉冲编码调制,它实际上是原始音频样本。
        //因此可以设置每个样本的分辨率为16位或者8位,16位将占用更多的空间和处理能力,表示的音频也更加接近真实
        private final int mAudioFormat=AudioFormat.ENCODING_PCM_16BIT;
        //指定缓冲区大小
        private int mBufferSizeInBytes;
        private String filePath;
    
        private int mWriteMinBufferSize;
        private AudioAttributes mAudioAttributes;
        AudioRecord mAudioRecord;
        AudioTrack mAudioTrack;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.ac_audio_record);
            filePath=getExternalFilesDir("Music").getPath()+"/test.pcm";
            initAudioRecord();
        }
        private void initAudioRecord(){
          mBufferSizeInBytes=AudioRecord.getMinBufferSize(SampleRateInHz,channelInMono,mAudioFormat);
          mWriteMinBufferSize=AudioTrack.getMinBufferSize(SampleRateInHz,channelInMono,mAudioFormat);
          mAudioRecord=new AudioRecord(mAudioSource,SampleRateInHz,channelInMono,mAudioFormat,mBufferSizeInBytes);
    
          AudioFormat audioFormat=new AudioFormat.Builder().setSampleRate(SampleRateInHz).setEncoding(mAudioFormat).setChannelMask(channelOutMono).build();
          mAudioAttributes=new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();
          mAudioTrack=new AudioTrack(mAudioAttributes,audioFormat,mWriteMinBufferSize, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE);
          File recordFile=new File(filePath);
         if (!recordFile.exists()){
             try {
                 recordFile.createNewFile();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
    
        }
        public void record(View view){
            isRecording=!isRecording;
            String text=isRecording?"结束":"录制";
            ((Button)view).setText(text);
            if (isRecording){
                final File recordFile=new File(filePath);
                if (recordFile.exists()){
                    recordFile.delete();
                    try {
                        recordFile.createNewFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                mAudioRecord.startRecording();
                Executors.newSingleThreadExecutor().execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            FileOutputStream fileOutputStream=new FileOutputStream(recordFile);
                            byte[] buffer=new byte[mBufferSizeInBytes];
                            while (isRecording){
                                int read=mAudioRecord.read(buffer,0,mBufferSizeInBytes);
                                if (AudioRecord.ERROR_INVALID_OPERATION!=read){
                                    fileOutputStream.write(buffer);
                                }
                            }
                            fileOutputStream.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
            }else {
                if (mAudioRecord!=null&&isRecording){
                    if (mAudioRecord.getState()==AudioRecord.RECORDSTATE_RECORDING){
                        mAudioRecord.stop();
                    }
                    mAudioRecord.release();
                    isRecording=false;
                }
    
            }
    
        }
        public void play(View view){
            mAudioTrack.play();
            Executors.newSingleThreadExecutor().execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        FileInputStream fileInputStream=new FileInputStream(filePath);
                        byte[] tempBuffer=new byte[mWriteMinBufferSize];
                        while (fileInputStream.available()>0){
                           int readCount= fileInputStream.read(tempBuffer);
                           if (readCount== AudioTrack.ERROR_INVALID_OPERATION||readCount==AudioTrack.ERROR_BAD_VALUE){
                               continue;
                           }
                           if (readCount!=0&&readCount!=-1){
                               mAudioTrack.write(tempBuffer,0,readCount);
                           }
                        }
                        Log.e("TAG","end");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    
        @Override
        protected void onDestroy() {
           if (mAudioRecord!=null){
               mAudioRecord.release();
               mAudioRecord=null;
           }
           if (mAudioTrack!=null){
               mAudioTrack.release();
               mAudioTrack=null;
           }
           super.onDestroy();
        }
    }

     

上一篇:简单实用的PCM音频播放器--沉寂几年之后回归的第一份笔记


下一篇:图灵机器人