packagecom.ldm.mediarecorder.activity;
importandroid.Manifest;
importandroid.content.pm.PackageManager;
importandroid.media.AudioFormat;
importandroid.media.AudioManager;
importandroid.media.AudioRecord;
importandroid.media.AudioTrack;
importandroid.media.MediaRecorder;
importandroid.os.AsyncTask;
importandroid.os.Build;
importandroid.os.Environment;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.support.annotation.NonNull;
importandroid.support.v4.app.ActivityCompat;
importandroid.support.v4.content.ContextCompat;
importandroid.util.Log;
importandroid.view.View;
importandroid.widget.AdapterView;
importandroid.widget.Button;
importandroid.widget.ListView;
importandroid.widget.Toast;
importcom.ldm.mediarecorder.R;
importcom.ldm.mediarecorder.adapter.AudioAdapter;
importcom.ldm.mediarecorder.base.BaseActivity;
importcom.ldm.mediarecorder.base.Constant;
importcom.ldm.mediarecorder.model.FileBean;
importjava.io.BufferedInputStream;
importjava.io.DataInputStream;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
/**
* 该实例中,我们使用AudioRecord类来完成我们的音频录制程序
* AudioRecord类,我们可以使用三种不同的read方法来完成录制工作,
* 每种方法都有其实用的场合
* 一、实例化一个AudioRecord类我们需要传入几种参数
* 1、AudioSource:这里可以是MediaRecorder.AudioSource.MIC
* 2、SampleRateInHz:录制频率,可以为8000hz或者11025hz等,不同的硬件设备这个值不同
* 3、ChannelConfig:录制通道,可以为AudioFormat.CHANNEL_CONFIGURATION_MONO和AudioFormat.CHANNEL_CONFIGURATION_STEREO
* 4、AudioFormat:录制编码格式,可以为AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的仿真性比8BIT好,但是需要消耗更多的电量和存储空间
* 5、BufferSize:录制缓冲大小:可以通过getMinBufferSize来获取
* 这样我们就可以实例化一个AudioRecord对象了
* 二、创建一个文件,用于保存录制的内容
* 同上篇
* 三、打开一个输出流,指向创建的文件
* DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))
* 四、现在就可以开始录制了,我们需要创建一个字节数组来存储从AudioRecorder中返回的音频数据,但是
* 注意,我们定义的数组要小于定义AudioRecord时指定的那个BufferSize
* short[]buffer = new short[BufferSize/4];
* startRecording();
* 然后一个循环,调用AudioRecord的read方法实现读取
* 另外使用MediaPlayer是无法播放使用AudioRecord录制的音频的,为了实现播放,我们需要
* 使用AudioTrack类来实现
* AudioTrack类允许我们播放原始的音频数据
*
*
* 一、实例化一个AudioTrack同样要传入几个参数
* 1、StreamType:在AudioManager中有几个常量,其中一个是STREAM_MUSIC;
* 2、SampleRateInHz:最好和AudioRecord使用的是同一个值
* 3、ChannelConfig:同上
* 4、AudioFormat:同上
* 5、BufferSize:通过AudioTrack的静态方法getMinBufferSize来获取
* 6、Mode:可以是AudioTrack.MODE_STREAM和MODE_STATIC,关于这两种不同之处,可以查阅文档
* 二、打开一个输入流,指向刚刚录制内容保存的文件,然后开始播放,边读取边播放
*
* 实现时,音频的录制和播放分别使用两个AsyncTask来完成
*/
public classAudioRecordActivityextendsBaseActivity {
privatePlayTaskplayer;
privateButtonstart_tv;
privateListViewlistView;
//线程操作
privateExecutorServicemExecutorService;
//当前是否正在录音
private volatile booleanisRecording;
//录音开始时间与结束时间
private longstartTime,endTime;
//录音所保存的文件
privateFilemAudioFile;
/**
* 文件列表数据
*/
privateListdataList;
privateAudioAdaptermAudioAdapter;
//private String mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/audio/";
privateStringmFilePath= Environment.getExternalStorageDirectory().getAbsolutePath()+"/zhangxinaaaaa/";
private byte[]mBuffer;
privateFileOutputStreammFileOutPutStream;
//文件流录音API
privateAudioRecordmAudioRecord;
private volatile booleanisPlaying;
/**
* 配置AudioRecord
*/
private final intaudioSource= MediaRecorder.AudioSource.MIC;
private intfrequence=8000;//录制频率,单位hz.这里的值注意了,写的不好,可能实例化AudioRecord对象的时候,会出错。我开始写成11025就不行。这取决于硬件设备
private intchannelConfig= AudioFormat.CHANNEL_CONFIGURATION_MONO;
private intaudioEncoding= AudioFormat.ENCODING_PCM_16BIT;
//缓存大小
private static final intBUFFER_SIZE=2048;
//计算AudioRecord内部buffer大小
private final intminBufferSize= AudioRecord.getMinBufferSize(frequence,channelConfig,audioEncoding);
//更新UI线程的Handler
privateHandlermHandler=newHandler() {
@Override
public voidhandleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what) {
caseConstant.RECORD_SUCCESS:
//录音成功,展示数据
if(null==mAudioAdapter) {
mAudioAdapter=newAudioAdapter(AudioRecordActivity.this,dataList,R.layout.file_item_layout);
}
listView.setAdapter(mAudioAdapter);
break;
//录音失败
caseConstant.RECORD_FAIL:
showToastMsg(getString(R.string.record_fail));
break;
//录音时间太短
caseConstant.RECORD_TOO_SHORT:
showToastMsg(getString(R.string.time_too_short));
break;
caseConstant.PLAY_COMPLETION:
showToastMsg(getString(R.string.play_over));
break;
caseConstant.PLAY_ERROR:
showToastMsg(getString(R.string.play_error));
break;
}
}
};
@Override
protected voidsetWindowView() {
setContentView(R.layout.activity_record);
dataList=newArrayList<>();
mExecutorService= Executors.newSingleThreadExecutor();
mBuffer=new byte[BUFFER_SIZE];
}
@Override
protected voidinitViews() {
this.start_tv= (Button) findViewById(R.id.start_tv);
this.listView= (ListView) findViewById(R.id.listview);
}
@Override
protected voidinitEvents() {
this.start_tv.setOnClickListener(this);
//点击Item播放对应的声音文件
this.listView.setOnItemClickListener(newAdapterView.OnItemClickListener() {
@Override
public voidonItemClick(AdapterView adapterView,View view, inti, longl) {
//使用AudioTrack播放声音流文件
Toast.makeText(AudioRecordActivity.this,i +"",Toast.LENGTH_SHORT).show();
player=newPlayTask(dataList.get(i).getFile());
player.execute();
}
});
}
@Override
public voidonClick(View view) {
switch(view.getId()) {
//开始录音操作
caseR.id.start_tv:
//正在录音
if(isRecording) {
isRecording=false;
start_tv.setText(R.string.start_record);
//停止录音
mExecutorService.submit(newRunnable() {
@Override
public voidrun() {
stopRecord();
}
});
}else{
isRecording=true;
start_tv.setText(R.string.stop_record);
//录音操作
mExecutorService.submit(newRunnable() {
@Override
public voidrun() {
if(Build.VERSION.SDK_INT>22) {
//6.0以上权限管理
permissionForM();
}else{
//开始录音
startRecord();
}
}
});
}
break;
}
}
/**
* 开始录制
*/
private voidstartRecord() {
try{
//创建录音文件,.m4a为MPEG-4音频标准的文件的扩展名
mAudioFile=newFile(mFilePath+ System.currentTimeMillis() +".pcm");
//创建父文件夹
mAudioFile.getParentFile().mkdirs();
//创建文件
mAudioFile.createNewFile();
//创建文件输出流
mFileOutPutStream=newFileOutputStream(mAudioFile);
//根据上面的设置参数初始化AudioRecord
mAudioRecord=newAudioRecord(audioSource,frequence,channelConfig,audioEncoding,Math.max(minBufferSize,BUFFER_SIZE));
//开始录音
mAudioRecord.startRecording();
//记录开始时间
startTime= System.currentTimeMillis();
short[] buffer =new short[BUFFER_SIZE];
while(isRecording) {
//r是实际读取的数据长度,一般而言r会小于buffersize
intr =mAudioRecord.read(buffer,0,BUFFER_SIZE);
longv =0;
// 将 buffer 内容取出,进行平方和运算
for(inti =0;i < buffer.length;i++) {
v += buffer[i] * buffer[i];
}
// 平方和除以数据总长度,得到音量大小。
doublemean = v / (double) r;
doublevolume =10* Math.log10(mean);
Log.d("zhangxin","分贝值:"+ volume);
}
//写入数据到文件
while(isRecording) {
intread =mAudioRecord.read(mBuffer,0,BUFFER_SIZE);
if(read >0) {
//保存到指定文件
mFileOutPutStream.write(mBuffer,0,read);
}
}
}catch(IOException e) {
mHandler.sendEmptyMessage(Constant.RECORD_FAIL);
}finally{
// if (null != mAudioRecord) {
// //释放资源
// mAudioRecord.release();
// }
}
}
/**
*@description停止录音
*
*/
private voidstopRecord() {
try{
//停止录音
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord=null;
mFileOutPutStream.close();
//记录时长
endTime= System.currentTimeMillis();
//录音时间处理,比如只有大于2秒的录音才算成功
inttime = (int) ((endTime-startTime) /1000);
if(time >=3) {
//录音成功,添加数据
FileBean bean =newFileBean();
bean.setFile(mAudioFile);
bean.setFileLength(time);
dataList.add(bean);
//录音成功,发Message
mHandler.sendEmptyMessage(Constant.RECORD_SUCCESS);
}else{
mAudioFile=null;
mHandler.sendEmptyMessage(Constant.RECORD_TOO_SHORT);
}
}catch(Exception e) {
mHandler.sendEmptyMessage(Constant.RECORD_FAIL);
}
}
@Override
protected voidonDestroy() {
super.onDestroy();
if(null!=mExecutorService) {
mExecutorService.shutdownNow();
}
}
/**
* 6.0以上版本手机权限处理
*/
private voidpermissionForM() {
if(ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED|| ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
newString[]{Manifest.permission.RECORD_AUDIO,Manifest.permission.WRITE_EXTERNAL_STORAGE},
Constant.PERMISSIONS_REQUEST_FOR_AUDIO);
}else{
startRecord();
}
}
@Override
public voidonRequestPermissionsResult(intrequestCode,@NonNullString[] permissions,@NonNullint[] grantResults) {
if(requestCode == Constant.PERMISSIONS_REQUEST_FOR_AUDIO) {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startRecord();
}
return;
}
super.onRequestPermissionsResult(requestCode,permissions,grantResults);
}
/**
* 播放音频
*/
public classPlayTaskextendsAsyncTask {
FileaudioFile;
publicPlayTask(File audioFile) {
this.audioFile= audioFile;
}
@Override
protectedVoiddoInBackground(Void... arg0) {
isPlaying=true;
intbufferSize = AudioTrack.getMinBufferSize(frequence,channelConfig,audioEncoding);
short[] buffer =new short[bufferSize /4];
try{
//定义输入流,将音频写入到AudioTrack类中,实现播放
DataInputStream dis =newDataInputStream(newBufferedInputStream(newFileInputStream(audioFile)));
//实例AudioTrack
AudioTrack track =newAudioTrack(AudioManager.STREAM_MUSIC,frequence,channelConfig,audioEncoding,bufferSize,AudioTrack.MODE_STREAM);
//开始播放
track.play();
//由于AudioTrack播放的是流,所以,我们需要一边播放一边读取
while(isPlaying&& dis.available() >0) {
inti =0;
while(dis.available() >0&& i < buffer.length) {
buffer[i] = dis.readShort();
i++;
}
//然后将数据写入到AudioTrack中
track.write(buffer,0,buffer.length);
}
//播放结束
track.stop();
dis.close();
}catch(Exception e) {
//TODO: handle exception
}
return null;
}
}
}