Search code examples
androidvoice-recording

Call recording using audiosource MIC always fails


I am coding a call recording feature using MIC as audio source, as VOICE_CALL is not allowed in some devices. Below is my code.

But sometimes this code crashes with Null pointer exception and sometimes does not stop the media-recorder I mean recording goes on after the call also.

Broadcast receiver registered as phone-state listener....

Any help would be appreciated. You can find my code below.

import java.io.File;
import java.io.IOException;
import java.util.Calendar;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.Environment;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class TestingCallmonitor extends BroadcastReceiver{
 private MediaRecorder mediaRecorder=null;
 boolean flag=false;  
    @Override
     public void onReceive(Context context, Intent intent) {
         String action = intent.getAction();

         if(action.equalsIgnoreCase("android.intent.action.PHONE_STATE"))
          {
           if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) 
              {

               //Toast.makeText(context, "ringing", Toast.LENGTH_LONG).show(); 

              }         

           if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE)) 
              {
                 if(flag) {   
                           mediaRecorder.stop();
                           mediaRecorder.release();
                           mediaRecorder=null;
                           }
                flag=false;
              }     

           if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) 
            {  
               flag=true;
               Calendar c=Calendar.getInstance();
               int hour=c.get(Calendar.HOUR);
               int min=c.get(Calendar.MINUTE);
               int sec=c.get(Calendar.SECOND);
               //Toast.makeText(context, "started", Toast.LENGTH_LONG).show();
               File folder = new File(Environment.getExternalStorageDirectory() + "/Callrecord");
                if (!folder.exists()) {
                    folder.mkdir();
                }
                String mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
                mFileName += "/Callrecord/call"+hour+"-"+min+"-"+sec+".3gp";
                mediaRecorder=new MediaRecorder();
                mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                //mediaRecorder.setAudioEncoder(MediaRecorder.getAudioSourceMax());
                mediaRecorder.setAudioSamplingRate(44100);
                mediaRecorder.setAudioEncodingBitRate(16);
                mediaRecorder.setOutputFile(mFileName);
                try{mediaRecorder.prepare();}catch(IOException e){Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show();}
                mediaRecorder.start();

             }    

         }   

    }

}


