Android录音时指针摆动的实现(附源码)


文中的Android代码主要是移植SoundRecorder的。主要是其中的VUMeter类,VUMeter是通过Recorder.getMaxAmplitude()的值计算,画出指针的偏移摆动。下面直接上代码

  1. /* 
  2.  * Copyright (C) 2011 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.android.soundrecorder;  
  18.   
  19. import android.content.Context;  
  20. import android.graphics.Canvas;  
  21. import android.graphics.Color;  
  22. import android.graphics.Paint;  
  23. import android.graphics.drawable.Drawable;  
  24. import android.util.AttributeSet;  
  25. import android.view.View;  
  26.   
  27. public class VUMeter extends View {  
  28.     static final float PIVOT_RADIUS = 3.5f;  
  29.     static final float PIVOT_Y_OFFSET = 10f;  
  30.     static final float SHADOW_OFFSET = 2.0f;  
  31.     static final float DROPOFF_STEP = 0.18f;  
  32.     static final float SURGE_STEP = 0.35f;  
  33.     static final long  ANIMATION_INTERVAL = 70;  
  34.       
  35.     Paint mPaint, mShadow;  
  36.     float mCurrentAngle;  
  37.       
  38.     Recorder mRecorder;  
  39.   
  40.     public VUMeter(Context context) {  
  41.         super(context);  
  42.         init(context);  
  43.     }  
  44.   
  45.     public VUMeter(Context context, AttributeSet attrs) {  
  46.         super(context, attrs);  
  47.         init(context);  
  48.     }  
  49.   
  50.     void init(Context context) {  
  51.         Drawable background = context.getResources().getDrawable(R.drawable.vumeter);  
  52.         setBackgroundDrawable(background);  
  53.           
  54.         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  55.         mPaint.setColor(Color.WHITE);  
  56.         mShadow = new Paint(Paint.ANTI_ALIAS_FLAG);  
  57.         mShadow.setColor(Color.argb(60000));  
  58.           
  59.         mRecorder = null;  
  60.           
  61.         mCurrentAngle = 0;  
  62.     }  
  63.   
  64.     public void setRecorder(Recorder recorder) {  
  65.         mRecorder = recorder;  
  66.         invalidate();  
  67.     }  
  68.       
  69.     @Override  
  70.     protected void onDraw(Canvas canvas) {  
  71.         super.onDraw(canvas);  
  72.   
  73.         final float minAngle = (float)Math.PI/8;  
  74.         final float maxAngle = (float)Math.PI*7/8;  
  75.                   
  76.         float angle = minAngle;  
  77.         if (mRecorder != null)  
  78.             angle += (float)(maxAngle - minAngle)*mRecorder.getMaxAmplitude()/32768;  
  79.   
  80.         if (angle > mCurrentAngle)  
  81.             mCurrentAngle = angle;  
  82.         else  
  83.             mCurrentAngle = Math.max(angle, mCurrentAngle - DROPOFF_STEP);  
  84.   
  85.         mCurrentAngle = Math.min(maxAngle, mCurrentAngle);  
  86.   
  87.         float w = getWidth();  
  88.         float h = getHeight();  
  89.         float pivotX = w/2;  
  90.         float pivotY = h - PIVOT_RADIUS - PIVOT_Y_OFFSET;  
  91.         float l = h*4/5;  
  92.         float sin = (float) Math.sin(mCurrentAngle);  
  93.         float cos = (float) Math.cos(mCurrentAngle);  
  94.         float x0 = pivotX - l*cos;  
  95.         float y0 = pivotY - l*sin;  
  96.         canvas.drawLine(x0 + SHADOW_OFFSET, y0 + SHADOW_OFFSET, pivotX + SHADOW_OFFSET, pivotY + SHADOW_OFFSET, mShadow);  
  97.         canvas.drawCircle(pivotX + SHADOW_OFFSET, pivotY + SHADOW_OFFSET, PIVOT_RADIUS, mShadow);  
  98.         canvas.drawLine(x0, y0, pivotX, pivotY, mPaint);  
  99.         canvas.drawCircle(pivotX, pivotY, PIVOT_RADIUS, mPaint);  
  100.           
  101.         if (mRecorder != null && mRecorder.state() == Recorder.RECORDING_STATE)  
  102.             postInvalidateDelayed(ANIMATION_INTERVAL);  
  103.     }  
  104. }  

录音类:RecordHelper.java

  1. package org.winplus.sh;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5.   
  6. import android.content.Context;  
  7. import android.media.AudioManager;  
  8. import android.media.MediaPlayer;  
  9. import android.media.MediaRecorder;  
  10. import android.media.MediaPlayer.OnCompletionListener;  
  11. import android.media.MediaPlayer.OnErrorListener;  
  12. import android.os.Bundle;  
  13. import android.os.Environment;  
  14.   
  15. public class RecordHelper implements OnCompletionListener, OnErrorListener {  
  16.     static final String SAMPLE_PREFIX = "recording";  
  17.     static final String SAMPLE_PATH_KEY = "sample_path";  
  18.     static final String SAMPLE_LENGTH_KEY = "sample_length";  
  19.   
  20.     public static final int IDLE_STATE = 0;  
  21.     public static final int RECORDING_STATE = 1;  
  22.     public static final int PLAYING_STATE = 2;  
  23.       
  24.     int mState = IDLE_STATE;  
  25.   
  26.     public static final int NO_ERROR = 0;  
  27.     public static final int SDCARD_ACCESS_ERROR = 1;  
  28.     public static final int INTERNAL_ERROR = 2;  
  29.     public static final int IN_CALL_RECORD_ERROR = 3;  
  30.       
  31.     public interface OnStateChangedListener {  
  32.         public void onStateChanged(int state);  
  33.         public void onError(int error);  
  34.     }  
  35.     OnStateChangedListener mOnStateChangedListener = null;  
  36.       
  37.     long mSampleStart = 0;       // time at which latest record or play operation started   
  38.     int mSampleLength = 0;      // length of current sample   
  39.     File mSampleFile = null;  
  40.       
  41.     MediaRecorder mRecorder = null;  
  42.     MediaPlayer mPlayer = null;  
  43.       
  44.     public RecordHelper() {  
  45.     }  
  46.       
  47.     public void saveState(Bundle recorderState) {  
  48.         recorderState.putString(SAMPLE_PATH_KEY, mSampleFile.getAbsolutePath());  
  49.         recorderState.putInt(SAMPLE_LENGTH_KEY, mSampleLength);  
  50.     }  
  51.       
  52.     public int getMaxAmplitude() {  
  53.         if (mState != RECORDING_STATE)  
  54.             return 0;  
  55.         return mRecorder.getMaxAmplitude();  
  56.     }  
  57.       
  58.     public void restoreState(Bundle recorderState) {  
  59.         String samplePath = recorderState.getString(SAMPLE_PATH_KEY);  
  60.         if (samplePath == null)  
  61.             return;  
  62.         int sampleLength = recorderState.getInt(SAMPLE_LENGTH_KEY, -1);  
  63.         if (sampleLength == -1)  
  64.             return;  
  65.   
  66.         File file = new File(samplePath);  
  67.         if (!file.exists())  
  68.             return;  
  69.         if (mSampleFile != null  
  70.                 && mSampleFile.getAbsolutePath().compareTo(file.getAbsolutePath()) == 0)  
  71.             return;  
  72.           
  73.         delete();  
  74.         mSampleFile = file;  
  75.         mSampleLength = sampleLength;  
  76.   
  77.         signalStateChanged(IDLE_STATE);  
  78.     }  
  79.       
  80.     public void setOnStateChangedListener(OnStateChangedListener listener) {  
  81.         mOnStateChangedListener = listener;  
  82.     }  
  83.       
  84.     public int state() {  
  85.         return mState;  
  86.     }  
  87.       
  88.     public int progress() {  
  89.         if (mState == RECORDING_STATE || mState == PLAYING_STATE)  
  90.             return (int) ((System.currentTimeMillis() - mSampleStart)/1000);  
  91.         return 0;  
  92.     }  
  93.       
  94.     public int sampleLength() {  
  95.         return mSampleLength;  
  96.     }  
  97.   
  98.     public File sampleFile() {  
  99.         return mSampleFile;  
  100.     }  
  101.       
  102.     /** 
  103.      * Resets the recorder state. If a sample was recorded, the file is deleted. 
  104.      */  
  105.     public void delete() {  
  106.         stop();  
  107.           
  108.         if (mSampleFile != null)  
  109.             mSampleFile.delete();  
  110.   
  111.         mSampleFile = null;  
  112.         mSampleLength = 0;  
  113.           
  114.         signalStateChanged(IDLE_STATE);  
  115.     }  
  116.       
  117.     /** 
  118.      * Resets the recorder state. If a sample was recorded, the file is left on disk and will  
  119.      * be reused for a new recording. 
  120.      */  
  121.     public void clear() {  
  122.         stop();  
  123.           
  124.         mSampleLength = 0;  
  125.           
  126.         signalStateChanged(IDLE_STATE);  
  127.     }  
  128.       
  129.     public void startRecording(int outputfileformat, String extension, Context context) {  
  130.         stop();  
  131.           
  132.         if (mSampleFile == null) {  
  133.             File sampleDir = Environment.getExternalStorageDirectory();  
  134.             if (!sampleDir.canWrite()) // Workaround for broken sdcard support on the device.   
  135.                 sampleDir = new File("/sdcard/sdcard");  
  136.               
  137.             try {  
  138.                 mSampleFile = File.createTempFile(SAMPLE_PREFIX, extension, sampleDir);  
  139.             } catch (IOException e) {  
  140.                 setError(SDCARD_ACCESS_ERROR);  
  141.                 return;  
  142.             }  
  143.         }  
  144.           
  145.         mRecorder = new MediaRecorder();  
  146.         mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);  
  147.         mRecorder.setOutputFormat(outputfileformat);  
  148.         mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);  
  149.         mRecorder.setOutputFile(mSampleFile.getAbsolutePath());  
  150.   
  151.         // Handle IOException   
  152.         try {  
  153.             mRecorder.prepare();  
  154.         } catch(IOException exception) {  
  155.             setError(INTERNAL_ERROR);  
  156.             mRecorder.reset();  
  157.             mRecorder.release();  
  158.             mRecorder = null;  
  159.             return;  
  160.         }  
  161.         // Handle RuntimeException if the recording couldn't start   
  162.         try {  
  163.             mRecorder.start();  
  164.         } catch (RuntimeException exception) {  
  165.             AudioManager audioMngr = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);  
  166.             boolean isInCall = ((audioMngr.getMode() == AudioManager.MODE_IN_CALL) ||  
  167.                     (audioMngr.getMode() == AudioManager.MODE_IN_COMMUNICATION));  
  168.             if (isInCall) {  
  169.                 setError(IN_CALL_RECORD_ERROR);  
  170.             } else {  
  171.                 setError(INTERNAL_ERROR);  
  172.             }  
  173.             mRecorder.reset();  
  174.             mRecorder.release();  
  175.             mRecorder = null;  
  176.             return;  
  177.         }  
  178.         mSampleStart = System.currentTimeMillis();  
  179.         setState(RECORDING_STATE);  
  180.     }  
  181.       
  182.     public void stopRecording() {  
  183.         if (mRecorder == null)  
  184.             return;  
  185.   
  186.         mRecorder.stop();  
  187.         mRecorder.release();  
  188.         mRecorder = null;  
  189.   
  190.         mSampleLength = (int)( (System.currentTimeMillis() - mSampleStart)/1000 );  
  191.         setState(IDLE_STATE);  
  192.     }  
  193.       
  194.     public void startPlayback() {  
  195.         stop();  
  196.           
  197.         mPlayer = new MediaPlayer();  
  198.         try {  
  199.             mPlayer.setDataSource(mSampleFile.getAbsolutePath());  
  200.             mPlayer.setOnCompletionListener(this);  
  201.             mPlayer.setOnErrorListener(this);  
  202.             mPlayer.prepare();  
  203.             mPlayer.start();  
  204.         } catch (IllegalArgumentException e) {  
  205.             setError(INTERNAL_ERROR);  
  206.             mPlayer = null;  
  207.             return;  
  208.         } catch (IOException e) {  
  209.             setError(SDCARD_ACCESS_ERROR);  
  210.             mPlayer = null;  
  211.             return;  
  212.         }  
  213.           
  214.         mSampleStart = System.currentTimeMillis();  
  215.         setState(PLAYING_STATE);  
  216.     }  
  217.       
  218.     public void stopPlayback() {  
  219.         if (mPlayer == null// we were not in playback   
  220.             return;  
  221.   
  222.         mPlayer.stop();  
  223.         mPlayer.release();  
  224.         mPlayer = null;  
  225.         setState(IDLE_STATE);  
  226.     }  
  227.       
  228.     public void stop() {  
  229.         stopRecording();  
  230.         stopPlayback();  
  231.     }  
  232.   
  233.     public boolean onError(MediaPlayer mp, int what, int extra) {  
  234.         stop();  
  235.         setError(SDCARD_ACCESS_ERROR);  
  236.         return true;  
  237.     }  
  238.   
  239.     public void onCompletion(MediaPlayer mp) {  
  240.         stop();  
  241.     }  
  242.       
  243.     private void setState(int state) {  
  244.         if (state == mState)  
  245.             return;  
  246.           
  247.         mState = state;  
  248.         signalStateChanged(mState);  
  249.     }  
  250.       
  251.     private void signalStateChanged(int state) {  
  252.         if (mOnStateChangedListener != null)  
  253.             mOnStateChangedListener.onStateChanged(state);  
  254.     }  
  255.       
  256.     private void setError(int error) {  
  257.         if (mOnStateChangedListener != null)  
  258.             mOnStateChangedListener.onError(error);  
  259.     }  
  260. }   

