Use microphone in multiple app simultaneously in Android
Asked Answered
T

1

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 ?

Tightfisted answered 20/8, 2014 at 10:29 Comment(6)
You can start service (something like intermediate layer), that will be getting information from mic, and then send data to multiple applications.Fluted
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.Semitic
@Sigrlami If I do that, I'll need to modify every application that use the microphone to use the special API, isn'it?Tightfisted
@Tightfisted 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.Fluted
@Sigrlami : do you have some resources or keywords to provide to me? (e.g : weblink) Thx!Tightfisted
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..Lardner
L
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;
}
Luik answered 8/6, 2015 at 14:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.