在他基础上新增了下列功能:
- 增加了权限的标注
- 修复 AudioRecord录制的音频播放时没反应的问题。
- 整理出完整代码并上传到GitHub上。
AudioRecord和MediaRecorder两种都可以录制音频,MediaRecorder已实现大量的封装,操作起来更加简单,
而AudioRecord使用起来更加灵活,能实现更多的功能。
1.AudioRecord(基于字节流录音)
优点:可以实现语音的实时处理,进行边录边播,对音频的实时处理。
缺点:输出的是PCM的语音数据,如果保存成音频文件是不能被播放器播放的。要用到AudioTrack这个去进行处理。
2.MediaRecorder(基于文件录音)
已集成了录音,编码,压缩等,支持少量的音频格式文件。
优点:封装度很高,操作简单
缺点:无法实现实时处理音频,输出的音频格式少。
- 首先将权限加上
<!-- 允许程序录制音频-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 写SD卡权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- AudioRecord的功能实现:
开始录音代码实现
/**
* 开始录音
*
* @return
*/
private boolean dostart() {
try {
//记录开始录音时间
startRecorderTime = System.currentTimeMillis();
//创建录音文件
mAudioRecordFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/recorderdemo/" + System.currentTimeMillis() + ".pcm");
if (!mAudioRecordFile.getParentFile().exists()) {
mAudioRecordFile.getParentFile().mkdirs();
mAudioRecordFile.createNewFile();
}
//创建文件输出流
mFileOutputStream = new FileOutputStream(mAudioRecordFile);
//配置AudioRecord
int audioSource = MediaRecorder.AudioSource.MIC;
//所有android系统都支持
int sampleRate = 44100;
//单声道输入
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
//PCM_16是所有android系统都支持的
int autioFormat = AudioFormat.ENCODING_PCM_16BIT;
//计算AudioRecord内部buffer最小
int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, autioFormat);
//buffer不能小于最低要求,也不能小于我们每次我们读取的大小。
mAudioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, autioFormat, Math.max(minBufferSize, BUFFER_SIZE));
//开始录音
mAudioRecord.startRecording();
//循环读取数据,写入输出流中
while (mIsRecording) {
//只要还在录音就一直读取
int read = mAudioRecord.read(mBuffer, 0, BUFFER_SIZE);
if (read <= 0) {
return false;
} else {
mFileOutputStream.write(mBuffer, 0, read);
}
}
//退出循环,停止录音,释放资源
stopRecorder();
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (mAudioRecord != null) {
mAudioRecord.release();
}
}
return true;
}
停止录音代码实现
/**
* 停止录音
* @return
*/
private boolean doStop() {
//停止录音,关闭文件输出流
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
Log.i("Tag8", "go here");
//记录结束时间,统计录音时长
stopRecorderTime = System.currentTimeMillis();
//大于3秒算成功,在主线程更新UI
final int send = (int) (stopRecorderTime - startRecorderTime) / 1000;
if (send > 3) {
mHandler.post(new Runnable() {
@Override
public void run() {
tv_stream_msg.setText("录音成功:" + send + "秒");
bt_stream_recorder.setText("开始录音");
Log.i("Tag8", "go there");
}
});
} else {
recorderFail();
return false;
}
return true;
}
播放音频文件代码实现
/**
* 播放音频文件
*
* @param audioFile
*/
private void doPlay(File audioFile) {
if (audioFile != null) {
Log.i("Tag8", "go there");
//配置播放器
//音乐类型,扬声器播放
int streamType = AudioManager.STREAM_MUSIC;
//录音时采用的采样频率,所以播放时同样的采样频率
int sampleRate = 44100;
//单声道,和录音时设置的一样
int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
//录音时使用16bit,所以播放时同样采用该方式
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
//流模式
int mode = AudioTrack.MODE_STREAM;
//计算最小buffer大小
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
//构造AudioTrack 不能小于AudioTrack的最低要求,也不能小于我们每次读的大小
AudioTrack audioTrack = new AudioTrack(streamType, sampleRate, channelConfig, audioFormat,
Math.max(minBufferSize, BUFFER_SIZE), mode);
audioTrack.play();
//从文件流读数据
FileInputStream inputStream = null;
try {
//循环读数据,写到播放器去播放
inputStream = new FileInputStream(audioFile);
//循环读数据,写到播放器去播放
int read;
//只要没读完,循环播放
while ((read = inputStream.read(mBuffer)) > 0) {
Log.i("Tag8", "read:" + read);
int ret = audioTrack.write(mBuffer, 0, read);
//检查write的返回值,处理错误
switch (ret) {
case AudioTrack.ERROR_INVALID_OPERATION:
case AudioTrack.ERROR_BAD_VALUE:
case AudioManager.ERROR_DEAD_OBJECT:
playFail();
return;
default:
break;
}
}
//播放结束
audioTrack.stop();
} catch (Exception e) {
e.printStackTrace();
//读取失败
playFail();
} finally {
mIsPlaying = false;
//关闭文件输入流
if (inputStream != null) {
closeStream(inputStream);
}
//播放器释放
resetQuietly(audioTrack);
}
//循环读数据,写到播放器去播放
//错误处理,防止闪退
}
}
释放资源代码
@Override
protected void onDestroy() {
super.onDestroy();
if (mExecutorService != null) {
mExecutorService.shutdownNow();
}
if (mAudioRecord != null) {
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
- MediaRecord录制音频
启动录音代码实现
/**
* 启动录音
*
* @return
*/
private boolean doStart() {
try {
//创建MediaRecorder
mMediaRecorder = new MediaRecorder();
//创建录音文件
mRecorderFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/recorderdemo/" + System.currentTimeMillis() + ".m4a");
if (!mRecorderFile.getParentFile().exists()) mRecorderFile.getParentFile().mkdirs();
mRecorderFile.createNewFile();
//配置MediaRecorder
//从麦克风采集
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//保存文件为MP4格式
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
//所有android系统都支持的适中采样的频率
mMediaRecorder.setAudioSamplingRate(44100);
//通用的AAC编码格式
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
//设置音质频率
mMediaRecorder.setAudioEncodingBitRate(96000);
//设置文件录音的位置
mMediaRecorder.setOutputFile(mRecorderFile.getAbsolutePath());
//开始录音
mMediaRecorder.prepare();
mMediaRecorder.start();
startRecorderTime = System.currentTimeMillis();
} catch (Exception e) {
Toast.makeText(MediaRecordActivity.this, "录音失败,请重试", Toast.LENGTH_SHORT).show();
return false;
}
//记录开始录音时间,用于统计时长,小于3秒中,录音不发送
return true;
}
结束录音代码实现
/**
* 关闭录音
*
* @return
*/
private boolean doStop() {
try {
mMediaRecorder.stop();
stopRecorderTime = System.currentTimeMillis();
final int second = (int) (stopRecorderTime - startRecorderTime) / 1000;
//按住时间小于3秒钟,算作录取失败,不进行发送
if (second < 3) return false;
mHander.post(new Runnable() {
@Override
public void run() {
tv_sendmsg.setText("录制成功:" + second + "秒");
}
});
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
播放音频代码实现
/**
* 播放音频文件
* @param audioFile
*/
private void doPlay(File audioFile) {
try {
//配置播放器 MediaPlayer
mediaPlayer = new MediaPlayer();
//设置声音文件
mediaPlayer.setDataSource(audioFile.getAbsolutePath());
//配置音量,中等音量
mediaPlayer.setVolume(1,1);
//播放是否循环
mediaPlayer.setLooping(false);
//设置监听回调 播放完毕
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
stopPlayer();
}
});
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
stopPlayer();
Toast.makeText(MediaRecordActivity.this,"播放失败",Toast.LENGTH_SHORT).show();
return true;
}
});
//设置播放
mediaPlayer.prepare();
mediaPlayer.start();
//异常处理,防止闪退
} catch (Exception e) {
e.printStackTrace();
stopPlayer();
}
}
完整demo源码已上传至GitHub,
地址:https://github.com/DevelopWb/Audio_Record