AudioRecoder 录音

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;

}

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容