android平台上录制音频主要有两种方式,MediaRecorder、AudioRecord。java
音频开发应用场景不少,仅仅录制保存知足不了大部分实际需求,因此,掌握 AudioRecord 的使用是必须的,本文针对AudioRecord的使用进行总结。android
AudioRecord 的使用主要有如下几个步骤:算法
初始化AudioRecord数组
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes) 复制代码
int size = 采样率 x 位宽 x 采样时间 x 通道数
)与音频采样时间有关,通常取 2.5ms~120ms 之间,不一样厂商取值不一样,因此AudioRecord类提供了 int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)
函数来获取改值,实际开发中,强烈建议由该函数计算出须要传入的 bufferSizeInBytes,而不是本身手动计算。虽然不一样的厂商的底层实现是不同的,但无外乎就是根据上面的计算公式获得一帧的大小,音频缓冲区的大小则必须是一帧大小的2~N倍。初始化音频数据bufferide
经过前面获取的 bufferSizeInBytes ,初始化读取音频数据的buffer。函数
final byte[] data = new byte[minBufferSize];
复制代码
开启采集编码
调用 AudioRecord 实例的 startRecording()
方法,开始采集音频spa
特别注意:开始采集后,要尽快经过音频读取数据取走音频,一旦缓冲区中的数据大于前面设置的
bufferSizeInBytes
,会发生over-running
线程
启动新线程,从音频数据buffer中读取音频数据code
开启新线程,调用 AudioRecord 实例的 public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes)
方法,获取音频数据。
中止采集、释放资源
调用 AudioRecord 实例的 stop()
、release()
方法,将改实例置为 null。
示例代码
别忘了配录音权限
public class MainActivity extends AppCompatActivity {
//采样率,如今可以保证在全部设备上使用的采样率是44100Hz, 可是其余的采样率(22050, 16000, 11025)在一些设备上也可使用。
public static final int SAMPLE_RATE_INHZ = 44100;
//声道数。CHANNEL_IN_MONO and CHANNEL_IN_STEREO. 其中CHANNEL_IN_MONO是能够保证在全部设备可以使用的。
public static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
//返回的音频数据的格式。 ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, and ENCODING_PCM_FLOAT.
public static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
Button btnBegin;
Button btnEnd;
private AudioRecord audioRecord;
private boolean isRecording;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnBegin = (Button) findViewById(R.id.btnBegin);
btnEnd = (Button) findViewById(R.id.btnEnd);
btnBegin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
beginRecord();
}
});
btnEnd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
endRecorde();
}
});
}
private void beginRecord() {
final int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE_INHZ, CHANNEL_CONFIG, AUDIO_FORMAT);
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE_INHZ, CHANNEL_CONFIG, AUDIO_FORMAT, minBufferSize);
final byte[] data = new byte[minBufferSize];
audioRecord.startRecording();
isRecording = true;
new Thread(new Runnable() {
@Override
public void run() {
while (isRecording) {
int read = audioRecord.read(data, 0, minBufferSize);
if (read != AudioRecord.ERROR_INVALID_OPERATION) {
//处理音频数据 data
}
}
}
}).start();
}
private void endRecorde() {
isRecording = false;
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
}
}
复制代码
封装
参考网上相关资源,这里给出一个简单的AudioRecord录音的封装类:AudioRecorder。
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;
/** * Created by wangyt on 2018/10/26 */
public class AudioRecorder {
private static final String TAG = "AudioRecorder";
public interface OnAudioDataArrivedListener {
void onAudioDataArrived(byte[] audioData);
}
//声源
private static final int DEFFAULT_AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;
//采样率,如今可以保证在全部设备上使用的采样率是44100Hz, 可是其余的采样率(22050, 16000, 11025)在一些设备上也可使用。
private static final int DEFAULT_SAMPLE_RATE_INHZ = 44100;
//声道数。CHANNEL_IN_MONO and CHANNEL_IN_STEREO. 其中CHANNEL_IN_MONO是能够保证在全部设备可以使用的。
private static final int DEFAULT_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
//返回的音频数据的格式。 ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, and ENCODING_PCM_FLOAT.
private static final int DEFAULT_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
//内部缓冲区大小
private int minBufferSize = 0;
//是否已启动录音
private boolean isStarted = false;
//是否能够从缓冲区中读取数据
private boolean canReadDataFromBuffer = true;
//从缓冲区中读取数据的回调方法
private OnAudioDataArrivedListener onAudioDataArrivedListener;
private AudioRecord audioRecord;
public boolean startRecord() {
return startRecord(DEFFAULT_AUDIO_SOURCE,
DEFAULT_SAMPLE_RATE_INHZ,
DEFAULT_CHANNEL_CONFIG,
DEFAULT_AUDIO_FORMAT);
}
public boolean startRecord(int audioSource, int sampleRate, int channel, int audioFormat) {
if (isStarted) {
Log.e(TAG, "startRecord: AudioRecorder has been already started");
return false;
}
//获取内部缓冲区最小size
minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channel, audioFormat);
if (minBufferSize == AudioRecord.ERROR_BAD_VALUE) {
Log.e(TAG, "startRecord: minBufferSize is error_bad_value");
return false;
}
Log.d(TAG, "startRecord: minBufferSize = " + minBufferSize + "bytes");
//初始化 audioRecord
audioRecord = new AudioRecord(audioSource, sampleRate, channel, audioFormat, minBufferSize);
if (audioRecord.getState() == AudioRecord.STATE_UNINITIALIZED) {
Log.e(TAG, "startRecord: audioRecord is uninitialized");
return false;
}
//启动录制
audioRecord.startRecording();
//能够从内部缓冲区中读取数据
canReadDataFromBuffer = true;
//启动子线程
new Thread(new Runnable() {
@Override
public void run() {
while (canReadDataFromBuffer){
//初始化缓冲区数据接收数组
byte[] data = new byte[minBufferSize];
//读取内部缓冲区中读取数据
int result = audioRecord.read(data, 0, minBufferSize);
if (result == AudioRecord.ERROR_BAD_VALUE){
Log.e(TAG, "run: audioRecord.read result is ERROR_BAD_VALUE");
}else if (result == AudioRecord.ERROR_INVALID_OPERATION){
Log.e(TAG, "run: audioRecord.read result is ERROR_INVALID_OPERATION");
}else {
if (onAudioDataArrivedListener != null){
//调用读取数据回调方法
onAudioDataArrivedListener.onAudioDataArrived(data);
}
Log.d(TAG, "run: audioRecord read " + result + "bytes");
}
}
}
}).start();
//设置录音已启动
isStarted = true;
Log.d(TAG, "startRecord: audioRecorder has been already started");
return true;
}
public void stopRecord(){
//若是录音还没有启动,直接返回
if (!isStarted) return;
//设置内部缓冲区数据不可读取
canReadDataFromBuffer = false;
//中止录音
if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING){
audioRecord.stop();
}
//释放资源
audioRecord.release();
//设置录音未启动
isStarted = false;
//回调置为空
onAudioDataArrivedListener = null;
}
}
复制代码