Android錄音

基礎知識

度量聲音強度,大家最熟悉的單位就是分貝(decibel,縮寫爲dB)。這是一個無綱量的相對單位,計算公式如下:

L_p=20 \log_{10}\left(\frac{p_{\mathrm{rms}}}{p_{\mathrm{ref}}}\right)\mbox{ dB}

分子是測量值的聲壓,分母是參考值的聲壓(20微帕,人類所能聽到的最小聲壓)。因此日常中說道聲音強度是多少多少分貝時,都是默認了一個很小的參考值的。

而Android設備傳感器可以提供的物理量是場的幅值(amplitude),常用下列公式計算分貝值:

L_\mathrm{dB} = 10 \log_{10} \bigg(\frac{A_1^2}{A_0^2}\bigg) = 20 \log_{10} \bigg(\frac{A_1}{A_0}\bigg). \,

從SDK中讀取了某段音頻數據的振幅後,取最大振幅或平均振幅(可以用平方和平均,或絕對值的和平均),代入上述公式的A1。

現在問題是,作爲參考值的振幅A0取多少呢?

博主查閱很多帖子、博文,這裏是最一團漿糊的地方。有的博文取600,是基於它視噪音的振幅爲600的假設,此時算出來的是相對背景噪音的分貝值,要是用戶不對麥克風發出聲音,算出的基本都是0分貝。而用戶實際使用場景下的背景噪音大小千差萬別,咱要是也照葫蘆畫瓢就不對了,尤其是對於那些製作絕對分貝計的需求,應找出20微帕聲壓值對應的振幅(或者也可以拿一個標準分貝計做校準參考)。

遵循以往的優良傳統,還是先上代碼吧,下面是佈局activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#EEEEEE" >

    <LinearLayout
        android:id="@+id/record_ll"
        android:layout_width="200dp"
        android:layout_height="33dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="10dp"
        android:background="@drawable/recode_language_bg_nor"
        android:gravity="center"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按住 錄製"
            android:textColor="#777777"
            android:textSize="14sp" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:background="@drawable/record_language_img2" />
    </LinearLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/record_ll"
        android:layout_marginBottom="10dp"
        android:background="#464646" >

        <RelativeLayout
            android:id="@+id/record_center_rel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true" >

            <LinearLayout
                android:id="@+id/record_bg"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:orientation="horizontal" >

                <ImageView
                    android:layout_width="39dp"
                    android:layout_height="70dp"
                    android:background="@drawable/record_language_img" />

                <ImageView
                    android:id="@+id/record_language_intensity_img"
                    android:layout_width="22dp"
                    android:layout_height="49dp"
                    android:layout_marginLeft="10dp"
                    android:layout_marginStart="10dp"
                    android:layout_marginTop="21dp"
                    android:src="@drawable/record_language_bg" />
            </LinearLayout>

            <RelativeLayout
                android:id="@+id/record_language_complete_rel"
                android:layout_width="110dp"
                android:layout_height="110dp"
                android:layout_centerInParent="true"
                android:visibility="gone" >

                <ImageView
                    android:id="@+id/record_language_complete_img"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@drawable/record_language_complete_bg" />

                <ImageView
                    android:id="@+id/record_language_play_img"
                    android:layout_width="30dp"
                    android:layout_height="40dp"
                    android:layout_centerInParent="true"
                    android:background="@drawable/record_language_stop_img" />

            </RelativeLayout>
        </RelativeLayout>
        

        <TextView
            android:id="@+id/record_note_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/record_center_rel"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:text="會員可添加\n最長60秒音頻介紹"
            android:textColor="#ffffff"
            android:textSize="14sp" />
        
        <TextView 
            android:id="@+id/record_language_time_text"
            android:layout_width="50dp"
            android:layout_height="20dp"
            android:background="@drawable/record_language_time_bg"
            android:layout_centerHorizontal="true"
            android:layout_below="@id/record_center_rel"
            android:layout_marginTop="10dp"
            android:textSize="12sp"
            android:textColor="#ffffff"
            android:gravity="center_vertical"
            android:text="0"
            android:paddingLeft="25dp"
            />

    </RelativeLayout>
    
    <TextView 
        android:id="@+id/min_time_length"
        android:layout_width="130dp"
        android:layout_height="30dp"
        android:background="@drawable/record_language_min_time_bg"
        android:text="錄音時長不足2秒"
        android:gravity="center"
        android:textSize="12sp"
        android:textColor="#ffffff"
        android:layout_centerInParent="true"
        android:visibility="visible"
        />

