Search code examples
androidbroadcastreceiverandroid-mediarecorder

How do i stop the Media Recorder when the Call has ended?


How Do i Stop() the media Recorder? I tried instantiating the

MediaRecorder r;

Globally but,

r.stop()

Does not work, because r is not instantiated.

If it is possible to save the state of this MediaRecorder Instance, and use it with the stop method later on, How do i do it?

public class nCallRecorder extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) {
            //start recording
            String CallNo = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
            MediaRecorder r = new MediaRecorder();
            r.setAudioSource(MediaRecorder.AudioSource.MIC);
            r.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            r.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            r.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+CallNo+".mp4");
            try { r.prepare(); } catch(IOException e) { e.printStackTrace(); }
            r.start();

        } else if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE)) {
            //stop recording
            Toast.makeText(context,"Call Ends",Toast.LENGTH_LONG).show();
        }
    }
}

EDIT 2:

The Service Starts But the Recorder is not working, the BroadcastReceiver is not working.

AndroidManifest.xml

<service android:name=".RecordService">
  <intent-filter>
    <action android:name="android.intent.action.PHONE_STATE" />
  </intent-filter>
</service>

RecordService.java

public class RecordService extends Service {
private MediaRecorder r = null;
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
private final BroadcastReceiver receiver = new BroadcastReceiver () {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) {
            String CallNo = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
            onCreate();
            r = new MediaRecorder();
            r.setAudioSource(MediaRecorder.AudioSource.MIC);
            r.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            r.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            r.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/l"+CallNo+".mp4");
            try { r.prepare(); } catch(IOException e) { e.printStackTrace(); }
            r.start();
            Toast.makeText(context,"Recording Started",Toast.LENGTH_LONG).show();
        } else if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE)) {
            cleanUp();
            Toast.makeText(context,"Call Ends",Toast.LENGTH_LONG).show();
        }
    }
};
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
        return START_STICKY;
    }
    private void cleanUp() {
        if(r != null) {
            try {
                r.stop();
            } catch (Exception ex) {
            } finally {
                r.release();
                r = null;
            }
        }
    }
    public void onCreate() {
        super.onCreate();
        IntentFilter filter = new IntentFilter();
        filter.addAction(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED);
        registerReceiver(receiver,filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
        cleanUp();
        Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
    }
}

The Error Logcat:

 Process: com.alivezoned.callrecorder, PID: 2864
    java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.PHONE_STATE flg=0x10 (has extras) } in com.alivezoned.callrecorder.RecordService$1@355ef143
            at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:871)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
     Caused by: java.lang.RuntimeException: start failed.
            at android.media.MediaRecorder.start(Native Method)
            at com.alivezoned.callrecorder.RecordService$1.onReceive(RecordService.java:34)
            at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:861)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

Solution

  • With your current code your reference to the MediaRecorder is lost once the program execution exits the block it was declared in.

    An easy way to store your reference is to eiter do the recording inside of a service (recommended) or to use a singleton which is responsible for handling all the MediaRecording things.

    The only thing to keep in mind regarding a singleton is that you may need to do some clean up when your application is destroyed not to leak resources.

    http://developer.android.com/guide/components/services.html

    Register your broadcast receiver in onCreate in the service and unregistered it in onDestroy.

    Something like this (then just start it from your activity or another broadcast receiver). Warning you're probably going to have to fix some compilation errors:

    public class MyService extends Service {
        private MediaRecorder mMediaRecorder;
        private final BroadcastReceiver mTelephonyReceiver = new BroadcastReceiver () {
            @Override
            public void onReceive(Context context, Intent intent) {
                // Changed order of equals to avoid extra null check.
                if (mMediaRecorder == null && TelephonyManager.EXTRA_STATE_RINGING.equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)) {
                    //start recording
                    String CallNo = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
                    mMediaRecorder  = new MediaRecorder();
                    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                    mMediaRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+CallNo+".mp4");
                    try { mMediaRecorder.prepare(); } catch(IOException e) { e.printStackTrace(); }
                    mMediaRecorder.start();
                } else if (TelephonyManager.EXTRA_STATE_IDLE.equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)) {
                    //stop recording
                    cleanUp();
                    Toast.makeText(context,"Call Ends",Toast.LENGTH_LONG).show();
                 }
            }
        }
    
        private void cleanUp() {
            if(mMediaRecorder != null) {
                try {
                    mMediaRecorder.stop();
                } catch (IOException ex) {
                     // Add your handling here.
                } finally {
                    mMediaRecorder.release();
                    mMediaRecorder = null;
                }
            }
        }
    
        public void onCreate () {
            super.onCreate();
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_YOUR_ACTION);
            registerReceiver(mTelephonyReceiver, filter);
        }
    
        public int onStartCommand(Intent intent, int flags, int startId) {
            return START_STICKY;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            unregisterReceiver(mTelephonyReceiver);
            cleanUp();
        }
    }
    

    If you want to start your service when the device boots up consider this stack overflow question: BroadcastReceiver not receiving BOOT_COMPLETED