Записывайте высококачественный звук с низким битрейтом с помощью xHE-AAC.

Starting in Android 17 QPR1 (API level 37.1 or Build.VERSION_CODES_FULL.CINNAMON_BUN_1 ), Android introduces platform support for Extended High Efficiency Advanced Audio Coding (xHE-AAC) encoding.

Определенный в стандартах ISO/IEC 23003-3 (MPEG-D USAC) и ISO/IEC 23003-4 (MPEG-D DRC) , xHE-AAC сочетает в себе унифицированное кодирование речи и звука с обязательной нормализацией громкости и встроенным управлением динамическим диапазоном. Хотя декодирование xHE-AAC поддерживается и предписывается документом Android Compatibility Definition Document (CDD) для нескольких версий платформы, добавление кодировщика xHE-AAC ( c2.android.xheaac.encoder и аппаратные реализации OEM) позволяет записывать голосовые и аудиосообщения с низким битрейтом, потоковое аудио в реальном времени и коммуникационные данные с превосходной четкостью речи и стабильной громкостью на разных устройствах.

Преимущества xHE-AAC

Традиционная запись голоса в мессенджерах Android обычно использует устаревший AAC-LC (AAC Low Complexity) с битрейтом 28 кбит/с. При низких битрейтах (<32 кбит/с) AAC-LC демонстрирует заметные артефакты ограничения полосы пропускания, нечеткое качество речи и неоптимальную эффективность сжатия. Для конечных пользователей это приводит к приглушенному, дребезжащему звуку, где согласные трудно различить, заставляя слушателей переслушивать сообщения или напрягать слух, чтобы понять речь в шумной обстановке. Кроме того, непостоянный уровень громкости в разных аудиозаписях вынуждает пользователей часто регулировать громкость устройства.

xHE-AAC overcomes these limitations by applying more advanced audio coding algorithms, for example dynamically switching between dedicated speech coding and general audio coding tools while extending frequency range with enhanced Spectral Band Replication (eSBR) and providing parametric stereo coding capability with very little additional coding overhead.

Built-in MPEG-D DRC provides mandatory loudness control for xHE-AAC to play back content at a consistent volume and offers dynamic range control processing to provide the best possible user experience for listening on any platform and in any environment.

Целевые сценарии использования

  • Расширенные коммуникационные сервисы (RCS) и голосовая связь: соответствует универсальному профилю GSMA RCC.71 версии 3.1 и более поздних версий, который требует использования xHE-AAC для передачи аудиосообщений с низкой скоростью передачи данных.
  • Прямая аудиотрансляция и подкасты: Обеспечивает стабильное качество звука даже при ухудшении качества мобильного или спутникового интернет-соединения.

Доступность платформы (уровень API 37.1+)

Для поддержки кодировки xHE-AAC на платформе требуется уровень API 37.1 ( Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.CINNAMON_BUN_1 / SDK 3700001 или выше).

Запрос на поддержку кодировщика xHE-AAC

Не следует предполагать, что кодировка xHE-AAC доступна на каждом устройстве, вызывая MediaCodec.createByCodecName(...) с "c2.android.xheaac.encoder" .

  • В некоторых устройствах вместо программного кодировщика платформы может использоваться аппаратно-ускоренный кодировщик xHE-AAC, предоставляемый производителем чипсета.
  • В более старых версиях ОС или в модифицированных ПЗУ отсутствует поддержка кодировки xHE-AAC.
  • Before encoding an attachment for peer-to-peer messaging (such as RCS or chat), apps should also check if the receiving client advertises USAC/xHE-AAC decoding support (for example, using SDP capability discovery profile-level-id=55 / object=42 ) to prevent interoperability failures on legacy receivers.

Проверьте возможности MediaCodecList.

Чтобы проверить, поддерживает ли текущее устройство кодирование xHE-AAC, проверьте profileLevels кодировщиков, поддерживающих MediaFormat.MIMETYPE_AUDIO_AAC :

Котлин

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.

После проверки поддержки xHE-AAC настройте MediaFormat , установив KEY_AAC_PROFILE равным MediaCodecInfo.CodecProfileLevel.AACObjectXHE (значение 42 ).

Котлин

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;
}

Поддерживаемые ограничения программного кодировщика ( c2.android.xheaac.encoder )

При использовании системного программного кодировщика xHE-AAC ( c2.android.xheaac.encoder ) компонент сообщает о следующих ограничениях возможностей:

  • Количество каналов: до 2 каналов (моно/стерео).
  • Частота дискретизации: 44100 Hz , 48000 Hz .
  • Диапазон битрейта: 12,000 bps до 400,000 bps (12–400 кбит/с).
  • Мультиплексирование контейнеров: Совместимо с необработанными элементарными потоками MP4A и мультиплексированием контейнеров MP4/M4A на платформе ( MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4 ).