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;

/**

* 該實(shí)例中,我們使用AudioRecord類來完成我們的音頻錄制程序

* AudioRecord類,我們可以使用三種不同的read方法來完成錄制工作,

* 每種方法都有其實(shí)用的場(chǎng)合

* 一、實(shí)例化一個(gè)AudioRecord類我們需要傳入幾種參數(shù)

* 1、AudioSource:這里可以是MediaRecorder.AudioSource.MIC

* 2、SampleRateInHz:錄制頻率,可以為8000hz或者11025hz等,不同的硬件設(shè)備這個(gè)值不同

* 3、ChannelConfig:錄制通道,可以為AudioFormat.CHANNEL_CONFIGURATION_MONO和AudioFormat.CHANNEL_CONFIGURATION_STEREO

* 4、AudioFormat:錄制編碼格式,可以為AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的仿真性比8BIT好,但是需要消耗更多的電量和存儲(chǔ)空間

* 5、BufferSize:錄制緩沖大?。嚎梢酝ㄟ^getMinBufferSize來獲取

* 這樣我們就可以實(shí)例化一個(gè)AudioRecord對(duì)象了

* 二、創(chuàng)建一個(gè)文件,用于保存錄制的內(nèi)容

* 同上篇

* 三、打開一個(gè)輸出流,指向創(chuàng)建的文件

* DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))

* 四、現(xiàn)在就可以開始錄制了,我們需要?jiǎng)?chuàng)建一個(gè)字節(jié)數(shù)組來存儲(chǔ)從AudioRecorder中返回的音頻數(shù)據(jù),但是

* 注意,我們定義的數(shù)組要小于定義AudioRecord時(shí)指定的那個(gè)BufferSize

* short[]buffer = new short[BufferSize/4];

* startRecording();

* 然后一個(gè)循環(huán),調(diào)用AudioRecord的read方法實(shí)現(xiàn)讀取

* 另外使用MediaPlayer是無法播放使用AudioRecord錄制的音頻的,為了實(shí)現(xiàn)播放,我們需要

* 使用AudioTrack類來實(shí)現(xiàn)

* AudioTrack類允許我們播放原始的音頻數(shù)據(jù)

*

*

* 一、實(shí)例化一個(gè)AudioTrack同樣要傳入幾個(gè)參數(shù)

* 1、StreamType:在AudioManager中有幾個(gè)常量,其中一個(gè)是STREAM_MUSIC;

* 2、SampleRateInHz:最好和AudioRecord使用的是同一個(gè)值

* 3、ChannelConfig:同上

* 4、AudioFormat:同上

* 5、BufferSize:通過AudioTrack的靜態(tài)方法getMinBufferSize來獲取

* 6、Mode:可以是AudioTrack.MODE_STREAM和MODE_STATIC,關(guān)于這兩種不同之處,可以查閱文檔

* 二、打開一個(gè)輸入流,指向剛剛錄制內(nèi)容保存的文件,然后開始播放,邊讀取邊播放

*

* 實(shí)現(xiàn)時(shí),音頻的錄制和播放分別使用兩個(gè)AsyncTask來完成

*/

public classAudioRecordActivityextendsBaseActivity {

privatePlayTaskplayer;

privateButtonstart_tv;

privateListViewlistView;

//線程操作

privateExecutorServicemExecutorService;

//當(dāng)前是否正在錄音

private volatile booleanisRecording;

//錄音開始時(shí)間與結(jié)束時(shí)間

private longstartTime,endTime;

//錄音所保存的文件

privateFilemAudioFile;

/**

* 文件列表數(shù)據(jù)

*/

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.這里的值注意了,寫的不好,可能實(shí)例化AudioRecord對(duì)象的時(shí)候,會(huì)出錯(cuò)。我開始寫成11025就不行。這取決于硬件設(shè)備

private intchannelConfig= AudioFormat.CHANNEL_CONFIGURATION_MONO;

private intaudioEncoding= AudioFormat.ENCODING_PCM_16BIT;

//緩存大小

private static final intBUFFER_SIZE=2048;

//計(jì)算AudioRecord內(nèi)部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:

//錄音成功,展示數(shù)據(jù)

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;

//錄音時(shí)間太短

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);

//點(diǎn)擊Item播放對(duì)應(yīng)的聲音文件

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以上權(quán)限管理

permissionForM();

}else{

//開始錄音

startRecord();

}

}

});

}

break;

}

}

/**

* 開始錄制

*/

private voidstartRecord() {

try{

//創(chuàng)建錄音文件,.m4a為MPEG-4音頻標(biāo)準(zhǔn)的文件的擴(kuò)展名

mAudioFile=newFile(mFilePath+ System.currentTimeMillis() +".pcm");

//創(chuàng)建父文件夾

mAudioFile.getParentFile().mkdirs();

//創(chuàng)建文件

mAudioFile.createNewFile();

//創(chuàng)建文件輸出流

mFileOutPutStream=newFileOutputStream(mAudioFile);

//根據(jù)上面的設(shè)置參數(shù)初始化AudioRecord

mAudioRecord=newAudioRecord(audioSource,frequence,channelConfig,audioEncoding,Math.max(minBufferSize,BUFFER_SIZE));

//開始錄音

mAudioRecord.startRecording();

//記錄開始時(shí)間

startTime= System.currentTimeMillis();

short[] buffer =new short[BUFFER_SIZE];

while(isRecording) {

//r是實(shí)際讀取的數(shù)據(jù)長度,一般而言r會(huì)小于buffersize

intr =mAudioRecord.read(buffer,0,BUFFER_SIZE);

longv =0;

// 將 buffer 內(nèi)容取出,進(jìn)行平方和運(yùn)算

for(inti =0;i < buffer.length;i++) {

v += buffer[i] * buffer[i];

}

// 平方和除以數(shù)據(jù)總長度,得到音量大小。

doublemean = v / (double) r;

doublevolume =10* Math.log10(mean);

Log.d("zhangxin","分貝值:"+ volume);

}

//寫入數(shù)據(jù)到文件

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();

//記錄時(shí)長

endTime= System.currentTimeMillis();

//錄音時(shí)間處理,比如只有大于2秒的錄音才算成功

inttime = (int) ((endTime-startTime) /1000);

if(time >=3) {

//錄音成功,添加數(shù)據(jù)

FileBean bean =newFileBean();

bean.setFile(mAudioFile);

bean.setFileLength(time);

dataList.add(bean);

//錄音成功,發(fā)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以上版本手機(jī)權(quán)限處理

*/

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類中,實(shí)現(xiàn)播放

DataInputStream dis =newDataInputStream(newBufferedInputStream(newFileInputStream(audioFile)));

//實(shí)例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++;

}

//然后將數(shù)據(jù)寫入到AudioTrack中

track.write(buffer,0,buffer.length);

}

//播放結(jié)束

track.stop();

dis.close();

}catch(Exception e) {

//TODO: handle exception

}

return null;

}

}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容