Enregistrer un son de haute qualité et à faible débit binaire avec xHE-AAC

À partir d'Android 17 QPR1 (niveau d'API 37.1 ou Build.VERSION_CODES_FULL.CINNAMON_BUN_1), Android introduit la prise en charge de plate-forme pour l'encodage Extended High Efficiency Advanced Audio Coding (xHE-AAC).

Défini dans les normes ISO/IEC 23003-3 (MPEG-D USAC) et ISO/IEC 23003-4 (MPEG-D DRC), xHE-AAC combine le codage audio et vocal unifié avec la normalisation obligatoire du volume sonore et le contrôle intégré de la plage dynamique. Bien que le décodage xHE-AAC soit pris en charge et obligatoire dans le document de définition de compatibilité Android (CDD) pour plusieurs versions de la plate-forme, l'ajout d'un encodeur xHE-AAC (implémentations matérielles c2.android.xheaac.encoder et OEM) vous permet d'enregistrer des messages vocaux et audio à faible débit, des flux audio en direct et des charges utiles de communication avec une clarté vocale supérieure et un volume constant sur tous les appareils.

Avantages du xHE-AAC

L'enregistrement vocal traditionnel dans les applications de messagerie Android utilise généralement l'ancien format AAC-LC (AAC Low Complexity) à 28 kbit/s. À de faibles débits (< 32 kbit/s), AAC-LC présente des artefacts de limitation de bande perceptibles, une qualité vocale floue et une efficacité de compression sous-optimale. Pour les utilisateurs finaux, cela se traduit par un son étouffé et métallique, où les consonnes sont difficiles à distinguer, ce qui oblige les auditeurs à réécouter les messages ou à faire des efforts pour comprendre la parole dans les environnements bruyants. De plus, les niveaux de volume incohérents entre les extraits vocaux obligent les utilisateurs à ajuster fréquemment le volume de l'appareil.

xHE-AAC surmonte ces limites en appliquant des algorithmes de codage audio plus avancés, par exemple en basculant dynamiquement entre des outils de codage vocal dédiés et des outils de codage audio généraux, tout en étendant la gamme de fréquences avec la réplication de bande spectrale améliorée (eSBR) et en offrant une capacité de codage stéréo paramétrique avec très peu de surcharge de codage supplémentaire.

Le DRC MPEG-D intégré fournit un contrôle obligatoire du volume pour le xHE-AAC afin de lire le contenu à un volume constant et offre un traitement de contrôle de la plage dynamique pour offrir la meilleure expérience utilisateur possible pour l'écoute sur n'importe quelle plate-forme et dans n'importe quel environnement.

Cas d'utilisation cibles

  • Services de communication enrichis (RCS) et messagerie vocale : conforme à la version 3.1 et aux versions ultérieures du profil universel GSMA RCC.71, qui impose le format xHE-AAC pour la messagerie audio à faible débit binaire.
  • Streaming audio en direct et podcasts : offre une qualité audio résiliente sur les connexions réseau mobile ou satellite dégradées.

Disponibilité de la plate-forme (niveau d'API 37.1 et versions ultérieures)

L'encodage xHE-AAC sur la plate-forme nécessite le niveau d'API 37.1 (Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.CINNAMON_BUN_1/SDK 3700001 ou version ultérieure).

Requête pour la prise en charge de l'encodeur xHE-AAC

Vous ne devez pas supposer que l'encodage xHE-AAC est disponible sur tous les appareils en appelant MediaCodec.createByCodecName(...) avec "c2.android.xheaac.encoder".

  • Certains appareils peuvent fournir un encodeur xHE-AAC à accélération matérielle du fournisseur du chipset plutôt que l'encodeur logiciel de la plate-forme.
  • Les anciennes versions de l'OS ou les ROM personnalisées ne sont pas compatibles avec l'encodage xHE-AAC.
  • Avant d'encoder une pièce jointe pour la messagerie peer-to-peer (comme RCS ou le chat), les applications doivent également vérifier si le client de réception annonce la prise en charge du décodage USAC/xHE-AAC (par exemple, à l'aide de la découverte des capacités SDP profile-level-id=55 / object=42) pour éviter les échecs d'interopérabilité sur les anciens récepteurs.

Inspecter les capacités de MediaCodecList

Pour vérifier si l'appareil actuel est compatible avec l'encodage xHE-AAC, inspectez le profileLevels des encodeurs compatibles avec MediaFormat.MIMETYPE_AUDIO_AAC :

Kotlin

import android.media.MediaCodecInfo.CodecProfileLevel
import android.media.MediaCodecList
import android.media.MediaFormat
import android.os.Build

/**
 * Checks if the current device supports xHE-AAC audio encoding.
 */
