Android录音时指针摆动的实现

本文中实现录音时候、指针摆动的功能主要是参考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 stub
		
		
		
		return 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 stub
			
			if(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);
			
		}
    	
    };
   
    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.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 stub
		int 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 stub
		Log.d("Infor", "录音状态发生改变");
		if (state == RecordHelper.RECORDING_STATE) {
			mWakeLock.acquire(); // 录音的时候让其不休眠
									
		} else {
			if (mWakeLock.isHeld())
				mWakeLock.release();
		}
		
	}
	public void onError(int error) {
		// TODO Auto-generated method stub
		Log.d("Infor", "error:"+error);
		this.showDialog(error);
	}
	@Override
	protected Dialog onCreateDialog(int id) {
		// TODO Auto-generated method stub
		
		switch(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 stub
							Log.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 stub
				RecordActivity.this.finish();	
				}
				
			}, null);
			
			
		default:
			return null;
		}
	}
}

结果截图:

Android录音时指针摆动的实现_第1张图片

要点:

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

你可能感兴趣的:(Android录音时指针摆动的实现)