Home | History | Annotate | Download | only in soundrecorder
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.soundrecorder;
     18 
     19 import java.io.File;
     20 import java.io.IOException;
     21 
     22 import android.content.Context;
     23 import android.media.AudioManager;
     24 import android.media.MediaPlayer;
     25 import android.media.MediaRecorder;
     26 import android.media.MediaPlayer.OnCompletionListener;
     27 import android.media.MediaPlayer.OnErrorListener;
     28 import android.os.Bundle;
     29 import android.os.Environment;
     30 import android.util.Log;
     31 
     32 public class Recorder implements OnCompletionListener, OnErrorListener {
     33     static final String SAMPLE_PREFIX = "recording";
     34     static final String SAMPLE_PATH_KEY = "sample_path";
     35     static final String SAMPLE_LENGTH_KEY = "sample_length";
     36 
     37     public static final int IDLE_STATE = 0;
     38     public static final int RECORDING_STATE = 1;
     39     public static final int PLAYING_STATE = 2;
     40 
     41     int mState = IDLE_STATE;
     42 
     43     public static final int NO_ERROR = 0;
     44     public static final int SDCARD_ACCESS_ERROR = 1;
     45     public static final int INTERNAL_ERROR = 2;
     46     public static final int IN_CALL_RECORD_ERROR = 3;
     47 
     48     public interface OnStateChangedListener {
     49         public void onStateChanged(int state);
     50         public void onError(int error);
     51     }
     52     OnStateChangedListener mOnStateChangedListener = null;
     53 
     54     long mSampleStart = 0;       // time at which latest record or play operation started
     55     int mSampleLength = 0;      // length of current sample
     56     File mSampleFile = null;
     57 
     58     MediaRecorder mRecorder = null;
     59     MediaPlayer mPlayer = null;
     60 
     61     public Recorder() {
     62     }
     63 
     64     public void saveState(Bundle recorderState) {
     65         recorderState.putString(SAMPLE_PATH_KEY, mSampleFile.getAbsolutePath());
     66         recorderState.putInt(SAMPLE_LENGTH_KEY, mSampleLength);
     67     }
     68 
     69     public int getMaxAmplitude() {
     70         if (mState != RECORDING_STATE)
     71             return 0;
     72         return mRecorder.getMaxAmplitude();
     73     }
     74 
     75     public void restoreState(Bundle recorderState) {
     76         String samplePath = recorderState.getString(SAMPLE_PATH_KEY);
     77         if (samplePath == null)
     78             return;
     79         int sampleLength = recorderState.getInt(SAMPLE_LENGTH_KEY, -1);
     80         if (sampleLength == -1)
     81             return;
     82 
     83         File file = new File(samplePath);
     84         if (!file.exists())
     85             return;
     86         if (mSampleFile != null
     87                 && mSampleFile.getAbsolutePath().compareTo(file.getAbsolutePath()) == 0)
     88             return;
     89 
     90         delete();
     91         mSampleFile = file;
     92         mSampleLength = sampleLength;
     93 
     94         signalStateChanged(IDLE_STATE);
     95     }
     96 
     97     public void setOnStateChangedListener(OnStateChangedListener listener) {
     98         mOnStateChangedListener = listener;
     99     }
    100 
    101     public int state() {
    102         return mState;
    103     }
    104 
    105     public int progress() {
    106         if (mState == RECORDING_STATE || mState == PLAYING_STATE)
    107             return (int) ((System.currentTimeMillis() - mSampleStart)/1000);
    108         return 0;
    109     }
    110 
    111     public int sampleLength() {
    112         return mSampleLength;
    113     }
    114 
    115     public File sampleFile() {
    116         return mSampleFile;
    117     }
    118 
    119     /**
    120      * Resets the recorder state. If a sample was recorded, the file is deleted.
    121      */
    122     public void delete() {
    123         stop();
    124 
    125         if (mSampleFile != null)
    126             mSampleFile.delete();
    127 
    128         mSampleFile = null;
    129         mSampleLength = 0;
    130 
    131         signalStateChanged(IDLE_STATE);
    132     }
    133 
    134     /**
    135      * Resets the recorder state. If a sample was recorded, the file is left on disk and will
    136      * be reused for a new recording.
    137      */
    138     public void clear() {
    139         stop();
    140 
    141         mSampleLength = 0;
    142 
    143         signalStateChanged(IDLE_STATE);
    144     }
    145 
    146     public void startRecording(int outputfileformat, String extension, Context context) {
    147         stop();
    148 
    149         if (mSampleFile == null) {
    150             File sampleDir = Environment.getExternalStorageDirectory();
    151             if (!sampleDir.canWrite()) // Workaround for broken sdcard support on the device.
    152                 sampleDir = new File("/sdcard/sdcard");
    153 
    154             try {
    155                 mSampleFile = File.createTempFile(SAMPLE_PREFIX, extension, sampleDir);
    156             } catch (IOException e) {
    157                 setError(SDCARD_ACCESS_ERROR);
    158                 return;
    159             }
    160         }
    161 
    162         mRecorder = new MediaRecorder();
    163         mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    164         mRecorder.setOutputFormat(outputfileformat);
    165         mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    166         mRecorder.setOutputFile(mSampleFile.getAbsolutePath());
    167 
    168         // Handle IOException
    169         try {
    170             mRecorder.prepare();
    171         } catch(IOException exception) {
    172             setError(INTERNAL_ERROR);
    173             mRecorder.reset();
    174             mRecorder.release();
    175             mRecorder = null;
    176             return;
    177         }
    178         // Handle RuntimeException if the recording couldn't start
    179         try {
    180             mRecorder.start();
    181         } catch (RuntimeException exception) {
    182             AudioManager audioMngr = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
    183             boolean isInCall = ((audioMngr.getMode() == AudioManager.MODE_IN_CALL) ||
    184                     (audioMngr.getMode() == AudioManager.MODE_IN_COMMUNICATION));
    185             if (isInCall) {
    186                 setError(IN_CALL_RECORD_ERROR);
    187             } else {
    188                 setError(INTERNAL_ERROR);
    189             }
    190             mRecorder.reset();
    191             mRecorder.release();
    192             mRecorder = null;
    193             return;
    194         }
    195         mSampleStart = System.currentTimeMillis();
    196         setState(RECORDING_STATE);
    197     }
    198 
    199     public void stopRecording() {
    200         if (mRecorder == null)
    201             return;
    202 
    203         mRecorder.stop();
    204         mRecorder.release();
    205         mRecorder = null;
    206 
    207         mSampleLength = (int)( (System.currentTimeMillis() - mSampleStart)/1000 );
    208         setState(IDLE_STATE);
    209     }
    210 
    211     public void startPlayback() {
    212         stop();
    213 
    214         mPlayer = new MediaPlayer();
    215         try {
    216             mPlayer.setDataSource(mSampleFile.getAbsolutePath());
    217             mPlayer.setOnCompletionListener(this);
    218             mPlayer.setOnErrorListener(this);
    219             mPlayer.prepare();
    220             mPlayer.start();
    221         } catch (IllegalArgumentException e) {
    222             setError(INTERNAL_ERROR);
    223             mPlayer = null;
    224             return;
    225         } catch (IOException e) {
    226             setError(SDCARD_ACCESS_ERROR);
    227             mPlayer = null;
    228             return;
    229         }
    230 
    231         mSampleStart = System.currentTimeMillis();
    232         setState(PLAYING_STATE);
    233     }
    234 
    235     public void stopPlayback() {
    236         if (mPlayer == null) // we were not in playback
    237             return;
    238 
    239         mPlayer.stop();
    240         mPlayer.release();
    241         mPlayer = null;
    242         setState(IDLE_STATE);
    243     }
    244 
    245     public void stop() {
    246         stopRecording();
    247         stopPlayback();
    248     }
    249 
    250     public boolean onError(MediaPlayer mp, int what, int extra) {
    251         stop();
    252         setError(SDCARD_ACCESS_ERROR);
    253         return true;
    254     }
    255 
    256     public void onCompletion(MediaPlayer mp) {
    257         stop();
    258     }
    259 
    260     private void setState(int state) {
    261         if (state == mState)
    262             return;
    263 
    264         mState = state;
    265         signalStateChanged(mState);
    266     }
    267 
    268     private void signalStateChanged(int state) {
    269         if (mOnStateChangedListener != null)
    270             mOnStateChangedListener.onStateChanged(state);
    271     }
    272 
    273     private void setError(int error) {
    274         if (mOnStateChangedListener != null)
    275             mOnStateChangedListener.onError(error);
    276     }
    277 }
    278