Android录音时指针摆动的实现

来源:互联网 发布:怎样在淘宝上入驻商家 编辑:程序博客网 时间:2024/06/10 04:37

本文中实现录音时候、指针摆动的功能主要是参考SoundRecorder的。主要是其中的VUMeter类,VUMeter是通过Recorder.getMaxAmplitude()的值计算,画出指针的偏移摆动。

下面直接上代码:

VUMeter类:

package hfut.geron.record;import hfut.geron.memorybook.R;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.View;public class VUMeter extends View {    static final float PIVOT_RADIUS = 3.5f;    static final float PIVOT_Y_OFFSET = 10f;    static final float SHADOW_OFFSET = 2.0f;    static final float DROPOFF_STEP = 0.18f;    static final float SURGE_STEP = 0.35f;    static final long  ANIMATION_INTERVAL = 70;        Paint mPaint, mShadow;    float mCurrentAngle;        RecordHelper mRecorder;    public VUMeter(Context context) {        super(context);        init(context);    }    public VUMeter(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    void init(Context context) {        Drawable background = context.getResources().getDrawable(R.drawable.record_bg2);        setBackgroundDrawable(background);                mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mPaint.setColor(Color.WHITE);        mShadow = new Paint(Paint.ANTI_ALIAS_FLAG);        mShadow.setColor(Color.argb(60, 0, 0, 0));                mRecorder = null;                mCurrentAngle = 0;    }    public void setRecorder(RecordHelper recorder) {    mRecorder = recorder;    invalidate();    }        @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        final float minAngle = (float)Math.PI/8;        final float maxAngle = (float)Math.PI*7/8;                        float angle = minAngle;        if (mRecorder != null)         angle += (float)(maxAngle - minAngle)*mRecorder.getMaxAmplitude()/32768;        if (angle > mCurrentAngle)            mCurrentAngle = angle;        else            mCurrentAngle = Math.max(angle, mCurrentAngle - DROPOFF_STEP);        mCurrentAngle = Math.min(maxAngle, mCurrentAngle);        float w = getWidth();        float h = getHeight();        float pivotX = w/2;        float pivotY = h - PIVOT_RADIUS - PIVOT_Y_OFFSET;        float l = h*4/5;        float sin = (float) Math.sin(mCurrentAngle);        float cos = (float) Math.cos(mCurrentAngle);        float x0 = pivotX - l*cos;        float y0 = pivotY - l*sin;        canvas.drawLine(x0 + SHADOW_OFFSET, y0 + SHADOW_OFFSET, pivotX + SHADOW_OFFSET, pivotY + SHADOW_OFFSET, mShadow);        canvas.drawCircle(pivotX + SHADOW_OFFSET, pivotY + SHADOW_OFFSET, PIVOT_RADIUS, mShadow);        canvas.drawLine(x0, y0, pivotX, pivotY, mPaint);        canvas.drawCircle(pivotX, pivotY, PIVOT_RADIUS, mPaint);                if (mRecorder != null)        postInvalidateDelayed(ANIMATION_INTERVAL);    }}

录音类:RecordHelper.java

