Mise à jour 3 : Je me suis associé à un autre développeur et il semble que nous ayons trouvé quelqu'un qui puisse le faire pour une grosse somme d'argent. Ils nous ont envoyé un apk de test et il semble fonctionner. Nous allons aller de l'avant et acheter la source. J'espère que nous n'allons pas nous faire arnaquer. Je mettrai à jour une fois que j'aurai trouvé
Mise à jour 2 : Je travaille toujours dessus. Après des jours plus pénibles, je pense maintenant qu'il n'y a rien d'extraordinaire mais qu'ils utilisent simplement AudioFlinger ( Voir le lien ) du côté natif pour appeler AudioFlinger::setParameters
Je cherche maintenant à trouver comment je peux écrire une simple JNI pour appeler AudioFlinger::setParameters avec audio_io_handle_t ioHandle, const String8& keyValuePairs
Je sais ce qui peut paires clé-valeur être mais pas un indice sur audio_io_handle_t
Mise à jour : Je pense maintenant que d'autres applications pourraient utiliser l'audio QCOM avec CAF. Voir audio_extn_utils_send_audio_calibration à l'adresse suivante lien pour le même
et voice_get_incall_rec_snd_device à lien pour le même
Je n'ai aucune connaissance de C/++. Comment puis-je savoir si je peux appeler ces méthodes du côté natif ? Puisque d'autres applications le peuvent, il doit y avoir un moyen.
J'ai lutté contre ce problème pendant plus de 40 jours, au moins 5 à 6 heures par jour. Je ne sais pas si cela est autorisé par l'OS, mais je suis heureux de faire un don pour la bonne réponse.
J'ai une application d'enregistrement d'appels qui utilise la source audio VOICE_CALL. Bien que l'ASOP ne l'implémente pas/ne l'impose pas, la plupart des fabricants ont implémenté VOICE_CALL et les applications qui utilisent la source audio VOICE_CALL fonctionnent bien sur de nombreux appareils. Et ce jusqu'à Android 6.
Google a modifié ce comportement avec Android 6. L'ouverture de la source audio VOICE_CALL nécessite désormais la permission Android.CAPTURE_AUDIO_OUTPUT qui n'est accordée qu'aux applications système.
Cela arrête essentiellement l'enregistrement des appels, ou cela aurait dû. C'est le cas pour mon application et pour plus de 200 autres applications d'enregistrement d'appels, à l'exception de 3 qui ont trouvé un moyen de contourner cette limitation.
J'ai essayé ces applications sur de nombreux téléphones différents équipés d'Android 6 et j'ai découvert certaines caractéristiques dans la façon dont ils parviennent à enregistrer.
Ils utilisent tous la classe Android AudioRecord et une source audio MIC ouverte. Je le fais aussi ; mais sur mon application, je ne reçois que l'audio du MIC, pas de l'autre partie. Ce que j'ai découvert me dit qu'ils émettent une sorte d'appel système juste après ou avant de commencer l'enregistrement.
Regardez le journal suivant d'une des applications qui enregistre avec succès VOICE_CALL, même si elle utilise MIC pour enregistrer. Il semble que l'application réussit à mixer/router/streamer/fusionner la source audio VOICE_CALL dans le 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)
Comme vous pouvez le voir dans la première ligne, il commence avec la source audio MIC input_source=1;routing=-2147483644.
Ensuite, sur la deuxième ligne, il fait quelque chose et obtient Android.permission.MODIFY_AUDIO_SETTINGS qui est une permission normale et mon application l'a aussi. Cela semble être la partie la plus importante et il semble que les 3 utilisent JNI pour faire ce qu'ils font pour déclencher le streaming/merging de la source audio VOICE_CALL vers le MIC et enregistrer avec l'API AudioRecorder standard.
Sur la ligne suivante, vous voyez que le matériel audio commence à mélanger VOICE_CALL (input_source=4) même s'il a ouvert la source audio MIC(1).
J'ai supposé qu'ils utilisaient
AudioManager.setParameters("key=value")
et essayé de nombreuses variations telles que
AudioManager.setParameters("input_source=4;routing=-2147483584;format=1")
sans aucune chance.
Alors, j'ai trouvé Android, NDK, routage audio, forcer l'audio à travers le casque et j'ai pensé qu'il pourrait s'agir d'une façon de mixer/router/streamer/fusionner VOICE_CALL dans la session AudioRecord actuelle et (puisque je n'ai aucune connaissance en C) j'ai essayé d'utiliser la reflation pour réaliser la même chose avec le code ci-dessous (encore une fois) sans succès.
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();
}
}
Il y a manifestement quelque chose qui me manque pour rendre l'enregistrement possible.
J'ai même proposé de payer pour obtenir cette information, tous ont refusé. J'ai dit que c'était normal. Je les publierai dès que je les aurai trouvées !
Avez-vous une idée de ce qu'ils pourraient faire ?