Actualización 3: Me he asociado con otro desarrollador y parece que hemos encontrado a alguien que puede hacer esto por una gran suma de dinero. Nos han enviado una apk de prueba y parece funcionar. Seguiremos adelante y compraremos la fuente. Espero que no seamos estafados. Actualizaré una vez que me entere
Actualización 2: Todavía estoy trabajando en ello. Después de días más dolorosos, ahora creo que no hay nada elegante, pero simplemente están usando AudioFlinger ( ver el enlace ) en el lado nativo para llamar a AudioFlinger :: setParameters
Ahora estoy buscando cómo puedo escribir un JNI simple para llamar a AudioFlinger :: setParameters con audio_io_handle_t ioHandle, const String8 & keyValuePairs
Sé lo que puede ser keyValuePairs pero no tengo ni idea de audio_io_handle_t
Actualización: ahora creo que otras aplicaciones podrían estar usando audio QCOM con CAF. Ver audio_extn_utils_send_audio_calibration en el enlace para el mismo
y voice_get_incall_rec_snd_device en el enlace para el mismo
No tengo conocimientos de C / ++. ¿Cómo puedo saber si puedo llamar a estos métodos desde el lado nativo? Dado que otras aplicaciones pueden hacerlo, debe haber una forma.
He estado luchando con esto durante más de 40 días durante al menos 5-6 horas al día. No estoy seguro de si está permitido por SO, pero también estoy feliz de hacer una donación para la respuesta correcta.
Tengo una aplicación de grabación de llamadas que usa la fuente de audio VOICE_CALL. Aunque ASOP no lo implementa / exige, la mayoría de los fabricantes han implementado VOICE_CALL y las aplicaciones que usan la fuente de audio VOICE_CALL funcionaron bien en muchos dispositivos. Eso es hasta Android 6.
Google cambió este comportamiento con Android 6. La apertura de la fuente de audio VOICE_CALL ahora requiere android.permission.CAPTURE_AUDIO_OUTPUT, que solo se otorga a las aplicaciones del sistema.
Esto esencialmente detiene la grabación de llamadas, o debería haberlo hecho. Bueno, lo hace para la mía y para más de 200 aplicaciones de grabación de llamadas además de 3 que han encontrado una manera de sortear esta limitación.
He estado probando esas aplicaciones en muchos teléfonos diferentes con Android 6 y descubrí ciertas características en la forma en que logran grabar.
Todos usan la clase Android AudioRecord y la fuente de audio MIC abierta. Yo también; pero en mi aplicación, solo recibo audio de MIC, no de la otra parte. Lo que descubrí es que me dicen que están emitiendo algún tipo de llamada al sistema justo después o antes de comenzar a grabar.
Eche un vistazo al siguiente registro de una de las aplicaciones que graban con éxito VOICE_CALL, a pesar de que usa MIC para grabar. Parece que la aplicación es de alguna manera para mezclar / enrutar / transmitir / fusionar la fuente de audio VOICE_CALL en el 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)
Como puede ver en la primera línea, comienza con la fuente de audio MIC input_source = 1; routing = -2147483644.
Luego, en la segunda línea, hace algo y se le otorga android.permission.MODIFY_AUDIO_SETTINGS, que es un permiso normal y mi aplicación también lo tiene. Esta parece ser la parte más importante y parece que los 3 están usando JNI para hacer lo que hagan para activar la transmisión / fusión de la fuente de audio VOICE_CALL a MIC y grabar con la API estándar de AudioRecorder.
En la siguiente línea, verá que el hardware de audio comienza a mezclar VOICE_CALL (input_source = 4) a pesar de que han abierto la fuente de audio MIC (1).
He asumido que usaron
AudioManager.setParameters("key=value")
y probé muchas variaciones como
AudioManager.setParameters("input_source=4;routing=-2147483584;format=1")
sin suerte.
Luego, encontré Android, NDK, enrutamiento de audio, forzando el audio a través de los auriculares y pensé que podrían ser de alguna manera mezclar / enrutar / transmitir / fusionar VOICE_CALL en la sesión actual de AudioRecord y (dado que no tengo conocimiento de C) intenté usar reflation para lograr lo mismo con el siguiente código (nuevamente) sin suerte.
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();
}
}
Obviamente, hay algo que me falta que hace posible la grabación.
Incluso me ofrecí a pagar para obtener esta información, pero todos se negaron. Bastante justo lo he dicho. ¡Lo publicaré una vez / si lo encuentro!
¿Tiene alguna idea de lo que podrían estar haciendo?