安卓SDK提供了两种音频采集的api,MediaRecorder和AudioRecord,相较于前者,后者更接近底层,能够更加灵活的控制。我们学习音视频开发,都是直接对原始的pcm音频进处理包括降噪、增益等。
所需权限
权限的申请自行解决。
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
AudioRecord参数
-
audioSource:音频输入源,通常为MediaRecorder.AudioSource.MIC(麦克风),此外还有VOICE_CALL、CAMCORDER等等,这里不一一赘述。
-
sampleRateInHz:采样率,目前44100Hz可以保证兼容所有的手机。
-
channelConfig:通道数,同上为了兼容性一般为AudioFormat.CHANNEL_IN_MONO(单通道)。
-
audioFormat:数据位宽,常用16bit可以兼容所有android手机。
-
bufferSizeInBytes:缓冲区大小,这个根据 采样率x位宽x采样时间x通道数 计算得来。
// 音频输入-麦克风
private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC;
//8K采集率
private final static int AUDIO_SAMPLE_RATE = 8000;
//格式
private final static int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
//16Bit
private final static int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
// 缓冲区字节大小
private int bufferSizeInBytes = 1600;
音频录制流程
1.初始化AudioRecord对象,注意其最小录音缓存buffer,可以使用getMinBufferSize得到。
public void init(Context context) {
//检查权限
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
audioRecord = new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE,
CHANNEL_CONFIG, AUDIO_FORMAT, bufferSizeInBytes);
LogUtils.i("初始化成功");
}
2.初始化一个buffer(用于保存新的录音数据),其大小等于第一步中的缓存buffer大小。
byte[] audiodata = new byte[bufferSizeInBytes];
3.开始录音,通常另起线程,创建数据流,同时设置正在录音标志flag来控制停止录音。
4.开始采集,一边从AudioRecord读取声音数据,一边将buffer写入数据流。
5.停止录音,将录音标志置为false,关闭数据流。
public void start() {
if (isRecord) {
LogUtils.i("正在录音");
return;
}
LogUtils.i("开始录音");
isRecord = true;
audioRecord.startRecording();
audioHandle = new Thread(() -> saveFile());
audioHandle.start();
}
private void saveFile() {
byte[] audiodata = new byte[bufferSizeInBytes];
FileOutputStream fos = null;
try {
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
fos = new FileOutputStream(file);
} catch (Exception e) {
e.printStackTrace();
}
while (isRecord) {
int readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
if (fos != null) {
try {
fos.write(audiodata);
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
if (fos != null) {
fos.close();// 关闭写入流
}
} catch (IOException e) {
}
}
public void stop() {
isRecord = false;
LogUtils.i("停止录音");
}
6.释放资源。
public void release() {
if (audioRecord != null) {
isRecord = false;
audioRecord.release();
audioRecord = null;
audioHandle.interrupt();
audioHandle = null;
LogUtils.i("释放");
}
}
结语
录制是否成功,可以去对应的文件目录下查看是否有相应的pcm文件,下节讲述pcm文件的播放。
本期博客参考:
需要源码的盆友也可以访问我的gitlub,我的gitlub源码