获取当前麦克风音量
2014年12月22日
0:21
首先是界面:
检测麦克风当前音量主要是用Android自己的类MediaRecorder来实现的,很多函数都是可以直接使用的,所以实现检测麦克风音量其实不是很难,只要注意一下使用的方法就可以了。
start:是开始监测
end:结束检测
大概思路就是用麦克风录音,用MediaRecorder.getMaxAmplitude()函数来获取麦克风当前的音量值
getMaxAmplitude()返回值就是从上一次调用getMaxAmplitude( )的时刻到这一次调用getMaxAmplitude( )时刻之间的音频振幅绝对值的最大值,如果控制两个getMaxAmplitude()调用的间隔比较小的话,就可以实时得到当前的音频的振幅的绝对值了。
值得一说的是,getMaxAmplitude()方法不能在android的主线程循环调用,否则程序会闪退(哈,试过好几次了,都不知道是什么原因,后来才发现是大概因为Android的主线程会使用比较多的资源来调用这个方法,然后系统九崩溃了,就造成了闪退。解决的方法就是把getMaxAmplitude()函数的调用放在一个线程里,通过控制线程的启动时间间隔来减少使用的资源以保证程序稳定不会闪退)
以下是MainActivity.java里的代码:(含注释)
package com.example.rec;
import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import android.support.v7.app.ActionBarActivity;
import android.annotation.SuppressLint;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
@SuppressLint("ShowToast")
public class MainActivity extends ActionBarActivity {
private MediaRecorder mp;
private TextView txt1;
private int value=0;
private TimerTask task=null;
private Timer timer=null;
private int maxx=0;
private TextView maxtext;
File soundFile=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt1=(TextView) findViewById(R.id.voise);
maxtext=(TextView)findViewById(R.id.maxxvalue);
}
public void deal_with(View v){ //这是按钮按下去触发的函数,然后再执行对于的实现方法
switch(v.getId()){
case R.id.startbt: //开始按钮
startrec();
break;
case R.id.endbt: //结束按钮
endrec();
break;
}
}
private void startrec(){ //开始监测,先准备好用麦克风录音,
if(mp==null){
File dir=new File(Environment.getExternalStorageDirectory(),"sound"); //指定录音输出文件的文件夹(最后会删除录音文件的)
if(!dir.exists()){ //文件夹路径不存在就创建一个
dir.mkdirs();
}
soundFile=new File(dir,System.currentTimeMillis()+".amr"); //创建输出文件
if(!soundFile.exists()){
try {
soundFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mp=new MediaRecorder(); //程序中操作的MediaRecorder类
mp.setAudioSource(MediaRecorder.AudioSource.MIC); //MediaRecorder类的初始化(注意顺序不能反
mp.setOutputFormat(MediaRecorder.OutputFormat.AMR_WB);
mp.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB);
mp.setOutputFile(soundFile.getAbsolutePath()); //MediaRecorder和文件绑定,MediaRecorder录制的内容将自动保存在soundFile文件中
try {
mp.prepare();
mp.start(); //开始录音
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Toast.makeText(MainActivity.this,"开始录音...", Toast.LENGTH_LONG).show(); //标签提示一下
starttorec(); //调用线程来实现获取当前音频振幅 (start to record)
}
}
private Handler mHandler =new Handler(){
public void handleMessage(Message msg){
txt1.setText(""+msg.arg1); //把Handle 中获得的信息在主线程使用,更新txt1的显示内容
if(maxx<msg.arg1){ //(注意在setText()中要加"",否则又会跪(使用是跪了几次才发现= =)
maxx=msg.arg1; //显示最大值
maxtext.setText(""+maxx);
}
starttorec(); //重新调用检测的线程
}
};
public void starttorec(){
timer=new Timer();
task=new TimerTask(){ //设置线程抽象类中的run(),这里更新value的值
@Override //把value的值放到用于线程之间交流数据的Handler的message里
public void run() {
value=mp.getMaxAmplitude();
Message message=mHandler.obtainMessage();
message.arg1=value;
mHandler.sendMessage(message); //Handler类发出信息
}
};
timer.schedule(task, 100); //timer,设置为100毫秒后执行task线程(会自动调用task的start()函数)
//timer是计时器,作用就是在设定时间后启动规定的线程。这用来限制
//getMaxAmplitude()的调用频率,减少资源的使用(时间调太短,也会闪退) //
}
private void endrec(){
if(mp!=null){
Toast.makeText(MainActivity.this,"录音结束...", Toast.LENGTH_SHORT).show(); //提示
timer.cancel();; //取消计时器(线程将不会被启动)
mp.stop(); //停止录音
mp.release(); //释放资源(mp不再绑定soundFile文件)
soundFile.delete(); //删除刚才录下的文件节约空间(也可以不删拿出来听一听~)
mp=null; //习惯性赋空值
}
}
}
MainActivity.java文件就是这样,在AndroidManifest.xml中声明写入sd卡,和打开麦克风的权限
还有的是同时刻,同场合不同机器所测出来的音频最大振幅值相差比较大,应该是硬件个体性差异的缘故。