Android AudioRecord forzando otra transmisión a la fuente de audio del MICRÓFONO


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 un apk de prueba y parece que funciona. Vamos a seguir adelante y comprar la fuente. Espero que no nos estafen. Voy a actualizar una vez que me entere

Actualización 2: Todavía trabajando en ello. Después de días más dolorosos ahora creo que no hay nada de fantasía pasando, pero simplemente están utilizando AudioFlinger ( Ver el enlace ) en el lado nativo para llamar 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 & Keyvaluepars

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 utilizando QCOM audio con CAF. Véase audio_extn_utils_send_audio_calibration en enlace para mismo

Y voice_get_incall_rec_snd_device en enlace para same

No tengo conocimiento de C/++. ¿Cómo puedo saber si puedo llamar a estos métodos desde el lado nativo? Dado que otras aplicaciones pueden, debe haber una manera.


He estado luchando con esto durante 40 días durante al menos 5-6 horas al día. No estoy seguro de si está permitido por LO, pero estoy feliz de hacer la 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 / ordena, 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. Abrir la fuente de audio VOICE_CALL ahora requiere Android.permiso.CAPTURE_AUDIO_OUTPUT que solo se concede 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 más de 200 otras grabaciones de llamadas aplicaciones aparte 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 ellos utilizan la clase Android AudioRecord y la fuente de audio open MIC. Yo también; pero en mi aplicación, solo obtengo audio de MIC, no de la otra parte. Lo que he descubierto es que me dicen que están emitiendo algún tipo de llamada al sistema justo después o antes de comenzar la grabación.

Echa un vistazo a la siguiente forma de registro una de las aplicaciones que graban con éxito VOICE_CALL, a pesar de que utiliza MIC para grabar. Parece que la aplicación es de alguna manera la gestión de mezclar/enrutar/transmitir / fusionar la fuente de audio VOICE_CALL en el MICRÓFONO.

- 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 MIC audio source input_source=1;routing=-2147483644.

Entonces, en la segunda línea que hace algo y obtener concedido android.permiso.MODIFY_AUDIO_SETTINGS que es normal permiso y mi aplicación también lo tiene. Esta parece ser la parte más importante y parece que todos 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 al MICRÓFONO 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 tales as

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

Sin suerte.

Entonces, he encontrado 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 (ya que no tengo conocimiento de C) traté de usar la reflación 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 esto información, todos rechazados. Es justo lo que he dicho. Lo publicaré una vez/si lo encuentro!

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

Author: CopsOnRoad, 2016-05-06

2 answers

Mi pareja y yo pudimos comprar lo que estábamos buscando. Estábamos en el camino correcto, fijaste KeyValuePairs en el lado nativo.

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

 10
Author: nLL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-28 19:02:44

Sus hallazgos son interesantes. He trabajado en algunos pequeños proyectos que involucran la API AudioRecord. Con suerte, lo siguiente ayudará:

Supongamos que desea configurar una instancia AudioRecord para que pueda grabar en mono de 16 bits a 16 kHz. Puede lograr esto creando una clase con algunos métodos de ayuda, 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 necesitarás mantener los mismos permisos en su lugar, ya que Marshmallow los usuarios 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 de AudioRecord

AudioCaputre API

MediaRecorder API

 0
Author: Joel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-20 03:27:15