</RelativeLayout>

老規矩,不多說,下面看一下activity的代碼:

package com.example.recordlanguage;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import android.app.Activity;
import android.graphics.Color;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.media.MediaRecorder.OnInfoListener;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.recordlanguage.RecordEngine.RecordListener;
import com.example.recordlanguage.RecordEngine.RecordTimeListener;
import com.example.recordlanguage.RecordEngine.VolumnChangeListener;

/**
 * 語音簡介
 * 
 * @author xiaoyf
 *
 * @createTime 2016年1月26日 下午5:52:58
 */
public class MainActivity extends Activity implements OnClickListener,
		OnTouchListener, RecordListener, OnInfoListener, RecordTimeListener {
	private LinearLayout record_ll;
	private LinearLayout record_bg;
	private ImageView record_language_intensity_img;
	private TextView record_note_text;
	private RelativeLayout record_language_complete_rel;
	private ImageView record_language_complete_img;
	private ImageView record_language_play_img;
	private TextView record_language_time_text;
	private TextView min_time_length;
	/**
	 * 是否正在播放錄音: true:正在播放; false:沒有正在播放的視頻
	 */
	private boolean isPlaying = false;

	private String mLocalRecordFilePath;
	private RecordEngine mRecordEngine;
	/**
	 * 錄音時間是否超時
	 */
	private boolean isRecordTimeOut = false;
	private int delayTime = 1000;
	private Handler mHintHandler = new Handler();
	private Runnable mStopHint = new Runnable() {
		public void run() {
			// 錄音按鈕不可以點擊
			record_ll.setClickable(false);
			record_ll.setPressed(false);
			record_ll.setFocusable(false);
			min_time_length.setVisibility(View.GONE);
			mHintHandler.removeCallbacks(mStopHint);
		}
	};

	private Runnable mStartHint = new Runnable() {
		public void run() {
			mHintHandler.removeCallbacks(mStartHint);
		}
	};
	private Animation animation;
	private MediaPlayer mediaPlayer;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initViews();
	}

	@Override
	protected void onStop() {
		// TODO Auto-generated method stub
		super.onStop();
		if (mRecordEngine != null) {
			mRecordEngine.RecordStop();
			mRecordEngine.RecordDelete();
		}

		if (mediaPlayer != null) {
			mediaPlayer.stop();
			mediaPlayer.release(); 
			mediaPlayer = null;

			isPlaying = false;
			record_language_complete_img.clearAnimation();
			record_language_play_img
					.setBackgroundResource(R.drawable.record_language_stop_img);
		}

	}

	/**
	 * 初始化控件
	 */
	private void initViews() {
		// TODO Auto-generated method stub
		record_ll = (LinearLayout) findViewById(R.id.record_ll);

		record_bg = (LinearLayout) findViewById(R.id.record_bg);
		record_language_intensity_img = (ImageView) findViewById(R.id.record_language_intensity_img);
		record_note_text = (TextView) findViewById(R.id.record_note_text);

		record_language_complete_rel = (RelativeLayout) findViewById(R.id.record_language_complete_rel);
		record_language_complete_img = (ImageView) findViewById(R.id.record_language_complete_img);
		record_language_play_img = (ImageView) findViewById(R.id.record_language_play_img);
		record_language_time_text = (TextView) findViewById(R.id.record_language_time_text);

		min_time_length = (TextView) findViewById(R.id.min_time_length);

		setVisibility();
		record_bg.setVisibility(View.VISIBLE);
		record_note_text.setVisibility(View.VISIBLE);

		record_language_play_img.setOnClickListener(this);
		record_ll.setOnTouchListener(this);

	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.record_language_play_img:// 播放或暫停錄音
			if (isPlaying) {// 正在播放
				record_language_play_img
						.setBackgroundResource(R.drawable.record_language_stop_img);
				isPlaying = false;
				record_language_complete_img.clearAnimation();
				if (mediaPlayer != null) {
					mediaPlayer.stop();
					mediaPlayer.release();
					mediaPlayer = null;
				}
			} else {// 沒有正在播放
				record_language_play_img
						.setBackgroundResource(R.drawable.record_language_play_img);
				isPlaying = true;
				if (animation == null) {
					animation = AnimationUtils.loadAnimation(this,
							R.anim.record_language_play_anim);
					animation.setInterpolator(new LinearInterpolator());// 不停頓
				}
				record_language_complete_img.startAnimation(animation);
				mediaPlayer();

			}

			break;

		default:
			break;
		}
	}

	/**
	 * 播放語音簡介
	 */
	private void mediaPlayer() {
		// TODO Auto-generated method stub
		try {
			if (mediaPlayer == null)
				mediaPlayer = new MediaPlayer();
			boolean isPlay = false;
			try {
				isPlay = mediaPlayer.isPlaying();
			} catch (Exception e) {
				// TODO: handle exception
			}
			if (isPlay) {
				mediaPlayer.reset();// 重置爲初始狀態
			}
			try {
				transferFile(mLocalRecordFilePath + "tmp", mLocalRecordFilePath);
			} catch (IOException e) {
				e.printStackTrace();
			}
			mediaPlayer.setDataSource(mLocalRecordFilePath);
			mediaPlayer.prepare();// 緩衝
			mediaPlayer.start();// 開始
			mediaPlayer
					.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {// 播出完畢事件
						@Override
						public void onCompletion(MediaPlayer arg0) {
							mediaPlayer.stop();
							mediaPlayer.release();// 釋放資源
							mediaPlayer = null;

							isPlaying = false;
							record_language_complete_img.clearAnimation();
							record_language_play_img
									.setBackgroundResource(R.drawable.record_language_stop_img);
						}
					});
			mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {// 錯誤處理事件
						@Override
						public boolean onError(MediaPlayer player, int arg1,
								int arg2) {
							mediaPlayer.stop();
							mediaPlayer.release();// 釋放資源
							mediaPlayer = null;

							Toast.makeText(getApplicationContext(), "語音播放有誤",
									Toast.LENGTH_LONG).show();
							isPlaying = false;
							record_language_complete_img.clearAnimation();
							record_language_play_img
									.setBackgroundResource(R.drawable.record_language_stop_img);
							return false;
						}
					});

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			boolean isPlay = false;
			try {
				isPlay = mediaPlayer.isPlaying();
			} catch (Exception e2) {
				// TODO: handle exception
			}
			if (isPlay) {
				mediaPlayer.stop();
				mediaPlayer.release();// 釋放資源
				mediaPlayer = null;
			}
			Toast.makeText(getApplicationContext(), "語音播放有誤", Toast.LENGTH_LONG)
					.show();
			isPlaying = false;
			record_language_complete_img.clearAnimation();
			record_language_play_img
					.setBackgroundResource(R.drawable.record_language_stop_img);

		}
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.record_ll:// 錄音
			recordLanguage(event);
			break;
		default:
			break;
		}

		return true;
	}

	/**
	 * 開始錄音
	 * 
	 * @param event
	 */
	private boolean recordLanguage(MotionEvent event) {
		// TODO Auto-generated method stub
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			boolean isPlay = false;
			try {
				if (mediaPlayer != null)
					isPlay = mediaPlayer.isPlaying();
			} catch (Exception e2) {
				// TODO: handle exception
			}
			if (isPlay) {
				mediaPlayer.stop();
				mediaPlayer.release();// 釋放資源
				mediaPlayer = null;
				isPlaying = false;
				record_language_complete_img.clearAnimation();
				record_language_play_img
						.setBackgroundResource(R.drawable.record_language_stop_img);
			}

			try {
				initVoiceModel();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
				return false;
			}

			isRecordTimeOut = false;

			try {
				startRecord();
			} catch (Exception e) {
				mRecordEngine.RecordStop();
				mRecordEngine.RecordDelete();
				e.printStackTrace();
				Toast.makeText(getApplicationContext(), "語音模塊初始化失敗,請重試!",
						Toast.LENGTH_LONG).show();
				break;
			}
			// 提示框顯示: 正在錄音...
			mHintHandler.removeCallbacks(mStopHint);
			mHintHandler.post(mStartHint);
			setVisibility();
			record_bg.setVisibility(View.VISIBLE);
			record_language_time_text.setVisibility(View.VISIBLE);
			record_language_time_text.setText("0");
			record_language_time_text.setTextColor(0xffffffff);
			record_ll.setBackgroundResource(R.drawable.recode_language_bg_sel);

			break;
		case MotionEvent.ACTION_UP:
			// Log.d("bbb", "擡起 MotionEvent.ACTION_UP");
			record_language_intensity_img.getDrawable().setLevel(0);
			record_ll.setBackgroundResource(R.drawable.recode_language_bg_nor);
			if (!mRecordEngine.ismRecording()) {
				return false;
			}
			mRecordEngine.RecordStop();
			// 錄音結束處理
			long recordTime = mRecordEngine.getRecordTime();
			if (recordTime < 2000) {
				setVisibility();
				record_bg.setVisibility(View.VISIBLE);
				record_language_time_text.setVisibility(View.VISIBLE);
				min_time_length.setVisibility(View.VISIBLE);
				mHintHandler.postDelayed(mStopHint, delayTime);
				return false;
			} else if (!isRecordTimeOut) {
				setVisibility();
				record_language_complete_rel.setVisibility(View.VISIBLE);
				record_language_time_text.setVisibility(View.VISIBLE);

			}
			break;
		case MotionEvent.ACTION_CANCEL:// 當權限訪問的時候,彈起權限問詢框的時候會調用
			record_ll.setBackgroundResource(R.drawable.recode_language_bg_nor);
			if (!mRecordEngine.ismRecording()) {
				return false;
			}
			mRecordEngine.RecordStop();
			mRecordEngine.RecordDelete();
			setVisibility();
			record_bg.setVisibility(View.VISIBLE);
			record_note_text.setVisibility(View.VISIBLE);

			break;
		case MotionEvent.ACTION_MOVE:
			break;

		default:
			break;
		}

		return true;

	}

	private void setVisibility() {
		record_bg.setVisibility(View.GONE);
		record_note_text.setVisibility(View.GONE);

		record_language_complete_rel.setVisibility(View.GONE);
		record_language_time_text.setVisibility(View.GONE);

		min_time_length.setVisibility(View.GONE);

	}

	public boolean pointInView(View view, float localX, float localY) {
		return localX >= 0 && localX < (view.getRight() - view.getLeft())
				&& localY >= 0 && localY < (view.getBottom() - view.getTop());
	}

	/**
	 * 初始化語音模塊
	 * 
	 * @throws FileNotFoundException
	 */
	private void initVoiceModel() throws FileNotFoundException {
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			mLocalRecordFilePath = Environment.getExternalStorageDirectory()
					.getAbsolutePath()
					+ "/record_voice_"
					+ System.currentTimeMillis() + ".amr";
			mRecordEngine = new RecordEngine(new File(mLocalRecordFilePath
					+ "tmp"), this);
			mRecordEngine.setRecordListener(this);
			mRecordEngine.setInfoListener(this);
			mRecordEngine.setRecordTimeListener(this);

		}
	}

	/**
	 * 語音錄製
	 * 
	 * @throws IllegalStateException
	 * @throws IOException
	 * @throws RuntimeException
	 */
	private void startRecord() throws IllegalStateException, IOException,
			RuntimeException {
		// 註冊音量變化偵聽器
		mRecordEngine.SetVolumnChangeListener(new VolumnChangeListener() {
			@Override
			public void change(int level) {
				record_language_intensity_img.getDrawable().setLevel(level);
			}
		});
		// 開始錄音
		mRecordEngine.RecordStart();
	}

	@Override
	public void onInfo(MediaRecorder mr, int what, int extra) {
		// TODO Auto-generated method stub
		if (what >= MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
			mRecordEngine.RecordStop();
			setVisibility();
			record_language_complete_rel.setVisibility(View.VISIBLE);
			record_language_time_text.setVisibility(View.VISIBLE);
			isRecordTimeOut = true;
			mHintHandler.post(mStopHint);
			record_language_time_text.setText("60");
			record_language_time_text.setTextColor(Color.RED);
			Toast.makeText(getApplicationContext(), "對不起,最長錄音60秒!",
					Toast.LENGTH_LONG).show();
		}
	}

	@Override
	public void onPrepare() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onComplated() {
		// TODO Auto-generated method stub

	}

	@Override
	public void refresh(long time) {
		// TODO Auto-generated method stub
		long recordTime = (time + 500) / 1000;
		if (recordTime <= 50) {
			record_language_time_text.setText(recordTime + "");
			record_language_time_text.setTextColor(0xffffffff);
		} else if (recordTime > 50 && recordTime <= 60) {
			record_language_time_text.setText(recordTime + "");
			record_language_time_text.setTextColor(Color.RED);
		} else {
			mRecordEngine.RecordStop();
			setVisibility();
			record_language_complete_rel.setVisibility(View.VISIBLE);
			record_language_time_text.setVisibility(View.VISIBLE);
			isRecordTimeOut = true;
			mHintHandler.post(mStopHint);
		}

	}

	/**
	 * 通過管道快速複製文件
	 * 
	 * @param srcFile
	 * @param dstFile
	 * @throws IOException
	 */
	public static void transferFile(String srcFile, String dstFile)
			throws IOException {
		FileInputStream fin = new FileInputStream(srcFile);
		FileOutputStream fout = new FileOutputStream(dstFile);
		FileChannel fcin = fin.getChannel();
		FileChannel fcout = fout.getChannel();
		ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配1KB作爲緩衝區

		while (true) {
			buffer.clear(); // 每次使用必須置空緩衝區
			int r = fcin.read(buffer);
			if (r == -1) {
				break;
			}
			buffer.flip(); // 寫入前使用flip這個方法
			fcout.write(buffer);
		}
	}

}

