File文件方式录音
public class FileActivity extends AppCompatActivity {
private TextView mTvPressToSay;
private TextView mTvLog,mPlay;
private ExecutorService mExecutorService;
private MediaRecorder mMediaRecorder;
private File mAudioFile;
private long mStartRecordTime,mStopRecordTime;
private volatile boolean isPlaying;
private MediaPlayer mMediaPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file);
mTvLog=findViewById(R.id.mTvLog);
mTvPressToSay=findViewById(R.id.mTvPressToSay);
mPlay=findViewById(R.id.mPlay);
mPlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//检查当前播放状态 防止多次播放
if (mAudioFile!=null&& !isPlaying){
//设置当前播放状态
isPlaying=true;
//播放在后台 提交一个后台任务
mExecutorService.submit(new Runnable() {
@Override
public void run() {
doPlay(mAudioFile);
}
});
}
}
});
//录音 JNI函数不具备线程安全性 所以要用单线程
mExecutorService= Executors.newSingleThreadExecutor();
//按下说话
mTvPressToSay.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startRecord();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
stopRecord();
break;
}
return true;
}
});
}
//开始录音
public void startRecord(){
mTvPressToSay.setText("正在说话");
mExecutorService.submit(new Runnable() {
@Override
public void run() {
//释放之前录音的 recorder
releaseRecorder();
//执行录音逻辑 如果失败提示用户
if (!doStart()){
recordFail();
}
}
});
}
//结束录音
public void stopRecord(){
mTvPressToSay.setText("按住说话");
mExecutorService.submit(new Runnable() {
@Override
public void run() {
//执行停止录音的逻辑
if (!doStop()){
recordFail();
}
releaseRecorder();
}
});
}
//启动录音逻辑
private boolean doStart() {
try {
//创建一个MediaRecorder
mMediaRecorder=new MediaRecorder();
//创建录音文件
mAudioFile=new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+"/iMoocDemo/"+System.currentTimeMillis()+".m4a");
mAudioFile.getParentFile().mkdirs();
mAudioFile.createNewFile();
//配置MeDiaRecorder
//从麦克风采集
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//保存文件为MP4
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
//所有安卓系统都支持的才采样频率
mMediaRecorder.setAudioSamplingRate(44100);
//通用的aac编码格式
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
//音质比较好的频率
mMediaRecorder.setAudioEncodingBitRate(96000);
//设置录音文件位置
mMediaRecorder.setOutputFile(mAudioFile.getAbsolutePath());
//开始录音
mMediaRecorder.prepare();
mMediaRecorder.start();
mStartRecordTime=System.currentTimeMillis();
//记录开始录音的时间,用于统计时常
} catch (IOException|RuntimeException e) {
e.printStackTrace();
return false;
}
return true;
}
//释放mediaRecorder
private void releaseRecorder() {
if (mMediaRecorder!=null){
mMediaRecorder.release();
mMediaRecorder=null;
}
}
//录音错误的处理
private void recordFail() {
mAudioFile=null;
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(FileActivity.this, "录制失败", Toast.LENGTH_SHORT).show();
}
});
}
//停止录音逻辑
private boolean doStop() {
try {
//停止录音
mMediaRecorder.stop();
//记录停止时间 统计时长
mStopRecordTime=System.currentTimeMillis();
//只接受超过3秒的录音 在ui上显示出来
final int second= (int) ((mStopRecordTime-mStartRecordTime)/1000);
if (second>3){
runOnUiThread(new Runnable() {
@Override
public void run() {
mTvLog.setText(mTvLog.getText()+"\n 录音成功"+second+"秒");
}
});
}
}catch (RuntimeException e){
e.printStackTrace();
}
return true;
}
//
private void doPlay(File mAudioFile) {
//配置播放器 mediaplayer
mMediaPlayer=new MediaPlayer();
try {
//设置声音文件
mMediaPlayer.setDataSource(mAudioFile.getAbsolutePath());
//设置监听回调
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
//播放接收 释放播放器
stopPlay();
}
});
mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
//提示用户
playFail();
//释放播放器
stopPlay();
//错误自己处理
return true;
}
});
//配置音量 是否循环
mMediaPlayer.setVolume(1,1);
mMediaPlayer.setLooping(false);
//准备开始
mMediaPlayer.prepare();
mMediaPlayer.start();
}catch (IOException|RuntimeException e){
e.printStackTrace();
//提醒用户
playFail();
//释放播放器
stopPlay();
}
//异常处理 防止闪退
}
//提示用户播放失败
private void playFail(){
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(FileActivity.this, "播放失败", Toast.LENGTH_SHORT).show();
}
});
}
//停止播放逻辑
private void stopPlay(){
//重置播放状态
isPlaying=false;
//释放播放器
if (mMediaPlayer!=null){
//重置我们的监听器防止内存泄漏
mMediaPlayer.setOnErrorListener(null);
mMediaPlayer.setOnCompletionListener(null);
mMediaPlayer.stop();
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer=null;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mExecutorService.shutdownNow();
releaseRecorder();
stopPlay();
}
}
字节流录音模式
public class StreamActivity extends AppCompatActivity {
private TextView mStart;
private TextView mTvLog,mPlay;
//volatile 保证多线程内存同步
private volatile boolean mIsRecording,isPlaying;
private ExecutorService mExecutorService;
private File mAudioFile;
private long mStartRecordTime,mStopRecordTime;
//buffer不能太大秒oom
private static final int BUFFER_SIZE=2024;
private byte[] mBuffer;
private FileOutputStream mFileOutputStream;
private AudioRecord mAudioRecord;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stream);
mTvLog=findViewById(R.id.mTvLog);
mStart=findViewById(R.id.mStart);
//录音 JNI函数不具备线程安全性 所以要用单线程
mExecutorService= Executors.newSingleThreadExecutor();
mBuffer=new byte[BUFFER_SIZE];
mPlay=findViewById(R.id.mPlay);
mPlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//检查当前播放状态 防止多次播放
if (mAudioFile!=null&& !isPlaying){
//设置当前播放状态
isPlaying=true;
//播放在后台 提交一个后台任务
mExecutorService.submit(new Runnable() {
@Override
public void run() {
doPlay(mAudioFile);
}
});
}
}
});
mStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mIsRecording){
mStart.setText("开始录音");
mIsRecording=false;
}else{
mStart.setText("结束录音");
//提价一个后台任务开始录音
mIsRecording=true;
mExecutorService.submit(new Runnable() {
@Override
public void run() {
if (!startRecord()){
recodFail();
}
}
});
}
}
});
}
private boolean startRecord() {
try {
//创建录音文件
mAudioFile=new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+"/iMoocDemo/"+System.currentTimeMillis()+".pcm");
mAudioFile.getParentFile().mkdirs();
mAudioFile.createNewFile();
//创建文件输出流
mFileOutputStream=new FileOutputStream(mAudioFile);
//配置Audiorecord
//从麦克风采集
int audioSource= MediaRecorder.AudioSource.MIC;
int sampleRate=44100;//所有安卓系统都支持的频率
//单声道输入
int chanelConfig= AudioFormat.CHANNEL_IN_MONO;
//pcm16是所有安卓系统都支持
int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
//计算AudioRecord 内部 buffer最小缓冲区的大小
int minBufferSize= AudioRecord.getMinBufferSize(sampleRate,chanelConfig,audioFormat);
//buffer 不能小于最低要求也不能小于我们每次读取的大小
mAudioRecord=new AudioRecord(audioSource,sampleRate
,chanelConfig,audioFormat,Math.max(minBufferSize,BUFFER_SIZE));
//开始录音
mAudioRecord.startRecording();
//记录开始录音时间 统计时常
mStartRecordTime=System.currentTimeMillis();
//循环读取数据 写到输出流中
while (mIsRecording){
//只要还在录音状态 ,就一直读取数据
int read=mAudioRecord.read(mBuffer,0,BUFFER_SIZE);
if (read>0){
//读取成功
mFileOutputStream.write(mBuffer,0,read);
}else{
//读取失败,返回false 提示用户
return false;
}
}
//退出循环,停止录音释放资源
return stopRecord();
}catch (IOException|RuntimeException e){
e.printStackTrace();
return false;
}finally {
//释放audioRecord资源
if (mAudioRecord!=null){
mAudioRecord.release();
}
}
}
//
private boolean stopRecord() {
try {
//停止录音 关闭文件输出流
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord=null;
mFileOutputStream.close();
//记录当前时间 大于3秒
mStopRecordTime=System.currentTimeMillis();
final int second= (int) ((mStopRecordTime-mStartRecordTime)/1000);
if (second>3){
runOnUiThread(new Runnable() {
@Override
public void run() {
mTvLog.setText(mTvLog.getText()+"\n 录音成功"+second+"秒");
}
});
}
}catch (IOException e){
e.printStackTrace();
return false;
}
return true;
}
private void recodFail() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(StreamActivity.this, "录音失败", Toast.LENGTH_SHORT).show();
//重置录音状态 以及ui状态
mIsRecording=false;
mStart.setText("开始录音");
}
});
}
private void doPlay(File audioFile) {
//配置播放器
//音乐类型 扬声器播放
int streamType= AudioManager.STREAM_MUSIC;
//录音时采用的采样频率,所以播放时候使用同样的采样频率
int sampleRate=44100;
//mono 表示单声道 录音输入单声道,播放输出单声道
int chanelConfig=AudioFormat.CHANNEL_OUT_MONO;
//录音时使用16bit 所以播放时同样的格式
int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
//流模式
int mode= AudioTrack.MODE_STREAM;
int minBufferSize=AudioTrack.getMinBufferSize(sampleRate,chanelConfig,audioFormat);
//构造audioTrack
AudioTrack audioTrack=new AudioTrack(streamType,sampleRate,
chanelConfig,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){
int ret=audioTrack.write(mBuffer,0,read);
//检查write返回值 错误处理
switch (ret){
case AudioTrack.ERROR_INVALID_OPERATION:
case AudioTrack.ERROR_BAD_VALUE:
case AudioTrack.ERROR_DEAD_OBJECT:
playFail();
return;
}
}
//错误处理防止闪退
}catch (RuntimeException |IOException e){
e.printStackTrace();
playFail();
}finally {
isPlaying=false;
if (inputStream!=null){
closeQuietly(inputStream);
}
resetQuietly(audioTrack);
}
}
private void resetQuietly(AudioTrack audioTrack) {
try {
//播放器释放
audioTrack.stop();
audioTrack.release();
}catch (Exception e){
e.printStackTrace();
}
}
private void closeQuietly(FileInputStream inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void playFail() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(StreamActivity.this, "播放失败", Toast.LENGTH_SHORT).show();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mExecutorService.shutdownNow();
}
}