Solution

  • here i added the call recorder sample source code for. Please try and let me know.

    RecordService.java

    import java.io.File;
    import java.io.IOException;
    import java.lang.Exception;
    import java.util.Date;
    import java.text.SimpleDateFormat;
    import android.os.IBinder;
    import android.app.Service;
    import android.app.Notification;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.preference.PreferenceManager;
    import android.content.SharedPreferences;
    import android.content.Context;
    import android.content.Intent;
    import android.media.MediaRecorder;
    import android.widget.Toast;
    import android.util.Log;
    import java.io.InputStream;
    import java.io.FileInputStream;
    import java.util.Iterator;
    
    public class RecordService 
        extends Service
        implements MediaRecorder.OnInfoListener, MediaRecorder.OnErrorListener
    {
        private static final String TAG = "CallRecorder";
    
        public static final String DEFAULT_STORAGE_LOCATION = "/sdcard/callrecorder";
        private static final int RECORDING_NOTIFICATION_ID = 1;
        private MediaRecorder recorder = null;
        private boolean isRecording = false;
        private File recording = null;;
        private final int audioformat = 3;
    
    
        private File makeOutputFile (SharedPreferences prefs)
        {
        File dir = new File(DEFAULT_STORAGE_LOCATION);
    
        // test dir for existence and writeability
        if (!dir.exists()) {
            try {
                dir.mkdirs();
            } catch (Exception e) {
                Log.e("CallRecorder", "RecordService::makeOutputFile unable to create directory " + dir + ": " + e);
                Toast t = Toast.makeText(getApplicationContext(), "CallRecorder was unable to create the directory " + dir + " to store recordings: " + e, Toast.LENGTH_LONG);
                t.show();
                return null;
            }
        } else {
            if (!dir.canWrite()) {
                Log.e(TAG, "RecordService::makeOutputFile does not have write permission for directory: " + dir);
                Toast t = Toast.makeText(getApplicationContext(), "CallRecorder does not have write permission for the directory directory " + dir + " to store recordings", Toast.LENGTH_LONG);
                t.show();
                return null;
            }
        }
    
        // test size
    
        // create filename based on call data
        String prefix = "call";
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd_HH:MM:SS");
        //prefix = sdf.format(new Date()) + "-callrecording";
    
        // add info to file name about what audio channel we were recording
        prefix += "-channel" + 1 + "-";
    
        // create suffix based on format
        String suffix = "";
        switch (audioformat) {
        case MediaRecorder.OutputFormat.THREE_GPP:
            suffix = ".3gpp";
            break;
        case MediaRecorder.OutputFormat.MPEG_4:
            suffix = ".mpg";
            break;
        case MediaRecorder.OutputFormat.RAW_AMR:
            suffix = ".amr";
            break;
        }
    
        try {
            return File.createTempFile(prefix, suffix, dir);
        } catch (IOException e) {
            Log.e("CallRecorder", "RecordService::makeOutputFile unable to create temp file in " + dir + ": " + e);
            Toast t = Toast.makeText(getApplicationContext(), "CallRecorder was unable to create temp file in " + dir + ": " + e, Toast.LENGTH_LONG);
            t.show();
            return null;
        }
        }
    
        public void onCreate()
        {
        super.onCreate();
        recorder = new MediaRecorder();
        Log.i("CallRecorder", "onCreate created MediaRecorder object");
        }
    
        public void onStart(Intent intent, int startId) {
        Log.i("CallRecorder", "RecordService::onStartCommand called while isRecording:" + isRecording);
    
        if (isRecording) return;
    
        Context c = getApplicationContext();
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
    
        Boolean shouldRecord = prefs.getBoolean(Preferences.PREF_RECORD_CALLS, false);
        if (!shouldRecord) {
            Log.i("CallRecord", "RecordService::onStartCommand with PREF_RECORD_CALLS false, not recording");
            //return START_STICKY;
            return;
        }
        recording = makeOutputFile(prefs);
        if (recording == null) {
            recorder = null;
            return; //return 0;
        }
    
           try {
            // These calls will throw exceptions unless you set the 
            // android.permission.RECORD_AUDIO permission for your app
            recorder.reset();
            recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            recorder.setOutputFormat(audioformat);
            Log.d("CallRecorder", "set output " + audioformat);
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
            Log.d("CallRecorder", "set encoder default");
            recorder.setOutputFile(recording.getAbsolutePath());
            Log.d("CallRecorder", "set file: " + recording);
            //recorder.setMaxDuration(msDuration); //1000); // 1 seconds
            //recorder.setMaxFileSize(bytesMax); //1024*1024); // 1KB
    
            recorder.setOnInfoListener(this);
            recorder.setOnErrorListener(this);
    
            try {
                recorder.prepare();
            } catch (java.io.IOException e) {
                Log.e("CallRecorder", "RecordService::onStart() IOException attempting recorder.prepare()\n");
                Toast t = Toast.makeText(getApplicationContext(), "CallRecorder was unable to start recording: " + e, Toast.LENGTH_LONG);
                t.show();
                recorder = null;
                return; //return 0; //START_STICKY;
            }
            Log.d("CallRecorder", "recorder.prepare() returned");
    
            recorder.start();
            isRecording = true;
            Log.i("CallRecorder", "recorder.start() returned");
            updateNotification(true);
        } catch (java.lang.Exception e) {
            Toast t = Toast.makeText(getApplicationContext(), "CallRecorder was unable to start recording: " + e, Toast.LENGTH_LONG);
            t.show();
    
            Log.e("CallRecorder", "RecordService::onStart caught unexpected exception", e);
            recorder = null;
        }
    
        return; //return 0; //return START_STICKY;
        }
    
        public void onDestroy()
        {
        super.onDestroy();
    
        if (null != recorder) {
            Log.i("CallRecorder", "RecordService::onDestroy calling recorder.release()");
            isRecording = false;
            recorder.release();
            Toast t = Toast.makeText(getApplicationContext(), "CallRecorder finished recording call to " + recording, Toast.LENGTH_LONG);
            t.show();
        }
    
        updateNotification(false);
        }
    
    
        // methods to handle binding the service
    
        public IBinder onBind(Intent intent)
        {
        return null;
        }
    
        public boolean onUnbind(Intent intent)
        {
        return false;
        }
    
        public void onRebind(Intent intent)
        {
        }
    
    
        private void updateNotification(Boolean status)
        {
        Context c = getApplicationContext();
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
    
        String ns = Context.NOTIFICATION_SERVICE;
        NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
    
        if (status) {
            int icon = R.drawable.rec;
            CharSequence tickerText = "Recording call from channel " + prefs.getString(Preferences.PREF_AUDIO_SOURCE, "1");
            long when = System.currentTimeMillis();
    
            Notification notification = new Notification(icon, tickerText, when);
    
            Context context = getApplicationContext();
            CharSequence contentTitle = "CallRecorder Status";
            CharSequence contentText = "Recording call from channel...";
            Intent notificationIntent = new Intent(this, RecordService.class);
            PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    
            notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
            mNotificationManager.notify(RECORDING_NOTIFICATION_ID, notification);
        } else {
            mNotificationManager.cancel(RECORDING_NOTIFICATION_ID);
        }
        }
    
        // MediaRecorder.OnInfoListener
        public void onInfo(MediaRecorder mr, int what, int extra)
        {
        Log.i("CallRecorder", "RecordService got MediaRecorder onInfo callback with what: " + what + " extra: " + extra);
        isRecording = false;
        }
    
        // MediaRecorder.OnErrorListener
        public void onError(MediaRecorder mr, int what, int extra) 
        {
        Log.e("CallRecorder", "RecordService got MediaRecorder onError callback with what: " + what + " extra: " + extra);
        isRecording = false;
        mr.release();
        }
    }
    

    PhoneListener.java

    import android.content.Intent;
    import android.content.Context;
    import android.content.ComponentName;
    import android.telephony.TelephonyManager;
    import android.telephony.PhoneStateListener;
    import android.util.Log;
    
    public class PhoneListener extends PhoneStateListener
    {
        private Context context;
    
        public PhoneListener(Context c) {
        Log.i("CallRecorder", "PhoneListener constructor");
        context = c;
        }
    
        public void onCallStateChanged (int state, String incomingNumber)
        {
        Log.d("CallRecorder", "PhoneListener::onCallStateChanged state:" + state + " incomingNumber:" + incomingNumber);
    
        switch (state) {
        case TelephonyManager.CALL_STATE_IDLE:
            Log.d("CallRecorder", "CALL_STATE_IDLE, stoping recording");
            Boolean stopped = context.stopService(new Intent(context, RecordService.class));
            Log.i("CallRecorder", "stopService for RecordService returned " + stopped);
            break;
        case TelephonyManager.CALL_STATE_RINGING:
            Log.d("CallRecorder", "CALL_STATE_RINGING");
            break;
        case TelephonyManager.CALL_STATE_OFFHOOK:
            Log.d("CallRecorder", "CALL_STATE_OFFHOOK starting recording");
            Intent callIntent = new Intent(context, RecordService.class);
            ComponentName name = context.startService(callIntent);
            if (null == name) {
                Log.e("CallRecorder", "startService for RecordService returned null ComponentName");
            } else {
                Log.i("CallRecorder", "startService returned " + name.flattenToString());
            }
            break;
        }
        }
    }
    

    Hope it should helpful for you.Its working fine for me. Please try and let me know. For more info please download the sample code form

    Call Recorder