其實這個activity也沒有過多要強調的,唯一的一點就是,當我們第一次使用這個demo進行錄音,我們按下按鈕開始錄音的時候,Android系統會彈起一個權限問詢彈框,這個時候系統會回調我們寫的ontouch()方法,其中的action是Action_Cancle,這個時候,我們需要在裏面做一些基本的處理。

下面我們來看看這個項目的核心代碼:

package com.example.recordlanguage;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import android.app.Service;
import android.content.Context;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.media.MediaRecorder.OnInfoListener;
import android.os.Handler;
import android.util.Log;

/**
 * 錄音的工具類
 * 
 * @author xiaoyf
 *
 * @createTime 2016年1月27日 下午3:54:42
 */
public class RecordEngine {
	final int MIN_AMPLITUDE_VALUE = 800; // 錄音程序可以識別的最小聲音振幅
	final int MAX_AMPLITUDE_VALUE = 32000;// 最大值有人說[32767]; // 錄音程序可以識別的最大聲音振幅
	final int VOLUMN_LEVEL_MAX = 7; // 音量分成7級
	final int ampPerLevel = (MAX_AMPLITUDE_VALUE - MIN_AMPLITUDE_VALUE)
			/ VOLUMN_LEVEL_MAX;
	private int mVolumnLevel = 0;

