Audio in hoher Qualität und mit niedriger Bitrate mit xHE-AAC aufnehmen

Ab Android 17 QPR1 (API-Level 37.1 oder Build.VERSION_CODES_FULL.CINNAMON_BUN_1) bietet Android Plattformunterstützung für die xHE-AAC-Codierung (Extended High Efficiency Advanced Audio Coding).

xHE-AAC ist in ISO/IEC 23003-3 (MPEG-D USAC) und ISO/IEC 23003-4 (MPEG-D DRC) definiert und kombiniert Unified Speech and Audio Coding mit obligatorischer Lautstärkenormalisierung und integrierter dynamischer Bereichssteuerung. Die Decodierung von xHE-AAC wird in mehreren Plattformversionen unterstützt und ist im Android Compatibility Definition Document (CDD) vorgeschrieben. Durch die Ergänzung eines xHE-AAC-Encoders (c2.android.xheaac.encoder und OEM-Hardwareimplementierungen) können Sie Sprach- und Audionachrichten, Live-Audio-Streams und Kommunikationsnutzlasten mit niedriger Bitrate aufzeichnen, die eine hervorragende Sprachverständlichkeit und eine geräteübergreifend einheitliche Lautstärke bieten.

Vorteile von xHE-AAC

Bei der herkömmlichen Sprachaufzeichnung in Android-Messaging-Apps wird in der Regel das ältere AAC-LC (AAC Low Complexity) mit 28 kbps verwendet. Bei niedrigen Bitraten (<32 kbit/s) weist AAC-LC deutliche Artefakte durch Bandbegrenzung, eine undeutliche Sprachqualität und eine suboptimale Komprimierungseffizienz auf. Für Endnutzer führt dies zu einem dumpfen, blechernen Klang, bei dem Konsonanten schwer zu unterscheiden sind. Zuhörer müssen Nachrichten wiedergeben oder sich anstrengen, um Sprache in lauten Umgebungen zu verstehen. Außerdem müssen Nutzer die Lautstärke des Geräts häufig anpassen, wenn die Lautstärke der Sprachclips nicht einheitlich ist.

xHE-AAC überwindet diese Einschränkungen durch die Anwendung fortschrittlicherer Audio-Codierungsalgorithmen, z. B. durch dynamisches Umschalten zwischen speziellen Sprachcodierungs- und allgemeinen Audio-Codierungstools, während der Frequenzbereich mit Enhanced Spectral Band Replication (eSBR) erweitert wird und die Möglichkeit zur parametrischen Stereocodierung mit sehr geringem zusätzlichen Codierungsaufwand geboten wird.

Die integrierte MPEG-D DRC bietet eine obligatorische Lautstärkeregelung für xHE-AAC, um Inhalte mit einer einheitlichen Lautstärke wiederzugeben, und eine Verarbeitung zur Steuerung des Dynamikbereichs, um die bestmögliche Nutzerfreundlichkeit beim Hören auf jeder Plattform und in jeder Umgebung zu bieten.

Zielanwendungsfälle

  • Rich Communication Services (RCS) und Sprachnachrichten:Entspricht GSMA RCC.71 Universal Profile Version 3.1 und höher, in der xHE-AAC für Audio-Messaging mit niedriger Bitrate vorgeschrieben ist.
  • Live-Audio-Streaming und Podcasts:Bietet eine robuste Audioqualität über Mobilfunk- oder Satellitennetzverbindungen mit schlechter Qualität.

Plattformverfügbarkeit (API-Level 37.1 und höher)

Die Unterstützung der xHE-AAC-Codierung auf der Plattform erfordert API-Level 37.1 (Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.CINNAMON_BUN_1 / SDK 3700001 oder höher).

Unterstützung für xHE-AAC-Encoder abfragen

Sie dürfen nicht davon ausgehen, dass die xHE-AAC-Codierung auf jedem Gerät verfügbar ist, indem Sie MediaCodec.createByCodecName(...) mit "c2.android.xheaac.encoder" aufrufen.

  • Einige Geräte bieten möglicherweise einen hardwarebeschleunigten xHE-AAC-Encoder vom Chipsatzanbieter anstelle des Software-Encoders der Plattform.
  • Ältere Betriebssystemversionen oder benutzerdefinierte ROMs unterstützen die xHE-AAC-Codierung nicht.
  • Bevor eine App einen Anhang für die Peer-to-Peer-Nachrichtenübermittlung (z. B. RCS oder Chat) codiert, sollte sie prüfen, ob der empfangende Client die USAC-/xHE-AAC-Decodierung unterstützt (z. B. über die SDP-Funktionserkennung profile-level-id=55 / object=42), um Interoperabilitätsfehler auf älteren Empfängern zu vermeiden.

MediaCodecList-Funktionen prüfen

So prüfen Sie, ob das aktuelle Gerät die xHE-AAC-Codierung unterstützt:profileLevelsMediaFormat.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;
}

xHE-AAC-Encoder konfigurieren und instanziieren

Nachdem Sie die Unterstützung von xHE-AAC bestätigt haben, konfigurieren Sie MediaFormat mit KEY_AAC_PROFILE auf MediaCodecInfo.CodecProfileLevel.AACObjectXHE (Wert 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;
}

Unterstützte Software-Encoder-Limits (c2.android.xheaac.encoder)

Bei Verwendung des vom System bereitgestellten xHE-AAC-Encoders (c2.android.xheaac.encoder) gibt die Komponente die folgenden Funktionsgrenzen an:

  • Anzahl der Kanäle:Bis zu 2 Kanäle (Mono / Stereo).
  • Abtastraten:44100 Hz, 48000 Hz.
  • Bitrate-Bereich:12,000 bps bis 400,000 bps (12 kbit/s bis 400 kbit/s).
  • Container-Muxing:Kompatibel mit elementaren MP4A-Rohdatenstreams und Plattform-MP4/M4A-Container-Muxing (MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4).