package hfut.geron.record;import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import android.content.Context;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.media.MediaPlayer.OnErrorListener;import android.media.MediaRecorder;import android.util.Log;public class RecordHelper implements OnCompletionListener, OnErrorListener{     private MediaRecorder mRecorder ; private String record_path;     public static final int IDLE_STATE = 0;   //空闲状态     public static final int RECORDING_STATE = 1; //录音状态             int mState = IDLE_STATE;   //状态标示,默认是空闲状态          public static final int NO_ERROR = 0;     public static final int SDCARD_ACCESS_ERROR = 1;     public static final int INTERNAL_ERROR = 2;          public interface OnStateChangedListener {         public void onStateChanged(int state);         public void onError(int error);     }     OnStateChangedListener mOnStateChangedListener = null;     public void setOnStateChangedListener(OnStateChangedListener listener) {         mOnStateChangedListener = listener;     }      public void startRecording(int outputfileformat, String suffix, Context context) { Log.d("Infor", "start..."); stopRecording();  if(CommonUtils.isSdCardAvailable()){ File audioRecPath = new File(CommonUtils.RECORD_PATH);//判断存储音频的文件夹是否存在,如果不存在则进行创建操作 if(!audioRecPath.exists()){ audioRecPath.mkdir(); } if(audioRecPath != null ){  //创建临时文件,以Record_开头 SimpleDateFormat   sDateFormat   =   new   SimpleDateFormat("yyyyMMdd_hhmmss");  String record_name   =   "Record_"+sDateFormat.format(new java.util.Date());  File audioRecFile; try {audioRecFile = File.createTempFile(record_name, suffix, audioRecPath); } catch (IOException e) {// TODO Auto-generated catch block setError(SDCARD_ACCESS_ERROR); return;}  mRecorder= new MediaRecorder();//设置采样的音频源为麦克风mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置输出文件格式        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);        //设置音频的编码方式        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);        //设置输出文件        Log.d("Infor", audioRecFile.getAbsolutePath());        record_path= audioRecFile.getAbsolutePath();        mRecorder.setOutputFile(audioRecFile.getAbsolutePath());                try{        mRecorder.prepare();                           }catch(IOException e){                   setError(INTERNAL_ERROR);                       mRecorder.reset();                       mRecorder.release();                       mRecorder = null;                       return;       }        //开始录音        if(this.mState==RecordHelper.IDLE_STATE){        mRecorder.start();        setState(RECORDING_STATE);        }  } }  else{ Log.d("Infor", "error,内存卡打不开。。。"); setError(SDCARD_ACCESS_ERROR); }  } public void stopRecording() {        if (mRecorder == null)            return;        mRecorder.stop();        mRecorder.release();        mRecorder = null;              setState(IDLE_STATE);    }  void setState(int state){//设置状态 if (state == mState)            return;                mState = state;            signalStateChanged(mState); }   public int getMaxAmplitude() {//得到录音的振幅        if (mState != RECORDING_STATE)            return 0;        return mRecorder.getMaxAmplitude();    }  //实现对自定义接口OnStateChangedListener的两个方法调用的条件    private void signalStateChanged(int state) {        if (mOnStateChangedListener != null)            mOnStateChangedListener.onStateChanged(state);    }        private void setError(int error) {        if (mOnStateChangedListener != null)            mOnStateChangedListener.onError(error);    }         public String getPath(){    return record_path;    }  /*继承接口方法*/ public boolean onError(MediaPlayer mp, int what, int extra) {// TODO Auto-generated method stubreturn true;}public void onCompletion(MediaPlayer mp) {// TODO Auto-generated method stub}}

RecordActivity:

package hfut.geron.memorybook.onebook;import java.io.File;import hfut.geron.memorybook.R;import hfut.geron.record.CommonUtils;import hfut.geron.record.RecordHelper;import hfut.geron.record.RecordHelper.OnStateChangedListener;import hfut.geron.record.VUMeter;import android.app.Activity;import android.app.Dialog;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.media.MediaRecorder;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.PowerManager;import android.os.PowerManager.WakeLock;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.ImageButton;import android.widget.TextView;import android.widget.Toast;public class RecordActivity extends Activity implements OnClickListener, OnStateChangedListener {    private TextView record_text_time;    private ImageButton record_btn_begin,record_btn_end;    private VUMeter mVUMeter;//VUMeter类是通过mRecorder.getMaxAmplitude()的值计算,画出指针的偏移摆动    WakeLock mWakeLock;//用WakeLock请求休眠锁,让其不会休眠    private String time;    private RecordHelper mRecordHelper;//录音类,实现录音功能        private int s1=0;    private int s2=0;    private int m1=0;    private int m2=0;    private final static int RECORD_ISOVER = 1;    private final static int SDCARD_ACCESS_ERROR=2;            private final static int NOTES_RECORD=1;    private Handler time_handler= new Handler();    private Runnable runnable = new Runnable(){public void run() {// TODO Auto-generated method stubif(s1==10){s2++;s1=0;}if(s2==6){s2=0;m1++;}if(m1==10){m1=0;m2++;}time=""+m2+m1+":"+s2+s1;record_text_time = (TextView) findViewById(R.id.record_text_time);record_text_time.setText(time);s1++;time_handler.postDelayed(runnable, 1000);}        };       @Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);this.setContentView(R.layout.recordialog);PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,"SoundRecorder");//请求休眠锁mRecordHelper = new RecordHelper();mRecordHelper.setOnStateChangedListener(this);mVUMeter = (VUMeter)this.findViewById(R.id.record_VUMeter);mVUMeter.setRecorder(mRecordHelper);record_text_time = (TextView)this.findViewById(R.id.record_text_time);record_btn_begin = (ImageButton)this.findViewById(R.id.record_btn_begin);record_btn_end= (ImageButton)this.findViewById(R.id.record_btn_end);record_btn_begin.setOnClickListener(this);record_btn_end.setOnClickListener(this);record_btn_begin.setId(1);record_btn_end.setId(2);}public void onClick(View v) {// TODO Auto-generated method stubint id=v.getId();switch(id){case 1:    //录音开始time_handler.post(runnable);Log.d("Infor", "录音开始...");mRecordHelper.startRecording(MediaRecorder.OutputFormat.DEFAULT,   ".amr", this);record_btn_end.setClickable(true);record_btn_begin.setClickable(false);    break;case 2:    //录音结束record_btn_begin.setClickable(true);time_handler.removeCallbacks(runnable);s1=s2=m1=m2=0;Log.d("Infor", "录音关闭...");mRecordHelper.stopRecording();showDialog(RECORD_ISOVER);break;}}public void onStateChanged(int state) {// TODO Auto-generated method stubLog.d("Infor", "录音状态发生改变");if (state == RecordHelper.RECORDING_STATE) {mWakeLock.acquire(); // 录音的时候让其不休眠} else {if (mWakeLock.isHeld())mWakeLock.release();}}public void onError(int error) {// TODO Auto-generated method stubLog.d("Infor", "error:"+error);this.showDialog(error);}@Overrideprotected Dialog onCreateDialog(int id) {// TODO Auto-generated method stubswitch(id){case RECORD_ISOVER:Log.d("Infor", "here");return CommonUtils.getDialog(this, "提示", "确定要保存该录音音频文件吗?", 0,"是", "否", new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stubLog.d("Infor", "保存该录音音频");Toast.makeText(RecordActivity.this, "录音文件保存成功...", Toast.LENGTH_SHORT).show();    Intent intent = new Intent(RecordActivity.this,NoteActivity.class);    intent.putExtra("recordpath", mRecordHelper.getPath());    RecordActivity.this.setResult(NOTES_RECORD, intent);    RecordActivity.this.finish();}}, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stub//删除之前的录音文件Log.d("Infor", "取消保存该录音音频");record_text_time.setText("00:00");Log.d("Infor", "PATH:"+mRecordHelper.getPath());File file = new File(mRecordHelper.getPath());if(file.exists()){Log.d("Infor", "存在");try{file.delete();}catch(Exception e){Log.d("Infor", "删除不了");}}}});case SDCARD_ACCESS_ERROR:return CommonUtils.getDialog(this, "提示", "无法读取内存卡..", 0, "是", null,  new DialogInterface.OnClickListener(){public void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stubRecordActivity.this.finish();}}, null);default:return null;}}}

结果截图:


要点:

1、该程序中使用了用WakeLock请求休眠锁,让其不会休眠。这样能保证录音过程中屏幕常亮。

2、该程序中主要使用VUMeter,自定义该类,VUMeter类是通过mRecorder.getMaxAmplitude()的值计算,画出指针的偏移摆动。

3、RecordHelper类中定义了一个接口OnStateChangedListener ,定义如下

public interface OnStateChangedListener {
         public void onStateChanged(int state);
         public void onError(int error);
     }

并在RecordHelper类中实例化该接口并set,如下:

     OnStateChangedListener mOnStateChangedListener = null;
         public void setOnStateChangedListener(OnStateChangedListener listener) {
               mOnStateChangedListener = listener;
     }

定义在何种情况下使用该接口中的两个方法:

 //实现对自定义接口OnStateChangedListener的两个方法调用的条件
   private void signalStateChanged(int state) {
       if (mOnStateChangedListener != null)
           mOnStateChangedListener.onStateChanged(state);
   }
   
   private void setError(int error) {
       if (mOnStateChangedListener != null)
           mOnStateChangedListener.onError(error);
   }

在RecordActivity类中就可以继承该接口

 class RecordActivity extends Activity implements OnStateChangedListener{}

mRecordHelper = new RecordHelper();
mRecordHelper.setOnStateChangedListener(this);

原创粉丝点击