	private File mRecordFile = null;
	private MediaRecorder mMediaRecorder;
	private MediaPlayer mMediaPlayer = null;
	private boolean mRecording = false;
	private VolumnChangeListener mVolumnChangeListener;
	private OnInfoListener mInfoListener;
	private RecordTimeListener recordTimeListener;
	private AudioManager audioManager;
	private RecordListener listener;

	private Context context;

	// 錄音音量變化偵聽接口
	public interface VolumnChangeListener {
		public void change(int level);
	}

	public void SetVolumnChangeListener(VolumnChangeListener listener) {
		mVolumnChangeListener = listener;
	}

	public void setInfoListener(OnInfoListener mInfoListener) {
		this.mInfoListener = mInfoListener;
	}

	public interface RecordTimeListener {
		void refresh(long time);
	}

	public void setRecordTimeListener(RecordTimeListener listener) {
		recordTimeListener = listener;
	}

	/**
	 * 根據頻率計算音量級別
	 * 
	 * @return 音量級別
	 */
	private int CaculateVolumnLevel() {
		int ratio = mMediaRecorder.getMaxAmplitude() / 600;
		int db = 0;// 分貝
		if (ratio > 1)
			db = (int) (20 * Math.log10(ratio));
		db /= 4;
		db = Math.min(db, 10);
		return db;
	}

