Android AudioRecord 强制另一个流到 MIC 音频源

更新3: 我已经和另一个开发人员合作,我们似乎找到了一个人谁可以这样做一大笔钱。他们给我们发来了一个试验装置,似乎起作用了。我们将继续购买来源。我希望我们不会被骗。一有消息我就通知你

更新2: 仍在进行中。在经历了更多痛苦的日子之后,我现在认为没有什么特别的事情发生,但是他们只是在本机端使用 AudioFlinger (看看链接)来调用 < strong > AudioFlinger: : setParameter

我现在正在寻找如何编写一个简单的 JNI 来调用 AudioFlinger: : setParameter Dio _ io _ handle _ t ioHandle,const String8 & keyValuePair

我知道 键值对是什么,但对 把手一无所知

更新: 我现在相信其他应用程序可能在 CAF 中使用 QCOM 音频。在 < a href = “ https://github.com/dtsinc/DTS-Eagle-Integration _ CAF-Android-hard-qcom-Audio/blob/master/hal/Audio _ extn/utils.c”rel = “ noReferrer”> 链接查看 Audio _ extn _ utils _ send _ Audio _  请参阅

以及 链接相同上的 voice _ get _ incall _ rec _ snd _ device

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


我已经为此挣扎了40多天,每天至少5-6个小时。我不知道是否允许这样做,但我很高兴捐赠的正确答案太多。

我有一个呼叫录音应用程序,使用 VOICE _ CALL 音频源。尽管 ASOP 没有实现/强制它,但大多数制造商已经实现了 VOICE _ CALL,使用 VOICE _ CALL 音频源的应用程序在许多设备上运行良好。直到安卓6。

谷歌用 Android 6改变了这种行为。打开 VOICE _ CALL 音频源现在需要 android.permission. CAPTURE _ AUDIO _ OUTPUT,它只授予系统应用程序。

这实际上停止了呼叫记录,或者应该停止。好吧,它适用于我的和其他200多个电话录音应用程序,除了3个已经找到了一种方法来绕过这个限制。

我已经在很多不同的 Android 6手机上尝试了这些应用程序,发现它们录音的方式有一些特点。

他们都使用 Android AudioRecord 类并打开 MIC 音频源。我也是,但是在我的应用程序中,我只能从 MIC 得到音频,而不能从另一方得到。我发现他们在开始录音之后或之前发出了某种系统调用。

看看下面的日志表格,其中一个应用程序成功地记录 VOICE _ CALL,即使它使用麦克风来记录。它看起来像应用程序是如何管理混合/路由/流/合并 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")

一无所获。

然后,我发现了 安卓,NDK,音频路由,强制音频通过耳机,并认为他们可能是某种混合/路由/流/合并 VOICE _ CALL 到当前 AudioRecord 会话和(因为没有 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();
}


}

很明显,有些东西是我遗漏的,这使得录音成为可能。

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

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

8086 次浏览

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

假设您想设置一个 AudioRecord实例,以便能够以16kHz 的频率记录16位单声道。您可以通过使用几个 helper 方法创建一个类来实现这一点,如下所示:

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

我猜你将需要保持相同的权限在地方,因为 棉花糖用户是唯一的,授予我们访问某些 权限的权限,如果不是几乎所有的冷静。

尝试实现类,让我们知道它是如何进行的,我也留下了一些额外的参考,以防你需要更多的研究。

祝你好运。

AudioRecord API

音频捕获应用程序接口

MediaRecorder API

我和我的搭档买到了我们要找的东西。我们在正确的路径上,您在本机端设置 keyValuePears。

不幸的是,我不能发表的来源,因为从公司的许可限制,我们有它为我们写的