界面:

  1. package org.winplus.sh;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Context;  
  5. import android.media.MediaRecorder;  
  6. import android.os.Bundle;  
  7. import android.os.PowerManager;  
  8. import android.os.PowerManager.WakeLock;  
  9. import android.util.Log;  
  10. import android.view.View;  
  11. import android.view.View.OnClickListener;  
  12. import android.widget.Button;  
  13.   
  14. public class SoundHandActivity extends Activity implements OnClickListener,  
  15.         RecordHelper.OnStateChangedListener {  
  16.   
  17.     private static final String TAG = "SoundHandActivity";  
  18.       
  19.     private VUMeter mVUMeter;  
  20.     private RecordHelper mRecorder;  
  21.   
  22.     private Button btnStart;  
  23.     private Button btnStop;  
  24.   
  25.     WakeLock mWakeLock;  
  26.   
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.main);  
  31.         setupViews();  
  32.     }  
  33.   
  34.     public void setupViews() {  
  35.   
  36.         PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);  
  37.         mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,  
  38.                 "SoundRecorder");  
  39.         mRecorder = new RecordHelper();  
  40.         mRecorder.setOnStateChangedListener(this);  
  41.         mVUMeter = (VUMeter) findViewById(R.id.uvMeter);  
  42.         mVUMeter.setRecorder(mRecorder);  
  43.   
  44.         btnStart = (Button) findViewById(R.id.button1);  
  45.         btnStop = (Button) findViewById(R.id.button2);  
  46.         btnStart.setOnClickListener(this);  
  47.         btnStop.setOnClickListener(this);  
  48.     }  
  49.   
  50.     @Override  
  51.     public void onClick(View v) {  
  52.         switch (v.getId()) {  
  53.         case R.id.button1:  
  54.             mRecorder.startRecording(MediaRecorder.OutputFormat.AMR_NB, ".amr",  
  55.                     this);  
  56.               
  57.             break;  
  58.   
  59.         case R.id.button2:  
  60.             mRecorder.stop();  
  61.             break;  
  62.         }  
  63.     }  
  64.       
  65.     private void updateUi() {  
  66.         Log.e(TAG, "=======================updateUi");  
  67.           
  68.         mVUMeter.invalidate();  
  69.     }  
  70.   
  71.     @Override  
  72.     public void onStateChanged(int state) {  
  73.         if (state == RecordHelper.PLAYING_STATE  
  74.                 || state == RecordHelper.RECORDING_STATE) {  
  75.             mWakeLock.acquire(); // we don't want to go to sleep while recording   
  76.                                     // or playing   
  77.         } else {  
  78.             if (mWakeLock.isHeld())  
  79.                 mWakeLock.release();  
  80.         }  
  81.          updateUi();  
  82.     }  
  83.   
  84.     @Override  
  85.     public void onError(int error) {  
  86.         // TODO Auto-generated method stub   
  87.   
  88.     }  
  89. }

OK,没有什么特别的。

Android录音时指针摆动的实现源码下载

免费下载地址在 http://linux.bkjia.com/

用户名与密码都是www.bkjia.com

具体下载目录在 /2012年资料/5月/13日/Android录音时指针摆动的实现(附源码)/

更多Android相关信息见Android 专题页面 http://www.bkjia.com/topicnews.aspx?tid=11

相关内容