Android录音时指针摆动的实现(附源码)
16lz
2021-01-26
文中的代码主要是移植SoundRecorder的。主要是其中的VUMeter类,VUMeter是通过Recorder.getMaxAmplitude()的值计算,画出指针的偏移摆动。下面直接上代码
/* * 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); }}
录音类:RecordHelper.java
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); }}
界面:
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;@Overridepublic 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);}@Overridepublic 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();}@Overridepublic 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();}@Overridepublic void onError(int error) {// TODO Auto-generated method stub}}
OK,没有什么特别的。 源码下载==》
原创文章转载请注明出处:http://www.blog.csdn.net/tangcheng_ok
更多相关文章
- Android(安卓)Service在bindService不能触发onServiceConnected
- Android用第三方jar包ClassNotFoundException:XXX in loader dal
- Android(安卓)Studio使用---眼花缭乱的插件使用技巧
- Android(安卓)代码控制手机数据网络的开关(5.0以上)
- android jni开发流程
- asmack杂记
- Webview里JS跳转到Activity页面
- Android(安卓)Lifecycle
- Android(安卓)4.0后,自定义Title报错 You cannot combine custom