7

I am developing an application which can record calls in Android. I have read a lot of topics where the call recording problem was discussed. And i know that not all Android phones can record calls. But i am wondering how can record calls the most popular applications on Play Market, such as https://play.google.com/store/apps/details?id=com.appstar.callrecorder or https://play.google.com/store/apps/details?id=polis.app.callrecorder. I think that thy are using not on MediaRecorder class to do this job, but also something else. Because i have developed my own application, but i can record only my voice. But these two applications are recording both my voice and the voice of a man to whom i am calling. How they are doing this? I know that we can't get an access to device speaker to record sound from it. Could you give me some ideas of how to record voice calls? Here is my code that i am using in my application:

public class CallRecorderService extends Service {

    private MediaRecorder mRecorder;
    private boolean isRecording = false;

    private PhoneStateListener phoneStateListener = new PhoneStateListener() {

        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
            switch (state) {
                case TelephonyManager.CALL_STATE_IDLE:
                    stopRecording();
                break;
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    startRecording(incomingNumber);
                break;
                case TelephonyManager.CALL_STATE_RINGING:
                break;
                default:

                break;
            }
        }
    };

    @Override
    public void onCreate() {
        TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void startRecording(String number) {
        try {
            String savePath = Environment.getExternalStorageDirectory().getAbsolutePath();
            savePath += "/Recorded";
            File file = new File(savePath);
            if (!file.exists()) {
                file.mkdir();
            }

            savePath += "/record_" + System.currentTimeMillis() + ".amr";
            mRecorder = new MediaRecorder();

            SharedPreferences sPrefs = getSharedPreferences(Constants.PREFERENCES_NAME, Context.MODE_PRIVATE);
            int inputSource = sPrefs.getInt(Constants.SOURCE_INPUT, Constants.SOURCE_VOICE_CALL);
            int outputSource = sPrefs.getInt(Constants.SOURCE_OUTPUT, Constants.OUTPUT_MPEG4);

            switch (inputSource) {
                case Constants.SOURCE_MIC:
                    increaseSpeakerVolume();
                break;
            }

            mRecorder.setAudioSource(inputSource);
            mRecorder.setOutputFormat(outputSource);
            mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mRecorder.setOutputFile(savePath);
            mRecorder.prepare();
            mRecorder.start();
            isRecording = true;

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void stopRecording(){
        if (isRecording) {
            isRecording = false;
            mRecorder.stop();
            mRecorder.release();
        }
    }

    private void increaseSpeakerVolume(){

        AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        audio.adjustStreamVolume(AudioManager.STREAM_VOICE_CALL,
                AudioManager.ADJUST_RAISE,
                AudioManager.FLAG_SHOW_UI);
    }

}
Ian2thedv
  • 2,691
  • 2
  • 26
  • 47
bukka.wh
  • 913
  • 2
  • 16
  • 29
  • possible duplicate of [Android Recording Incoming and Outgoing Calls](http://stackoverflow.com/questions/6688444/android-recording-incoming-and-outgoing-calls) – Roberto Anić Banić Jul 24 '15 at 07:28
  • Check [This](http://stackoverflow.com/questions/3370278/record-phone-calls-on-android-phone) Out – marc_s Jul 24 '15 at 07:36
  • I was using the same code recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL); //Voice downlink/ Uplink recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setAudioEncoder(AudioEncoder.AAC ); but it didn't help me. I think that these top applications on PlayMarket are using the MediaRecorder.AudioSource.MIC and also increasing the sound of the speaker on device to record both sides. What are you thinking about this? – bukka.wh Jul 24 '15 at 07:45
  • _"What are you thinking about this?"_ Sounds like you'd end up with a very poor recording. Plus, maybe you don't want to use speakerphone mode all the time. – Michael Jul 24 '15 at 07:50
  • Okay, so this is not a good idea. I have used a lot of variations of inputs and outputs in my application (CAMCORDER, DEFAULT, MIC, REMOTE_SUBMIX, VOICE_CALL, VOICE_COMMUNICATION, VOICE_DOWNLINK, VOICE_RECOGNITION, VOICE_UPLINK). But all of them were recording only my voice or not working at all. – bukka.wh Jul 24 '15 at 08:06

1 Answers1

1

I think they do use MediaRecorder. Perhaps main problem with it is that, it is tricky to write the data from it into something else but file on local store. In order to work it around, you could create a pipe. Then use its file descriptor as an input fd for MediaRecorder. And the pipe output then could be controlled by some thread that will read the audio packages (in one of format, aac or.. wav even) and then do whatever you want with the data.

Here is some code. Note, this is a proto, may not even compile, just to give you an idea.

        /* 2M buffer should be enough. */
        private final static int SOCKET_BUF_SIZE = 2 * 1024 * 1000;

        private void openSockets() throws IOException {
            receiver = new LocalSocket();
            receiver.connect(new LocalSocketAddress("com.companyname.media-" + socketId));
            receiver.setReceiveBufferSize(SOCKET_BUF_SIZE);
            sender = lss.accept();
            sender.setSendBufferSize(SOCKET_BUF_SIZE);
        }

        private void closeSockets() {
            try {
                if (sender != null) {
                    sender.close();
                    sender = null;
                }
                if (receiver != null) {
                    receiver.close();
                    receiver = null;
                }
            } catch (Exception ignore) {
            }
        }


      public void prepare() throws IllegalStateException, IOException {
        int samplingRate;

        openSockets();

        if (mode == MODE_TESTING) {
            samplingRate = requestedSamplingRate;
        } else {
            samplingRate = actualSamplingRate;
        }
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        try {
            Field name = MediaRecorder.OutputFormat.class.getField("AAC_ADTS");
            if (BuildConfig.DEBUG)
                Log.d(StreamingApp.TAG, "AAC ADTS seems to be supported: AAC_ADTS=" + name.getInt(null));
            mediaRecorder.setOutputFormat(name.getInt(null));
        } catch (Exception e) {
            throw new IOException("AAC is not supported.");
        }

        try {
            mediaRecorder.setMaxDuration(-1);
            mediaRecorder.setMaxFileSize(Integer.MAX_VALUE);
        } catch (RuntimeException e) {
            Log.e(StreamingApp.TAG, "setMaxDuration or setMaxFileSize failed!");
        }

        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mediaRecorder.setAudioChannels(1);
        mediaRecorder.setAudioSamplingRate(samplingRate);
        mediaRecorder.setOutputFile(sender.getFileDescriptor());

        startListenThread(receiver.getInputStream());
        mediaRecorder.start();
    }
Cynichniy Bandera
  • 5,991
  • 2
  • 29
  • 33
  • Thank you very much for the answer. Could you please tell me more about the pipe? How can i create it? – bukka.wh Jul 24 '15 at 08:09
  • Thank you very much for the code! I'll try to implement it in my app. For this moment I am using this code to start recording (this is not all code, but some pieces from it) File file = new File(savePath); savePath += "/record_" + System.currentTimeMillis() + ".amr"; mRecorder = new MediaRecorder(); mRecorder.setAudioSource(inputSource); mRecorder.setOutputFormat(outputSource); mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); mRecorder.setOutputFile(savePath); – bukka.wh Jul 24 '15 at 08:19
  • Sorry for my perseverance, could you please tell to what class does lss variable belong? Thanks) – bukka.wh Jul 24 '15 at 08:49
  • Its local server socket i think. Will check later when im back to my laptop. – Cynichniy Bandera Jul 24 '15 at 09:25
  • socketId = new Random().nextInt(); lss = new LocalServerSocket("com.companyname.media-" + somesocketId); – Cynichniy Bandera Jul 24 '15 at 10:33
  • Thanks! I'll try to implement that – bukka.wh Jul 24 '15 at 10:57
  • did your issue is fixed – Dhruv Tyagi Mar 14 '18 at 12:32