java android c android-ndk qualcomm

java - Android AudioRecord forzando otra transmisión a la fuente de audio MIC



android-ndk qualcomm (2)

Mi compañero y yo pudimos comprar lo que estábamos buscando. Estábamos en el camino correcto, estableciste keyValuePairs en el lado nativo.

Desafortunadamente, no puedo publicar la fuente debido a las restricciones de licencia de la compañía que teníamos escrita para nosotros.

Actualización 3: me he asociado con otro desarrollador y parece que encontramos a alguien que puede hacer esto por una gran suma de dinero. Nos han enviado un 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 lujoso pero simplemente están usando AudioFlinger ( Ver el enlace ) en el lado nativo para llamar a AudioFlinger :: setParameters

Ahora estoy buscando encontrar 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 una pista sobre 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 conocimiento de C / ++. ¿Cómo puedo saber si puedo llamar a estos métodos desde el lado nativo? Como otras aplicaciones pueden, debe haber una manera.

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 SO lo permite, pero estoy feliz de hacer una donación para la respuesta correcta también.

Tengo una aplicación de grabación de llamadas que utiliza 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 el mío y para más de 200 aplicaciones de grabación de llamadas, aparte de 3 que han encontrado una manera de evitar 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 abren la fuente de audio MIC. Yo también; pero en mi aplicación, solo recibo audio de MIC, no de la otra parte. Lo que descubrí es decirme 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 formulario de registro de una de las aplicaciones que registran con éxito VOICE_CALL, a pesar de que utiliza MIC para grabar. Parece que la aplicación es algo así como lograr mezclar / enrutar / transmitir / fusionar la fuente de audio VOICE_CALL en 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; enrutamiento = -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 sea que hagan para activar la transmisión / fusión de la fuente de audio VOICE_CALL a MIC y grabar con la API de AudioRecorder estándar

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).

Supuse que usaban

AudioManager.setParameters("key=value")

e intenté 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 algo así como mezclar / enrutar / transmitir / fusionar VOICE_CALL en la sesión actual de AudioRecord y (ya que no tengo conocimiento de C) intenté usar la reflación para lograr lo mismo con el siguiente código (de nuevo) 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, todos se negaron. Justo lo que he dicho. ¡Lo publicaré una vez / si lo encuentro!

¿Tienes alguna idea de lo que podrían estar haciendo?


Tus hallazgos son interesantes. He trabajado en algunos pequeños proyectos relacionados con la API AudioRecord . Con suerte, lo siguiente ayudará:

Supongamos que desea configurar una instancia de AudioRecord para poder grabar en mono de 16 bits a 16 kHz. Puede lograr esto creando una clase con algunos métodos auxiliares, como los siguientes:

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

Supongo que tendrá que mantener los mismos permisos en su lugar, ya que los usuarios de Marshmallow son los únicos que nos otorgan acceso a ciertos permisos, si no casi todos los geniales.

Intente implementar la clase y háganos saber cómo fue, también estoy dejando algunas referencias adicionales en caso de que necesite más investigación.

Buena suerte.

API AudioRecord

API AudioCaputre

API de MediaRecorder