转自:http://blog.csdn.net/tangcheng_ok/article/details/7561822 <请尊重作者的劳动成果>
文中的代码主要是移植SoundRecorder的。主要是其中的VUMeter类,VUMeter是通过Recorder.getMaxAmplitude()的值计算,画出指针的偏移摆动。下面直接上代码:
<span style="font-size:16px;">/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.soundrecorder; 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; Recorder 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.vumeter); 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(Recorder 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 && mRecorder.state() == Recorder.RECORDING_STATE) postInvalidateDelayed(ANIMATION_INTERVAL); } } </span> 录音类:RecordHelper.java [java] view plaincopy <span style="font-size:16px;">package org.winplus.sh; import java.io.File; import java.io.IOException; import android.content.Context; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.os.Bundle; import android.os.Environment; public class RecordHelper implements OnCompletionListener, OnErrorListener { static final String SAMPLE_PREFIX = "recording"; static final String SAMPLE_PATH_KEY = "sample_path"; static final String SAMPLE_LENGTH_KEY = "sample_length"; public static final int IDLE_STATE = 0; public static final int RECORDING_STATE = 1; public static final int PLAYING_STATE = 2; 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 static final int IN_CALL_RECORD_ERROR = 3; public interface OnStateChangedListener { public void onStateChanged(int state); public void onError(int error); } OnStateChangedListener mOnStateChangedListener = null; long mSampleStart = 0; // time at which latest record or play operation started int mSampleLength = 0; // length of current sample File mSampleFile = null; MediaRecorder mRecorder = null; MediaPlayer mPlayer = null; public RecordHelper() { } public void saveState(Bundle recorderState) { recorderState.putString(SAMPLE_PATH_KEY, mSampleFile.getAbsolutePath()); recorderState.putInt(SAMPLE_LENGTH_KEY, mSampleLength); } public int getMaxAmplitude() { if (mState != RECORDING_STATE) return 0; return mRecorder.getMaxAmplitude(); } public void restoreState(Bundle recorderState) { String samplePath = recorderState.getString(SAMPLE_PATH_KEY); if (samplePath == null) return; int sampleLength = recorderState.getInt(SAMPLE_LENGTH_KEY, -1); if (sampleLength == -1) return; File file = new File(samplePath); if (!file.exists()) return; if (mSampleFile != null && mSampleFile.getAbsolutePath().compareTo(file.getAbsolutePath()) == 0) return; delete(); mSampleFile = file; mSampleLength = sampleLength; signalStateChanged(IDLE_STATE); } public void setOnStateChangedListener(OnStateChangedListener listener) { mOnStateChangedListener = listener; } public int state() { return mState; } public int progress() { if (mState == RECORDING_STATE || mState == PLAYING_STATE) return (int) ((System.currentTimeMillis() - mSampleStart)/1000); return 0; } public int sampleLength() { return mSampleLength; } public File sampleFile() { return mSampleFile; } /** * Resets the recorder state. If a sample was recorded, the file is deleted. */ public void delete() { stop(); if (mSampleFile != null) mSampleFile.delete(); mSampleFile = null; mSampleLength = 0; signalStateChanged(IDLE_STATE); } /** * Resets the recorder state. If a sample was recorded, the file is left on disk and will * be reused for a new recording. */ public void clear() { stop(); mSampleLength = 0; signalStateChanged(IDLE_STATE); } public void startRecording(int outputfileformat, String extension, Context context) { stop(); if (mSampleFile == null) { File sampleDir = Environment.getExternalStorageDirectory(); if (!sampleDir.canWrite()) // Workaround for broken sdcard support on the device. sampleDir = new File("/sdcard/sdcard"); try { mSampleFile = File.createTempFile(SAMPLE_PREFIX, extension, sampleDir); } catch (IOException e) { setError(SDCARD_ACCESS_ERROR); return; } } mRecorder = new MediaRecorder(); mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mRecorder.setOutputFormat(outputfileformat); mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); mRecorder.setOutputFile(mSampleFile.getAbsolutePath()); // Handle IOException try { mRecorder.prepare(); } catch(IOException exception) { setError(INTERNAL_ERROR); mRecorder.reset(); mRecorder.release(); mRecorder = null; return; } // Handle RuntimeException if the recording couldn't start try { mRecorder.start(); } catch (RuntimeException exception) { AudioManager audioMngr = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); boolean isInCall = ((audioMngr.getMode() == AudioManager.MODE_IN_CALL) || (audioMngr.getMode() == AudioManager.MODE_IN_COMMUNICATION)); if (isInCall) { setError(IN_CALL_RECORD_ERROR); } else { setError(INTERNAL_ERROR); } mRecorder.reset(); mRecorder.release(); mRecorder = null; return; } mSampleStart = System.currentTimeMillis(); setState(RECORDING_STATE); } public void stopRecording() { if (mRecorder == null) return; mRecorder.stop(); mRecorder.release(); mRecorder = null; mSampleLength = (int)( (System.currentTimeMillis() - mSampleStart)/1000 ); setState(IDLE_STATE); } public void startPlayback() { stop(); mPlayer = new MediaPlayer(); try { mPlayer.setDataSource(mSampleFile.getAbsolutePath()); mPlayer.setOnCompletionListener(this); mPlayer.setOnErrorListener(this); mPlayer.prepare(); mPlayer.start(); } catch (IllegalArgumentException e) { setError(INTERNAL_ERROR); mPlayer = null; return; } catch (IOException e) { setError(SDCARD_ACCESS_ERROR); mPlayer = null; return; } mSampleStart = System.currentTimeMillis(); setState(PLAYING_STATE); } public void stopPlayback() { if (mPlayer == null) // we were not in playback return; mPlayer.stop(); mPlayer.release(); mPlayer = null; setState(IDLE_STATE); } public void stop() { stopRecording(); stopPlayback(); } public boolean onError(MediaPlayer mp, int what, int extra) { stop(); setError(SDCARD_ACCESS_ERROR); return true; } public void onCompletion(MediaPlayer mp) { stop(); } private void setState(int state) { if (state == mState) return; mState = state; signalStateChanged(mState); } private void signalStateChanged(int state) { if (mOnStateChangedListener != null) mOnStateChangedListener.onStateChanged(state); } private void setError(int error) { if (mOnStateChangedListener != null) mOnStateChangedListener.onError(error); } } </span>
<span style="font-size:16px;">package org.winplus.sh; import android.app.Activity; import android.content.Context; import android.media.MediaRecorder; import android.os.Bundle; 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.Button; public class SoundHandActivity extends Activity implements OnClickListener, RecordHelper.OnStateChangedListener { private static final String TAG = "SoundHandActivity"; private VUMeter mVUMeter; private RecordHelper mRecorder; private Button btnStart; private Button btnStop; WakeLock mWakeLock; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); setupViews(); } public void setupViews() { PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "SoundRecorder"); mRecorder = new RecordHelper(); mRecorder.setOnStateChangedListener(this); mVUMeter = (VUMeter) findViewById(R.id.uvMeter); mVUMeter.setRecorder(mRecorder); btnStart = (Button) findViewById(R.id.button1); btnStop = (Button) findViewById(R.id.button2); btnStart.setOnClickListener(this); btnStop.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button1: mRecorder.startRecording(MediaRecorder.OutputFormat.AMR_NB, ".amr", this); break; case R.id.button2: mRecorder.stop(); break; } } private void updateUi() { Log.e(TAG, "=======================updateUi"); mVUMeter.invalidate(); } @Override public void onStateChanged(int state) { if (state == RecordHelper.PLAYING_STATE || state == RecordHelper.RECORDING_STATE) { mWakeLock.acquire(); // we don't want to go to sleep while recording // or playing } else { if (mWakeLock.isHeld()) mWakeLock.release(); } updateUi(); } @Override public void onError(int error) { // TODO Auto-generated method stub } }</span>