问题:在使用Android的AudioRecord进行录音时,录制生成的录音文件的时长比实际录制时间长,且录制的音频有一部分是有杂音或者没有声音的。
安卓出现录音问题还可以参考另一篇文章 Android 录音功能无法正常使用
最近被安排去在写安卓的项目了,出现上述的问题,看了好久的代码都没发现原因,最后就改了两行代码就好了,希望大家不要再掉这个坑里了。。。
本文先说录音的简单流程,然后是导致出现问题的代码,最后给出解决办法。
1、录音的简单流程:
开始录音函数:首先判断录音的状态,如果为准备录音则开始录音,开始录音后创建了一个新的线程,设置录音的状态为正在录音,将录音数据写入pcm文件中。写文件操作通过一个while循环判断,如果当前状态为正在录音状态,则数据写入文件。
停止录音函数:停止录音后,改变录音的状态,释放资源。
原始代码:
/**
* 开始录音
*/
public void startRecordAudio() {
if (status == Status.STATUS_NO_READY || TextUtils.isEmpty(fileName)) {
throw new IllegalStateException("录音尚未初始化,请检查是否禁止了录音权限~");
}
if (status == Status.STATUS_START) {
throw new IllegalStateException("正在录音");
}
Log.d("AudioRecorder", "===startRecord===" + audioRecord.getState());
audioRecord.startRecording();
new Thread(new Runnable() {
@Override
public void run() {
writeDataTOFile();
}
}).start();
}
/**
* 停止录音
*/
public void stopRecordAudio() {
Log.d("AudioRecorder", "===stopRecord===");
if (status == Status.STATUS_NO_READY || status == Status.STATUS_READY) {
throw new IllegalStateException("录音尚未开始");
} else {
audioRecord.stop();
status = Status.STATUS_STOP;
Log.d("AudioRecorder","release()");
release();
}
}
/**
* 将音频信息写入文件
* @param listener 音频流的监听
*/
private void writeDataTOFile() {
// new一个byte数组用来存一些字节数据,大小为缓冲区大小
byte[] audiodata = new byte[bufferSizeInBytes];
FileOutputStream fos = null;
int readsize = 0;
try {
File file = new File(FileUtil.getPcmFileAbsolutePath(fileName)); // 创建文件/storage/emulated/0/pauseRecordDemo/pcm/2020-10-20-10:18:14.pcm
Log.d("TAG","文件名为 == "+file);
if (file.exists()) {
Log.d("TAG","文件已存在!");
file.delete();
}
else {
Log.d("TAG","该文件不存在,尝试创建该文件!");
file.createNewFile();//多级目录
if(file.exists())
Log.d("TAG","文件创建成功! " + file);
}
fos = new FileOutputStream(file);// 建立一个可存取字节的文件
} catch (IllegalStateException e) {
Log.e("AudioRecorder", e.getMessage());
throw new IllegalStateException(e.getMessage());
} catch (FileNotFoundException e) {
Log.e("AudioRecorder", e.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
//将录音状态设置成正在录音状态
status = Status.STATUS_START;
while (status == Status.STATUS_START) {
readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) {
try {
fos.write(audiodata);
if(fos==null) {
Log.d("TAG","写入文件失败");
}
} catch (IOException e) {
Log.e("AudioRecorder", e.getMessage());
}
}
}
try {
if (fos != null) {
fos.close();// 关闭写入流
}
} catch (IOException e) {
Log.e("AudioRecorder", e.getMessage());
}
}
/**
* 释放资源
*/
public void release() {
isRelease=false;
Log.d("AudioRecorder", "===release===");
pcmFilePath=FileUtil.getPcmFileAbsolutePath(fileName); //获取pcm文件路径
//将pcm文件转化为wav文件
mergePCMFilesToWAVFile(pcmFilePath);
if (audioRecord != null) {
audioRecord.release();
audioRecord = null;
}
status = Status.STATUS_NO_READY;
isRelease=true;
}
2、问题分析
上面的代码看起来是没有问题的,在录制时间较短的时候,甚至可能看不出出现问题了。
文件是有音频的,表示录音实际已经是在录了,但是出现文件时长、有杂音问题,首先定位应该是写文件的时候出现了错误。一开始认为是不是缓冲区的大小设置不对,通过打印日志发现这里没有问题。找了很久的原因,发现写文件是在一个新的线程中进行的,但是在写之前需要先判断当前的录音状态,如果当前状态为正在录音状态,才将数据写入文件。而在停止录音函数时,关键的两行代码,是先停止了录音,然后改变录音的状态。
这里录音已经停止了,但是状态还没有来得及改变,导致将音频写入文件的线程中的while循环还在进行。简单来说,就是已经没有音频输入了,但是还在写文件。由此导致了音频文件的时长较实际时间长,而且有杂音。
3、问题解决
解决办法:先改变录音状态,再停止录音,只需要更换停止录音函数里面两行代码的位置。
正确代码:
/**
* 停止录音
*/
public void stopRecordAudio() {
Log.d("AudioRecorder", "===stopRecord===");
if (status == Status.STATUS_NO_READY || status == Status.STATUS_READY) {
throw new IllegalStateException("录音尚未开始");
} else {
status = Status.STATUS_STOP; //改变当前录音状态
audioRecord.stop(); //停止录音
Log.d("AudioRecorder","release()");
release(); //释放资源
}
}
--------如有侵权,联系删除!