	// 錄音定時器,更新狀態
	private int mTimingDelay = 100;
	private long mRecordTime = 0;
	Handler timingHandler = new Handler();
	/**
	 * 更新音量級別
	 */
	Runnable timingRunnable = new Runnable() {
		public void run() {
			int newLevel = CaculateVolumnLevel();
			if (mVolumnLevel != newLevel) {
				mVolumnLevel = newLevel;
				if (mVolumnChangeListener != null)
					mVolumnChangeListener.change(mVolumnLevel);
			}

			// 循環啓動定時器
			timingHandler.postDelayed(timingRunnable, mTimingDelay);
		}
	};
	/**
	 * 記錄錄音的時間
	 */
	Runnable recordTimeRunnable = new Runnable() {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			if (recordTimeListener != null) {
				long time = System.currentTimeMillis() - mRecordTime;
				recordTimeListener.refresh(time);
				// 循環啓動定時器
				timingHandler.postDelayed(recordTimeRunnable, 950);
			}
		}
	};

	private void startTiming() {
		mRecordTime = System.currentTimeMillis() + 800L;
		timingHandler.postDelayed(timingRunnable, mTimingDelay);
		timingHandler.postDelayed(recordTimeRunnable, 950);
	}

	private void stopTiming() {
		mRecordTime = System.currentTimeMillis() - mRecordTime;
		timingHandler.removeCallbacks(timingRunnable);
		timingHandler.removeCallbacks(recordTimeRunnable);
	}

	/**
	 * 獲取本次錄音時間長度
	 * 
	 * @return
	 */
	public long getRecordTime() {
		return mRecordTime;
	}

	public RecordEngine(Context mContext) throws FileNotFoundException {
		this(null, mContext);
		this.context = mContext;
	}

	public RecordEngine(File recordFile, Context mContext)
			throws FileNotFoundException {
		if (recordFile != null) {
			File dir = recordFile.getParentFile();
			if (!dir.exists()) {
				dir.mkdirs();
			}

			// 創建文件
			if (!recordFile.exists()) {
				try {
					recordFile.createNewFile();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		mRecordFile = recordFile;
		mRecordTime = System.currentTimeMillis();
		audioManager = (AudioManager) mContext
				.getSystemService(Service.AUDIO_SERVICE);
	}

	public void setRecordListener(RecordListener listener) {
		this.listener = listener;
	}

	/* 錄音 */
	public void RecordStart() throws IllegalStateException, IOException,
			RuntimeException {
		if (listener != null) {
			listener.onPrepare();
		}
		mMediaRecorder = new MediaRecorder();
		startTiming();
		// AudioRecord audioRecord=new AudioRecord(audioSource, sampleRateInHz,
		// channelConfig, audioFormat, bufferSizeInBytes)
		mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 聲源
		// 設置音頻文件的編碼:AAC/AMR_NB/AMR_MB/Default
		mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
		mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 編碼
		mMediaRecorder.setAudioEncodingBitRate(4000);// 比特率
		// mMediaRecorder.setAudioSamplingRate(4000);// 採樣率
		mMediaRecorder.setAudioChannels(1);// 單聲道
		mMediaRecorder.setOnInfoListener(mInfoListener);
		mMediaRecorder.setOutputFile(mRecordFile.getAbsolutePath());
		mMediaRecorder.setMaxDuration(60 * 1000);
		mMediaRecorder.prepare();
		mMediaRecorder.start();
		mRecording = true;
	}

	public void RecordStop() {
		if (mRecordFile != null) {
			if (mMediaRecorder != null) {
				try {
					mMediaRecorder.stop();
					mMediaRecorder.release();
					mMediaRecorder = null;
				} catch (IllegalStateException e) {
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			mRecording = false;
			stopTiming();
		}
		if (listener != null) {
			listener.onComplated();
		}
		listener = null;
	}

	public void RecordPlay(Context mContext) throws IllegalArgumentException,
			SecurityException, IllegalStateException, IOException {
		// FileInputStream audioFileStream = new FileInputStream(mRecordFile);
		if (mRecordFile == null) {
		} else {
			mMediaPlayer = new MediaPlayer();
			// mMediaPlayer = MediaPlayer.create(mContext,
			// Uri.fromFile(mRecordFile));
			// mMediaPlayer = new MediaPlayer();
			mMediaPlayer.setDataSource(mRecordFile.getAbsolutePath());
			mMediaPlayer.prepare();
			mMediaPlayer.start();
		}
	}

	public int getSuitedVolume(int streamType) {
		int volume = 10;
		if (audioManager != null) {
			int currentVolume = audioManager.getStreamVolume(streamType);
			int tmpVolume = (int) (audioManager.getStreamMaxVolume(streamType) * 0.6);
			// 確保音量至少爲60%
			volume = currentVolume >= tmpVolume ? currentVolume
					: (tmpVolume > volume ? tmpVolume : volume);
		}
		return volume;
	}

	public void RecordPlayStop() {
		if (mMediaPlayer != null) {
			mMediaPlayer.stop();
			mMediaPlayer.release();
			mMediaPlayer = null;
		}
	}

	/**
	 * 設置播放音量
	 * 
	 * @param volume
	 *            音量,如果設置爲-1則設置爲當前系統音量
	 * */
	public void setRecordPlayerVolume(int volume) {
		if (audioManager != null) {
			volume = volume == -1 ? audioManager
					.getStreamVolume(AudioManager.STREAM_MUSIC) : volume;
			audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
					volume, AudioManager.FLAG_PLAY_SOUND);
		}
	}

	public String RecordGetPath() {
		String path = mRecordFile.getPath();
		return path;
	}

	public void RecordDelete() {
		if (mRecordFile != null) {
			if (mRecordFile.exists())
				mRecordFile.delete();
		}
	}

	public MediaPlayer getMediaPlayer() {
		return mMediaPlayer;
	}

	public boolean ismRecording() {
		return mRecording;
	}

	public interface RecordListener {
		public void onPrepare();

		public void onComplated();
	}
}

這個核心方法裏面會包含一些,對錄音硬件的基本的設置、以及一些回調方法,用來監聽音量的變化、錄音開始和結束、錄音時間

基本到這裏就結束啦,我再給大家分享一篇很不錯的獲取錄音分貝的文章:http://blog.csdn.net/greatpresident/article/details/38402147


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章