Audio à faible latence

L'audio à faible latence rend les jeux plus réalistes et plus réactifs.

Complétez la checklist suivante pour activer l'audio à faible latence dans votre jeu sur Android :

  1. Utiliser Oboe
  2. Demander le mode Performances "à faible latence"
  3. Demander le mode de partage "exclusif"
  4. Utiliser la fréquence de 48 000 Hz ou le convertisseur de taux d'échantillonnage Oboe
  5. Définir l'utilisation sur AAUDIO_USAGE_GAME
  6. Utiliser des rappels de données
  7. Éviter de bloquer des opérations dans le rappel
  8. Régler la taille de la mémoire tampon sur "Double tampon"

1. Utiliser l'API Oboe

L'API Oboe est un wrapper C++ qui appelle AAudio sur Android 8.1 (niveau d'API 27) ou version ultérieure. Sur les versions antérieures d'Android, Oboe utilise OpenSL ES.

Oboe est disponible sur GitHub ou en tant que binaire prédéfini. Oboe dispose également d'un QuirksManager qui corrige les problèmes sur des appareils spécifiques, ce qui rend votre application compatible avec un plus grand nombre d'appareils. Si vous ne pouvez pas utiliser Oboe, utilisez directement AAudio.

2. Demander le mode à faible latence

Avec Oboe ou AAudio, demandez le mode à faible latence. Sinon, vous obtenez un mode à latence plus élevée par défaut.

Oboe

builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);

AAudio

AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);

3. Demander le mode exclusif

Vous pouvez également demander un accès exclusif au tampon MMAP. Votre application n'obtiendra peut-être pas un accès exclusif, mais si tel est le cas, elle écrira directement dans un tampon lu par le DSP, ce qui donnera à votre application la latence la plus faible possible.

Oboe

builder.setSharingMode(oboe::SharingMode::Exclusive);

AAudio

AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);

4. Éviter la conversion du taux d'échantillonnage

Utilisez le taux d'échantillonnage naturel de l'appareil. Pour ce faire, ne spécifiez pas de taux d'échantillonnage. La fréquence d'échantillonnage sera presque certainement de 48 000 Hz. Si vous spécifiez un taux d'échantillonnage, le framework audio envoie vos données sur un chemin différent, qui peut avoir une latence beaucoup plus élevée.

Si vous devez utiliser un autre taux d'échantillonnage, utilisez Oboe pour effectuer la conversion du taux d'échantillonnage :

builder->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium);

5. Déclarer correctement votre cas d'utilisation

Spécifier la raison pour laquelle votre application lit du contenu audio est essentiel pour que le système applique les bons paramètres de routage, de volume et de performances. Par exemple, les jeux doivent indiquer l'utilisation de AAUDIO_USAGE_GAME pour tirer pleinement parti de l'optimisation de la latence, en particulier lorsqu'ils sont connectés à un casque Bluetooth.

Oboe

builder.setUsage(oboe::Usage::Game);

AAudio

AAudioStreamBuilder_setUsage(builder, AAUDIO_USAGE_GAME);

6. Utiliser une fonction de rappel

Utilisez un rappel pour le flux de sortie. Si vous utilisez des écritures bloquantes et que vous vous trouvez sur un appareil non compatible avec le mode MMAP AAudio, la latence peut être beaucoup plus élevée.

Oboe

builder.setDataCallback(&myCallbackObject);

AAudio

AAudioStreamBuilder_setDataCallback(builder, &my_callback_proc);

7. Éviter de bloquer le rappel

Lorsque vous utilisez un flux à faible latence, le délai entre les rappels peut être très court, à peine quelques millisecondes. Il est donc très important de ne rien faire dans le rappel qui pourrait le bloquer pendant longtemps. Si le rappel est bloqué, le tampon est insuffisant et des glitchs surviennent dans l'audio.

Évitez d'effectuer les opérations suivantes dans un rappel :

  • Allouer ou libérer de la mémoire
  • E/S de fichiers ou de réseau
  • Attendre un mutex ou un verrouillage
  • Sommeil
  • Calculs ponctuels lourds du processeur

Les rappels doivent effectuer les calculs à un rythme régulier pour une lecture fluide et sans glitchs.

8. Ajuster la taille de la mémoire tampon

Une fois que votre application ouvre le flux audio, vous devez ajuster la taille de la mémoire tampon utilisable pour une latence optimale. Oboe définit automatiquement la taille de la mémoire tampon sur deux rafales. Mais avec AAudio, la valeur par défaut est beaucoup plus élevée. Utilisez la double mise en mémoire tampon en définissant la taille de la mémoire tampon sur le double de la taille des rafales. La taille des rafales correspond à la taille maximale des rappels.

AAudio :

int32_t frames = AAudioStream_getFramesPerBurst() * 2;
AAudioStream_setBufferSizeInFrames(stream, frames);

Si la taille de la mémoire tampon est trop faible, vous risquez d'avoir des glitchs causés par des dépassements de mémoire tampon. Vous pouvez obtenir le nombre de glitchs en appelant AAudioStream_getXRunCount(stream). Augmentez la taille de la mémoire tampon si nécessaire.

Consultez la documentation GitHub Oboe pour obtenir une explication de la terminologie liée aux tampons.

OpenSL ES

Si vous êtes compatible avec des versions d'Android antérieures à la version 8.1, vous devez utiliser OpenSL ES. Si vous utilisez Oboe, vous pouvez configurer votre application pour améliorer la latence. Consultez la section Obtenir une latence optimale dans la documentation GitHub.

Résultats de la checklist

Le tableau suivant contient les mesures de la latence aller-retour (entrée-sortie) réalisées par OboeTester.

Configuration Latence (ms)
Suivre toutes les recommandations 20
Mode Performances sans faible latence 205
Non EXCLUSIF (PARTAGÉ) 26
44 100 Hz (AAudio) 160
44 100 Hz (Oboe SRC) 23
Ne pas utiliser de rappel de sortie (MMAP) 21
Ne pas utiliser de rappel de sortie (pas MMAP) 62
Taille de la mémoire tampon définie sur la valeur maximale 53