【问题标题】:Android AudioRecord forcing another stream to MIC audio sourceAndroid AudioRecord 强制另一个流到 MIC 音频源
【发布时间】:2016-09-01 23:58:35
【问题描述】:

更新 3:我已与另一位开发人员合作,我们似乎找到了能够以大笔资金完成此任务的人。他们向我们发送了一个测试 apk,它似乎有效。我们将继续购买源代码。我希望我们不会被骗。知道了我会更新的

更新 2: 仍在努力。经过更痛苦的日子,我现在认为没有什么特别的事情了,但他们只是在本机端使用 AudioFlinger (See the link) 来调用 AudioFlinger::setParameters

我现在正在寻找如何编写一个简单的 JNI 来调用 AudioFlinger::setParameters audio_io_handle_t ioHandle, const String8& keyValuePairs

我知道 keyValuePairs 是什么,但不知道 audio_io_handle_t

更新:我现在相信其他应用可能正在使用带有 CAF 的 QCOM 音频。请参阅link for same 上的 audio_extn_utils_send_audio_calibration

link for same上的voice_get_incall_rec_snd_device

我没有 C/++ 知识。我怎样才能知道我是否可以从本机端调用这些方法? 既然其他应用可以,那一定有办法。


40 多天以来,我每天至少要花 5-6 个小时来解决这个问题。我不确定 SO 是否允许,但我也很乐意为正确答案捐款。

我有一个使用 VOICE_CALL 音频源的通话录音应用。虽然 ASOP 没有实现/强制它,但大多数制造商已经实现了 VOICE_CALL,并且使用 VOICE_CALL 音频源的应用程序在许多设备上都可以正常工作。直到 Android 6。

Google 在 Android 6 中改变了这种行为。现在打开 VOICE_CALL 音频源需要 android.permission.CAPTURE_AUDIO_OUTPUT,它只授予系统应用程序。

这基本上停止了通话录音,或者应该有。嗯,它适用于我和 200 多个其他通话记录应用程序,除了 3 个找到解决此限制的方法。

我一直在许多不同的搭载 Android 6 的手机上尝试这些应用,并在它们设法记录的方式中发现了某些特征。

它们都使用 Android AudioRecord 类并开放 MIC 音频源。我也做;但在我的应用程序上,我只能从 MIC 获取音频,而不是对方。我发现告诉我他们在开始录制之后或之前发出某种系统调用。

查看以下日志,其中一个成功记录了 VOICE_CALL 的应用程序,即使它使用 MIC 进行记录。看起来应用程序是一些如何管理混合/路由/流/合并 VOICE_CALL 音频源到 MIC。

- D/audio_hw_primary: in_set_parameters: enter: kvpairs=input_source=1;routing=-2147483644
- D/PermissionCache: checking android.permission.MODIFY_AUDIO_SETTINGS for uid=10286 => granted (432 us)
- D/audio_hw_primary: in_set_parameters: enter: kvpairs=input_source=4;routing=-2147483584;format=1
- D/audio_hw_primary: select_devices: out_snd_device(0: ) in_snd_device(283: voice-dmic-ef)
- D/hardware_info: hw_info_append_hw_type : device_name = voice-dmic-ef
- D/voice: voice_get_incall_rec_snd_device: in_snd_device(283: voice-dmic-ef) incall_record_device(283: voice-dmic-ef)

正如您在第一行中看到的,它以 MIC 音频源 input_source=1;routing=-2147483644 开头。

然后,在第二行它做了一些事情并获得了 android.permission.MODIFY_AUDIO_SETTINGS 这是正常权限,我的应用程序也有它。这似乎是最重要的部分,看起来所有 3 人都在使用 JNI 来执行他们所做的任何事情来触发将 VOICE_CALL 音频源流式传输/合并到 MIC 并使用标准 AudioRecorder API 进行录制

在下一行,您会看到音频硬件开始混合 VOICE_CALL (input_source=4),即使它们已打开 MIC(1) 音频源。

我假设他们使用过

AudioManager.setParameters("key=value")

并尝试了许多变体,例如

AudioManager.setParameters("input_source=4;routing=-2147483584;format=1")

运气不好。

然后,我发现 Android, NDK, Audio routing, forcing audio through the headset 并认为它们可能是一些如何在当前 AudioRecord 会话中混合/路由/流/合并 VOICE_CALL 并且(因为没有 C 知识)尝试使用再膨胀来实现与以下相同的事情代码(再次)没有运气。

