18

We have an Android device on which we would like to use the microphone in 2 app simultaneously.

In fact, we have a vocal command service that is running in the background (we are using the CMU Sphinx library). The problem is when we start a video recorder (camera application), we can't start the recording as 2 applications can't access to the microphone at the same time.

Error

08-20 12:20:14.601: I/MediaRecorderJNI(7261): prepare: surface=0x59590668
08-20 12:20:15.916: E/MediaRecorder(7261): start failed: -38
08-20 12:20:15.916: E/com.example.CamcorderView(7261): Failed to start recorder.
08-20 12:20:15.916: E/com.example.CamcorderView(7261): java.lang.IllegalStateException
08-20 12:20:15.916: E/com.example.CamcorderView(7261):     at android.media.MediaRecorder.start(Native Method)

Note that the camera works well when the vocal service is off.

Moreover, I precise that I've already read this thread :

Android: Accessing the microphone simultaniously (RecognizerIntent + own app)

but the difference here is that we have a hand on the O/S and the kernel. So we can apply patch if needed.

Is it an SDK/OS/Kernel limitation? Is there any workaround ?

Community
  • 1
  • 1
Louisbob
  • 860
  • 3
  • 9
  • 22
  • 1
    You can start service (something like intermediate layer), that will be getting information from mic, and then send data to multiple applications. – sigrlami Aug 20 '14 at 10:38
  • 2
    I don't remember exactly where the limitation comes from, but on one of the platforms I've worked with we had a workaround in the form of a stream splitter. This class was written by the platform provider (so it was proprietary), and was part of libaudioflinger IIRC. It would manage the audio hw input stream, and hand out audio data to all clients (apps) that wanted to record audio. So it can be done if you have the ability to build your own Android ROM, but it's not trivial. – Michael Aug 20 '14 at 10:42
  • @Sigrlami If I do that, I'll need to modify every application that use the microphone to use the special API, isn'it? – Louisbob Aug 20 '14 at 11:54
  • @Louisbob Yes, but you can make this layer to grab all accesses to mic, and redicrect to your own API. You could possibly achieve this by using reflection, implement a speciall *classloader* that recognizes requested class and returns something different. – sigrlami Aug 20 '14 at 12:24
  • @Sigrlami : do you have some resources or keywords to provide to me? (e.g : weblink) Thx! – Louisbob Aug 21 '14 at 08:56
  • Did you ever get to writing this layer? Android's approach to synchronizing the mic just about kills everything that want's to use voice commands system wide.. – Vlad Mar 11 '15 at 15:25

1 Answers1

1

This scenario happens

for instance

when you want to record phone call. you can use the open source call recorder. see this and this

Here is a code sample

private MediaRecorder recorder = null;
public void onCreate()
{
    super.onCreate();
    recorder = new MediaRecorder();
    Log.i("CallRecorder", "onCreate created MediaRecorder object");
}

public void onStart(Intent intent, int startId) {

    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;
    }

    int audiosource = Integer.parseInt(prefs.getString(Preferences.PREF_AUDIO_SOURCE, "1"));
    int audioformat = Integer.parseInt(prefs.getString(Preferences.PREF_AUDIO_FORMAT, "1"));

    recording = makeOutputFile(prefs);
    if (recording == null) {
        recorder = null;
        return; //return 0;
    }

    Log.i("CallRecorder", "RecordService will config MediaRecorder with audiosource: " + audiosource + " audioformat: " + audioformat);
    try {
        // These calls will throw exceptions unless you set the 
        // android.permission.RECORD_AUDIO permission for your app
        recorder.reset();
        recorder.setAudioSource(audiosource);
        recorder.setOutputFormat(audioformat);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
        recorder.setOutputFile(recording.getAbsolutePath());
        //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");
            t.show();
            recorder = null;
            return;
        }
        Log.d("CallRecorder", "recorder.prepare() returned");

        recorder.start();
        isRecording = true;
        Log.i("CallRecorder", "recorder.start() returned");
        updateNotification(true);
    } catch (java.lang.Exception e) {
        Log.e("CallRecorder", "RecordService::onStart caught unexpected exception", e);
        recorder = null;
    }

    return;
}
Durai Amuthan.H
  • 31,670
  • 10
  • 160
  • 241
Alireza Rahimi
  • 489
  • 3
  • 6