Обновление 3:. Я сотрудничал с другим разработчиком, и мы, похоже, нашли кого-то, кто может это сделать за большую сумму денег. Они прислали нам тест-апк, и, похоже, он работает. Мы пойдем вперед и купим источник. Надеюсь, нас не обманут. Я обновлю, когда узнаю
Обновление 2: Все еще работает над этим. После более болезненных дней я теперь думаю, что нет ничего интересного, но они просто используют AudioFlinger (См. Ссылку) на родной стороне для вызова AudioFlinger:: SetParameters
Теперь я хочу найти, как я могу написать простой JNI для вызова AudioFlinger:: setParameters с audio_io_handle_t ioHandle, const String8 & keyValuePairs
Я знаю, что может keyValuePairs быть, но не иметь понятия о audio_io_handle_t
Обновление: Теперь я полагаю, что другие приложения могут использовать аудио QCOM с CAF. См. Audio_extn_utils_send_audio_calibration в ссылка для одного и того же
и 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 и запись с помощью стандартного API AudioRecorder
На следующей строке вы увидите, что аудиооборудование начинает смешивать VOICE_CALL (input_source = 4), даже если они открыли источник звука MIC (1).
Я предположил, что они использовали
AudioManager.setParameters("key=value")
и попробовал множество вариаций, таких как
AudioManager.setParameters("input_source=4;routing=-2147483584;format=1")
без везения.
Затем я нашел Android, NDK, аудио-маршрутизацию, заставляя звук через гарнитуру, и подумал, что они могут быть такими, как mix/route/stream/merge VOICE_CALL в текущую сессию AudioRecord и (так как не имеют знаний C) пытались использовать reflation для достижения той же самой вещи с ниже кода (снова) без везения.
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();
}
}
Очевидно, что мне что-то не хватает, что делает запись возможной.
Я даже предложил заплатить, чтобы получить эту информацию, все отказались. Достаточно справедливо, я сказал. Я буду публиковать его один раз/если найду его!
Есть ли у вас какие-либо идеи относительно того, что они могут делать?
Спасибо заранее.