我和另一个开发者合作过,我们似乎找到了一个可以花一大笔钱来做这件事的人.他们给我们发送了一个测试apk,它似乎起了作用.我们将继续购买来源.我希望我们不会上当受骗.我一发现就会更新

Update 2:还在努力.在经历了更多痛苦的日子后,我现在认为没有什么特别的事情发生,但他们只是在原生一侧使用AudioFinger(See the link)拨打AudioFlinger::setParameters

我现在正在寻找如何编写一个简单的JNI来调用AudioFlinger::setParameters

我知道keyValuePairs会是什么,但对audio_io_handle_t一无所知

Update:我现在相信,其他应用程序可能会在CAF中使用QCOM音频.请参阅link for same时的音频校准

而voice_get_incall_rec_snd_device在link for same

我没有C/++知识.如何才能确定是否可以从本机端调用这些方法? 既然其他应用可以,那么一定有办法.


我每天至少有5-6个小时都在为此奋斗40多天.我不确定这是否得到了SO的允许,但我也很乐意为正确答案捐款.

我有一个通话录音应用程序,使用语音通话音频源.尽管ASOP没有实施/强制实施,但大多数制造商已经实施了VOICE_CALL,并且使用VOICE_CALL音频源的应用在许多设备上运行良好.直到安卓6.

谷歌用安卓6改变了这种行为.打开语音呼叫音频源现在需要android.准许捕获仅授予系统应用程序的音频输出.

这基本上停止了通话记录,或者应该停止.好吧,它适用于我和200多个其他通话记录应用程序,除了3个已经找到了绕过这一限制的方法.

我一直在用安卓6在许多不同的手机上试用这些应用程序,并发现了它们记录的某些特点.

都是使用Android AudioRecord类,打开MIC音频源.我也是;但在我的应用程序上,我只能从麦克风那里获得音频,而不能从对方那里获得音频.我发现的是,他们在开始录制之后或之前发出了某种类型的系统调用.

请看下面的日志(log),这些日志(log)来自成功录制VOICE_CALL的应用程序之一,即使它使用MIC进行录制.看起来APP是如何将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)

正如您在第一行中看到的,它以麦克音频源INPUT_SOURCE=1;ROUTING=-2147483644开始.

然后,在第二行,它做了一些事情,并被授予了安卓系统.准许修改音频设置,这是正常权限,我的应用程序也有.这似乎是最重要的部分,看起来所有3家公司都在使用JNI来触发语音呼叫音频源到麦克风的流式传输/合并,并使用standart AudioRecorder API进行录制

在下一行中,你会看到音频硬件开始混合语音通话(输入源=4),尽管它们已经打开了麦克风(1)音频源.

我以为他们用了

AudioManager.setParameters("key=value")

并try 了许多变体,例如

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

没有任何运气.

然后,我找到了Android, NDK, Audio routing, forcing audio through the headset个,并认为它们可能是一些如何混合/路由/流/合并语音呼叫到当前的录音会话,并且(因为没有C知识)try 使用回流来实现同样的事情与下面的代码(再次)没有运气.

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

}

显然,我遗漏了一些东西,这使得录制成为可能.

我甚至提出付钱来获取这些信息,但都被拒绝了.我说得很公平.我会出版一次/如果我找到的话!

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

推荐答案

我和我的合伙人能够购买我们想要的东西.我们走的是正确的道路,你在本地设置了keyValuePairs.

不幸的是,由于我们为我们编写的公司的许可限制,我不能公布源代码.

C++相关问答推荐

如何避免使用相对路径包含在c中

当多个线程在C中写入相同的文件描述符时,如何防止争用情况?

将 struct 变量赋给自身(通过指针取消引用)是否定义了行为?

如何在C中通过套接字自定义数据类型读取原始变量?

C语言编译阶段与翻译阶段的关系

如何在C中打印包含扫描字符和整数的语句?

使用错误的命令执行程序

关于";*(++p)->;t";、&++p->;t";和&q;++*p->;t";的问题

C将数组传递给函数以修改数组

使用%f格式说明符打印整数值

Go和C中的数据 struct 对齐差异

如何解释数组中的*(ptr)和*(ptr+2)?

如何打印循环调度问题的时间表

通过char*访问指针的对象表示是未定义的行为吗?

为什么argc和argv即使在主函数之外也能工作?

为什么孤儿进程在 Linux 中没有被 PID 1 采用,就像我读过的一本书中声称的那样?

模仿 memmove 的行为

macos/arm64 上地址空间不使用第一位吗?

尽管将其标记为易失性,但 gcc 是否优化了我的等待代码?

cs50拼写器分配中的无限循环