/* * 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 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; import android.util.Log; public class Recorder 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 Recorder() { } 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); } }