private static void setForceUseOn() {

/*
setForceUse(int usage, int config);

----usage for setForceUse, must match AudioSystem::force_use
public static final int FOR_COMMUNICATION = 0;
public static final int FOR_MEDIA = 1;
public static final int FOR_RECORD = 2;
public static final int FOR_DOCK = 3;
public static final int FOR_SYSTEM = 4;
public static final int FOR_HDMI_SYSTEM_AUDIO = 5;

----device categories config for setForceUse, must match AudioSystem::forced_config
public static final int FORCE_NONE = 0;
public static final int FORCE_SPEAKER = 1;
public static final int FORCE_HEADPHONES = 2;
public static final int FORCE_BT_SCO = 3;
public static final int FORCE_BT_A2DP = 4;
public static final int FORCE_WIRED_ACCESSORY = 5;
public static final int FORCE_BT_CAR_DOCK = 6;
public static final int FORCE_BT_DESK_DOCK = 7;
public static final int FORCE_ANALOG_DOCK = 8;
public static final int FORCE_DIGITAL_DOCK = 9;
public static final int FORCE_NO_BT_A2DP = 10;
public static final int FORCE_SYSTEM_ENFORCED = 11;
public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12;
public static final int FORCE_DEFAULT = FORCE_NONE;


 */

    try {
        Class audioSystemClass = Class.forName("android.media.AudioSystem");
        Method setForceUse = audioSystemClass.getMethod("setForceUse", int.class, int.class);
        setForceUse.invoke(null, 0, 0);      // setForceUse(FOR_RECORD, FORCE_NONE)


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

}

显然,我缺少一些使录音成为可能的东西。

我什至提出要付费获取这些信息,都被拒绝了。我已经说过了。我将发布一次/如果我找到它!

你知道他们可能在做什么吗?

【问题讨论】:

标签: java android c android-ndk qualcomm


【解决方案1】:

我和我的伙伴能够购买我们想要的东西。我们走在正确的道路上,您在本机端设置了 keyValuePairs。

很遗憾,由于我们为我们编写的公司的许可限制,我无法发布源代码

【讨论】:

  • 一个人的bug是另一个人的特性。
  • 你是对的,nLL 是 ACR,如果他不能分享解决方案,他为什么要使用这个 stackoverflow 社区?我认为这完全违背了社区的主要动机。我保证如果我能得到解决方案,我会立即发布解决方案,因为我相信开源。
  • @japanjotsingh 让我们一起寻找解决方案
  • @nLL 我可能听起来很粗鲁,但兄弟这对我们所有人来说都非常令人沮丧:-(
  • CallRecLib 是一个库,提供了一种用于在 Android 6 上录制电话对话的 hack github.com/ViktorDegtyarev/CallRecLib
【解决方案2】:

你的发现很有趣。我参与了一些涉及AudioRecord API 的小项目。希望以下内容会有所帮助:

假设您想设置一个AudioRecord 实例,以便您可以在 16kHz 下录制 16 位单声道。您可以通过创建一个带有一些辅助方法的类来实现这一点,如下所示:

public class AudioRecordTool {
        private final int minBufferSize;
        private boolean doRecord = false;
        private final AudioRecord audioRecord;

        public AudioRecordTool() {
            minBufferSize = AudioTrack.getMinBufferSize(16000,
                    AudioFormat.CHANNEL_OUT_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);
            audioRecord = new AudioRecord(
                    MediaRecorder.AudioSource.VOICE_COMMUNICATION,
                    16000,
                    AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    minBufferSize * 2);
        }

        public void writeAudioToStream(OutputStream audioStream) {
            doRecord = true; //Will dictate if we are recording.
            audioRecord.startRecording();
            byte[] buffer = new byte[minBufferSize * 2];
            while (doRecord) {
                int bytesWritten = audioRecord.read(buffer, 0, buffer.length);
                try {
                    audioStream.write(buffer, 0, bytesWritten);
                } catch (IOException e) {
                    //You can log if you like, or simply ignore it
                   stopRecording();
                }
            }
            //cleanup
            audioRecord.stop();
            audioRecord.release();
        }

        public void stopRecording() {
            doRecord = false;
        }
    }

我猜您需要保留相同的权限,因为只有 Marshmallow 用户才能授予我们访问某些权限(如果不是几乎全部)的权限很酷的。

尝试实现该类并让我们知道它是如何进行的,我还会留下一些额外的参考资料,以防您需要更多研究。

祝你好运。

AudioRecord API

AudioCaputre API

MediaRecorder API

【讨论】:

  • 不,不幸的是,这与我的问题无关。我已经在使用 AudioReocord 类并广泛使用它。
  • 这个问题你解决了吗?我真的需要一个可行的解决方案:-(
猜你喜欢
  • 2012-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多