長(zhǎng)按按鈕后退出,報(bào)錯(cuò)setAudioSource failed.
public class AudioManager {
? ?private MediaRecorder mMediaRecorder;
? ?private String mDir;
? ?private String mCurrentFilePath;
? ?private boolean isPrepared;
? ?private static AudioManager mInstance;
? ?private AudioManager(String dir) {
? ? ? ?this.mDir = dir;
? ?}
? ?/*
? ?* 回調(diào)準(zhǔn)備完畢
? ?* */
? ?public interface AudioStateListener{
? ? ? ?void wellPrepared();
? ?}
? ?public AudioStateListener mListener;
? ?public void setOnAudioStateListener(AudioStateListener listener){
? ? ? ?this.mListener = listener;
? ?}
? ?// ?單例設(shè)計(jì)模式,保證對(duì)象唯一性
? ?public static AudioManager getInstance(String dir) {
? ? ? ?if (mInstance == null) {
? ? ? ? ? ?synchronized (AudioManager.class) { ?// 同步
? ? ? ? ? ? ? ?if (mInstance == null) {
? ? ? ? ? ? ? ? ? ?mInstance = new AudioManager(dir);
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?return mInstance;
? ?}
? ?// 準(zhǔn)備
? ?public void prepareAudio(){
? ? ? ?try {
? ? ? ? ? ?isPrepared = false;
? ? ? ? ? ?File dir = new File( mDir );
? ? ? ? ? ?if(dir.exists()){
? ? ? ? ? ? ? ?dir.mkdirs();
? ? ? ? ? ?}
? ? ? ? ? ?String fileName = generateFileName();
? ? ? ? ? ?File file = new File( dir, fileName);
? ? ? ? ? ?mCurrentFilePath =file.getAbsolutePath();
? ? ? ? ? ?mMediaRecorder = new MediaRecorder();
? ? ? ? ? ?// 設(shè)置輸出文件
? ? ? ? ? ?mMediaRecorder.setOutputFile( file.getAbsolutePath() );
? ? ? ? ? ?// 設(shè)置MediaRecorder的音頻源為麥克風(fēng)
? ? ? ? ? ?mMediaRecorder.setAudioSource( MediaRecorder.AudioSource.MIC );
? ? ? ? ? ?// 設(shè)置音頻的格式
? ? ? ? ? ?mMediaRecorder.setOutputFormat( MediaRecorder.OutputFormat.AMR_NB );
? ? ? ? ? ?// 設(shè)置音頻的編碼為amr
? ? ? ? ? ?mMediaRecorder.setAudioEncoder( MediaRecorder.AudioEncoder.AMR_NB );
? ? ? ? ? ?mMediaRecorder.prepare();
? ? ? ? ? ?mMediaRecorder.start(); ? ?// 可以開始錄制了
? ? ? ? ? ?// 準(zhǔn)備結(jié)束
? ? ? ? ? ?isPrepared = true;
? ? ? ? ? ?if (mListener != null){
? ? ? ? ? ? ? ?mListener.wellPrepared();
? ? ? ? ? ?}
? ? ? ?} catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? ?}
? ?}
? ?// 隨機(jī)生成文件的名稱
? ?private String generateFileName() {
? ? ? ?return UUID.randomUUID().toString()+".amr";
? ?}
? ?// 獲取voice等級(jí)
? ?public int getVoiceLevel(int maxLevel){
? ? ? ?if (isPrepared){
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?// mMediaRecorder.getMaxAmplitude()的值為 1-32768
? ? ? ? ? ? ? ?return maxLevel * mMediaRecorder.getMaxAmplitude() / 32768 + 1;
? ? ? ? ? ?}catch (Exception e){
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?return 1;
? ?}
? ?// 釋放
? ?public void release(){
? ? ? ?mMediaRecorder.stop();
? ? ? ?mMediaRecorder.reset();
? ? ? ?mMediaRecorder = null;
? ?}
? ?// 取消
? ?public void cancel(){
? ? ? ?release();
? ? ? ?if (mCurrentFilePath != null){
? ? ? ? ? ?File file = new File( mCurrentFilePath );
? ? ? ? ? ?file.delete();
? ? ? ? ? ?mCurrentFilePath = null;
? ? ? ?}
? ?}
? ?public String getCurrentFilePath() {
? ? ? ?return mCurrentFilePath;
? ?}
————————————————————————————————————————————
public class RecorderBtn extends Button implements AudioManager.AudioStateListener {
? ?private static final int STATE_NORMAL = 1; ? ? ? ? // 默認(rèn)狀態(tài)
? ?private static final int STATE_RECORDING = 2; ? ? ?// 開始錄音
? ?private static final int STATE_WANT_TO_CANCEL = 3; // 取消錄音
? ?private static final int DISTANCE_Y_CANCEL = 50; ? // 根據(jù)坐標(biāo)改變dialog
? ?private int mCurState = STATE_NORMAL; // 當(dāng)前默認(rèn)狀態(tài)
? ?private RecorderDialog mDialog; ?// 創(chuàng)建dialog對(duì)象
? ?private boolean isRecording = false; ? ? // 已經(jīng)開始錄音
? ?private AudioManager mAudioManager;
? ?private float mTime; ? // 用于計(jì)時(shí)
? ?private boolean mReady; // 是否出發(fā)longclick
? ?/*
? ?* 獲取音量大小的Runnble
? ?* */
? ?private Runnable mGetVoiceLevelRunnble = new Runnable() {
? ? ? ?@Override
? ? ? ?public void run() {
? ? ? ? ? ?while (isRecording){
? ? ? ? ? ? ? ?try {
? ? ? ? ? ? ? ? ? ?Thread.sleep( 100 );
? ? ? ? ? ? ? ? ? ?mTime += 0.1f;
? ? ? ? ? ? ? ? ? ?mHandler.sendEmptyMessage( MSG_VOICE_CHANGED );
? ? ? ? ? ? ? ?} catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ? }
? ?};
? ?public RecorderBtn(Context context) {
? ? ? ?this( context, null );
? ?}
? ?// 初始化按鈕和按鈕的長(zhǎng)按事件
? ?public RecorderBtn(Context context, AttributeSet attrs) {
? ? ? ?super( context, attrs );
? ? ? ?mDialog = new RecorderDialog( getContext() );
? ? ? ?String dir = Environment.getExternalStorageDirectory()+"/recorder_audios";
? ? ? ?mAudioManager = AudioManager.getInstance(dir);
? ? ? ?mAudioManager.setOnAudioStateListener( ?this );
? ? ? ?setOnLongClickListener( new OnLongClickListener() {
? ? ? ? ? ?@Override
? ? ? ? ? ?public boolean onLongClick(View view) {
? ? ? ? ? ? ? ?mReady = true;
? ? ? ? ? ? ? ?mAudioManager.prepareAudio();
? ? ? ? ? ? ? ?return false;
? ? ? ? ? ?}
? ? ? ?} );
? ?}
? ?/*
? ?* 錄音完成后的回調(diào)
? ?* */
? ?public interface AudioFinishRecorderListener{
? ? ? ?void onFinish(float seconds,String filePath);
? ?}
? ?private AudioFinishRecorderListener mListener;
? ?public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener) {
? ? ? ?this.mListener = listener;
? ?}
? ?private static final int MSG_AUDIO_PREPARED = 001;
? ?private static final int MSG_VOICE_CHANGED = 002;
? ?private static final int MSG_DIALOG_DIMISS = 003;
? ?private static final int VOICE_LEVEL = 7;
? ?private Handler mHandler = new Handler( ?){
? ? ? ?@Override
? ? ? ?public void handleMessage(Message msg) {
? ? ? ? ? ?switch (msg.what){
? ? ? ? ? ? ? ?case MSG_AUDIO_PREPARED:
? ? ? ? ? ? ? ? ? ?// 真正顯示在音頻結(jié)束準(zhǔn)備之后
? ? ? ? ? ? ? ? ? ?mDialog.shouRecordingDialog();
? ? ? ? ? ? ? ? ? ?isRecording = true;
? ? ? ? ? ? ? ? ? ?// 開啟線程
? ? ? ? ? ? ? ? ? ?new Thread( mGetVoiceLevelRunnble ).start();
? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ?case MSG_VOICE_CHANGED:
? ? ? ? ? ? ? ? ? ?mDialog.updateVoiveLevel( mAudioManager.getVoiceLevel( VOICE_LEVEL ) );
? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ?case MSG_DIALOG_DIMISS:
? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ?}
? ? ? ? ? ?super.handleMessage( msg );
? ? ? ?}
? ?};
? ?@Override
? ?public void wellPrepared() {
? ? ? ?mHandler.sendEmptyMessage( MSG_AUDIO_PREPARED );
? ?}
? ?// 根據(jù)按鈕的狀態(tài)來進(jìn)行操作
? ?@Override
? ?public boolean onTouchEvent(MotionEvent event) {
? ? ? ?int action = event.getAction();
? ? ? ?int x = (int) event.getX();
? ? ? ?int y = (int) event.getY();
? ? ? ?switch (action) {
? ? ? ? ? ?case MotionEvent.ACTION_DOWN: ? ? ? ?// 按下操作
? ? ? ? ? ? ? ?changeState( STATE_RECORDING );
? ? ? ? ? ? ? ?break;
? ? ? ? ? ?case MotionEvent.ACTION_MOVE: ? ? ? // 移動(dòng)操作
? ? ? ? ? ? ? ?if (isRecording){
? ? ? ? ? ? ? ? ? ?// 根據(jù)坐標(biāo)的位置,判斷是否想要取消
? ? ? ? ? ? ? ? ? ?if (wantToCancel( x, y )) {
? ? ? ? ? ? ? ? ? ? ? ?changeState(STATE_WANT_TO_CANCEL);
? ? ? ? ? ? ? ? ? ?}else {
? ? ? ? ? ? ? ? ? ? ? ?changeState( STATE_RECORDING );
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?break;
? ? ? ? ? ?case MotionEvent.ACTION_UP: ? ? ? ? // 松開操作
? ? ? ? ? ? ? ?if(!mReady){
? ? ? ? ? ? ? ? ? ?reset();
? ? ? ? ? ? ? ? ? ?return super.onTouchEvent( event );
? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?if (!isRecording || mTime < 0.6f){
? ? ? ? ? ? ? ? ? ?mDialog.tooShort();
? ? ? ? ? ? ? ? ? ?mAudioManager.cancel();
? ? ? ? ? ? ? ? ? ?mHandler.sendEmptyMessageDelayed( MSG_DIALOG_DIMISS,1300 );
? ? ? ? ? ? ? ?}else if (mCurState == STATE_RECORDING){
? ? ? ? ? ? ? ? ? ?// 正常錄制結(jié)束
? ? ? ? ? ? ? ? ? ?mDialog.dimssDialog();
? ? ? ? ? ? ? ? ? ?mAudioManager.release();
? ? ? ? ? ? ? ? ? ?if (mListener != null ){
? ? ? ? ? ? ? ? ? ? ? ?mListener.onFinish( mTime, mAudioManager.getCurrentFilePath());
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?}else if (mCurState == STATE_WANT_TO_CANCEL){
? ? ? ? ? ? ? ? ? ?mDialog.dimssDialog();
? ? ? ? ? ? ? ? ? ?mAudioManager.cancel();
? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?reset();
? ? ? ? ? ? ? ?break;
? ? ? ?}
? ? ? ?return super.onTouchEvent( event );
? ?}
? ?// 設(shè)置最開始按鈕的默認(rèn)狀態(tài)
? ?private void reset() {
? ? ? ?isRecording = false;
? ? ? ?mReady = false;
? ? ? ?mTime = 0;
? ? ? ?changeState( STATE_NORMAL );
? ?}
? ?private boolean wantToCancel(int x, int y) {
? ? ? ?if (x <0 || x>getWidth()){ // 判斷手指的橫坐標(biāo)是否超出按鈕范圍
? ? ? ? ? ?return true;
? ? ? ?}
? ? ? ?if (y <-DISTANCE_Y_CANCEL || y>getHeight()+DISTANCE_Y_CANCEL){
? ? ? ? ? ?return true;
? ? ? ?}
? ? ? ?return false;
? ?}
? ?// 改變按鈕的內(nèi)容
? ?private void changeState(int state) {
? ? ? ?if (mCurState != state){
? ? ? ? ? ? ? ?mCurState = state;
? ? ? ? ? ?switch (state){
? ? ? ? ? ? ? ?// 改變按鈕背景色及顯示文本
? ? ? ? ? ? ? ?case STATE_NORMAL:
? ? ? ? ? ? ? ? ? ?setBackgroundResource( R.drawable.btn_recorder_normal );
? ? ? ? ? ? ? ? ? ?setText( R.string.str_recorder_normal );
? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ?case STATE_RECORDING:
? ? ? ? ? ? ? ? ? ?setBackgroundResource( R.drawable.btn_recorder_recording );
? ? ? ? ? ? ? ? ? ?setText( R.string.str_recorder_recording );
? ? ? ? ? ? ? ? ? ?if(isRecording){
? ? ? ? ? ? ? ? ? ? ? ?mDialog.recording();
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ?case STATE_WANT_TO_CANCEL:
? ? ? ? ? ? ? ? ? ?setBackgroundResource( R.drawable.btn_recorder_recording );
? ? ? ? ? ? ? ? ? ?setText( R.string.str_recorder_want_cancel );
? ? ? ? ? ? ? ? ? ?mDialog.wantToCancel();
? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ?}
————————————————————————————————————————————
權(quán)限也加過了啊,為什么會(huì)這樣,求解
2016-09-18
如果是電腦上用的虛擬機(jī)那就是虛擬機(jī)沒有麥克風(fēng)導(dǎo)致