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(); } }
-