在Android中同时在多个应用程序中使用麦克风

18
我们有一个安卓设备,想要在两个应用程序中同时使用麦克风。实际上,我们有一个后台运行的语音命令服务(使用CMU Sphinx库)。问题在于当我们启动录像机(相机应用程序)时,由于两个应用程序不能同时访问麦克风,因此无法开始录制。 错误
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)

请注意,当语音服务关闭时,相机的工作表现良好。

此外,我要说明我已经阅读了这个主题:

Android:同时访问麦克风(RecognizerIntent + 自己的应用程序)

但是这里的区别在于我们对操作系统和内核有控制权。因此,如果需要,我们可以应用补丁。

这是一个SDK / OS / Kernel的限制吗?是否有任何解决方法?


1
你可以启动一个服务(类似中间层),从麦克风获取信息,然后将数据发送到多个应用程序。 - sigrlami
2
我不记得限制来自哪里,但在我使用过的某个平台上,我们有一个流分离器的解决方法。这个类是由平台提供商编写的(因此它是专有的),并且是libaudioflinger的一部分,如果我没记错的话。它将管理音频硬件输入流,并向所有想要录制音频的客户端(应用程序)分发音频数据。因此,如果您有能力构建自己的Android ROM,则可以完成此操作,但这并不容易。 - Michael
@Sigrlami 如果我这样做,那么每个使用麦克风的应用程序都需要修改以使用特殊的API,是吗? - Louisbob
@Louisbob 是的,但是你可以让这个层捕获所有对麦克风的访问,并重定向到你自己的API。你可以通过使用反射来实现这一点,实现一个特殊的类加载器来识别请求的类并返回不同的内容。 - sigrlami
@Sigrlami:你有一些资源或关键词可以提供给我吗?(例如:网址)谢谢! - Louisbob
你有没有写这个层?Android同步麦克风的方法几乎会破坏所有想要在整个系统中使用语音命令的东西。 - Vlad
1个回答

1

当你想要录制电话通话时,可以使用开源的通话录音机。请参见thisthis

以下是代码示例:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接