fun isXheAacEncodingSupported(): Boolean {
    // Verify API Level >= 37.1 (CINNAMON_BUN_1 / SDK 3700001)
    if (Build.VERSION.SDK_INT_FULL < Build.VERSION_CODES_FULL.CINNAMON_BUN_1) {
        return false
    }

    val codecList = MediaCodecList(MediaCodecList.REGULAR_CODECS)
    for (codecInfo in codecList.codecInfos) {
        if (!codecInfo.isEncoder) continue

        if (MediaFormat.MIMETYPE_AUDIO_AAC in codecInfo.supportedTypes) {
            val capabilities =
                codecInfo.getCapabilitiesForType(MediaFormat.MIMETYPE_AUDIO_AAC)
            // Check if AACObjectXHE (42) is present in profileLevels
            val supportsXhe = capabilities.profileLevels.any { profileLevel ->
                profileLevel.profile == CodecProfileLevel.AACObjectXHE
            }
            if (supportsXhe) {
                return true
            }
        }
    }
    return false
}

Java

import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.os.Build;

/**
 * Checks if the current device supports xHE-AAC audio encoding.
 */
public boolean isXheAacEncodingSupported() {
    // Verify API Level >= 37.1 (CINNAMON_BUN_1 / SDK 3700001)
    if (Build.VERSION.SDK_INT_FULL < Build.VERSION_CODES_FULL.CINNAMON_BUN_1) {
        return false;
    }

    MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
    for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) {
        if (!codecInfo.isEncoder()) continue;

        for (String type : codecInfo.getSupportedTypes()) {
            if (MediaFormat.MIMETYPE_AUDIO_AAC.equals(type)) {
                MediaCodecInfo.CodecCapabilities capabilities =
                        codecInfo.getCapabilitiesForType(MediaFormat.MIMETYPE_AUDIO_AAC);
                for (CodecProfileLevel profileLevel : capabilities.profileLevels) {
                    if (profileLevel.profile == CodecProfileLevel.AACObjectXHE) {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

Configurer et instancier l'encodeur xHE-AAC

Une fois que vous avez vérifié la compatibilité avec xHE-AAC, configurez votre MediaFormat avec KEY_AAC_PROFILE défini sur MediaCodecInfo.CodecProfileLevel.AACObjectXHE (valeur 42).

Kotlin

fun setupXheAacEncoder(): MediaCodec? {
    if (!isXheAacEncodingSupported()) {
        return null
    }

    val mimeType = MediaFormat.MIMETYPE_AUDIO_AAC
    val sampleRate = 48000
    val channelCount = 1 // Mono voice recording
    val bitRate = 20000  // 20 kbps delivers superior speech clarity

    val format = MediaFormat.createAudioFormat(mimeType, sampleRate, channelCount).apply {
        setInteger(MediaFormat.KEY_BIT_RATE, bitRate)
        setInteger(MediaFormat.KEY_AAC_PROFILE, CodecProfileLevel.AACObjectXHE)
    }

    // Find the hardware or software encoder supporting this format and profile
    val codecList = MediaCodecList(MediaCodecList.REGULAR_CODECS)
    val encoderName = codecList.findEncoderForFormat(format) ?: return null
    val encoder = MediaCodec.createByCodecName(encoderName)
    encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
    return encoder
}

Java

public MediaCodec setupXheAacEncoder() throws IOException {
    if (!isXheAacEncodingSupported()) {
        return null;
    }

    String mimeType = MediaFormat.MIMETYPE_AUDIO_AAC;
    int sampleRate = 48000;
    int channelCount = 1; // Mono voice recording
    int bitRate = 20000;  // 20 kbps delivers superior speech clarity

    MediaFormat format = MediaFormat.createAudioFormat(mimeType, sampleRate, channelCount);
    format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
    format.setInteger(MediaFormat.KEY_AAC_PROFILE, CodecProfileLevel.AACObjectXHE);

    // Find the hardware or software encoder supporting this format and profile
    MediaCodecList codecList =
            new MediaCodecList(MediaCodecList.REGULAR_CODECS);
    String encoderName = codecList.findEncoderForFormat(format);
    if (encoderName == null) {
        return null;
    }

    MediaCodec encoder = MediaCodec.createByCodecName(encoderName);
    encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    return encoder;
}

Limites des logiciels d'encodage compatibles (c2.android.xheaac.encoder)

Lorsque vous utilisez l'encodeur logiciel xHE-AAC fourni par le système (c2.android.xheaac.encoder), le composant annonce les limites de capacité suivantes :

  • Nombre de canaux : jusqu'à 2 canaux (mono / stéréo).
  • Taux d'échantillonnage : 44100 Hz, 48000 Hz.
  • Plage de débit : de 12,000 bps à 400,000 bps (12 kbit/s à 400 kbit/s).
  • Multiplexage de conteneur : compatible avec les flux élémentaires MP4A bruts et le multiplexage de conteneur MP4/M4A de la plate-forme (MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4).