تسجيل صوت عالي الجودة بمعدل بت منخفض باستخدام xHE-AAC

بدءًا من الإصدار Android 17 QPR1 (مستوى واجهة برمجة التطبيقات 37.1 أو Build.VERSION_CODES_FULL.CINNAMON_BUN_1)، يتيح نظام التشغيل Android إمكانية ترميز الترميز المتقدّم للصوت عالي الكفاءة الموسّع (xHE-AAC).

يجمع ترميز xHE-AAC، المحدّد في ISO/IEC 23003-3 (MPEG-D USAC) وISO/IEC 23003-4 (MPEG-D DRC)، بين ترميز Unified Speech and Audio Coding (USAC) وبين ميزة تسوية مستوى الصوت الإلزامية وميزة التحكّم المضمّنة في النطاق الديناميكي. على الرغم من أنّ فك ترميز xHE-AAC كان متاحًا ومطلوبًا بموجب مستند تعريف التوافق مع Android (CDD) في إصدارات متعددة من النظام الأساسي، فإنّ إضافة برنامج ترميز xHE-AAC (c2.android.xheaac.encoder وعمليات التنفيذ على أجهزة OEM) تتيح لك تسجيل الرسائل الصوتية والرسائل الصوتية المباشرة وحِزم بيانات الاتصال بمعدل بت منخفض وبوضوح فائق للصوت ومستوى صوت ثابت على جميع الأجهزة.

مزايا ترميز xHE-AAC

يستخدم التسجيل الصوتي التقليدي في تطبيقات المراسلة على Android عادةً ترميز AAC-LC (ترميز AAC منخفض التعقيد) القديم بمعدل 28 كيلوبت في الثانية. عند معدلات نقل بيانات منخفضة (<32 كيلوبت في الثانية)، يعرض ترميز AAC-LC تشويشًا ملحوظًا في نطاق التردد، وجودة صوت غير واضحة، وكفاءة ضغط دون المستوى المطلوب. بالنسبة إلى المستخدمين النهائيين، يؤدي ذلك إلى تشويش الصوت وصعوبة تمييز الحروف الساكنة، ما يستدعي إعادة تشغيل الرسائل أو بذل جهد إضافي لفهم الكلام في البيئات الصاخبة. بالإضافة إلى ذلك، تؤدي مستويات الصوت غير المتسقة في المقاطع الصوتية إلى اضطرار المستخدمين إلى تعديل مستوى صوت الجهاز بشكل متكرر.

يتغلّب برنامج الترميز xHE-AAC على هذه القيود من خلال تطبيق خوارزميات ترميز صوتي أكثر تقدّمًا، مثل التبديل الديناميكي بين أدوات ترميز الكلام المخصّصة وأدوات الترميز الصوتي العامة، مع توسيع نطاق التردد باستخدام ميزة Spectral Band Replication (eSBR) المحسّنة وتوفير إمكانية ترميز استريو بارامترية مع القليل جدًا من الحمل الزائد للترميز الإضافي.

توفّر ميزة MPEG-D DRC المضمّنة إمكانية التحكّم الإلزامي في مستوى الصوت في ترميز xHE-AAC لتشغيل المحتوى بمستوى صوت ثابت، كما توفّر معالجة للتحكّم في النطاق الديناميكي من أجل تقديم أفضل تجربة ممكنة للمستخدمين عند الاستماع إلى المحتوى على أي منصة وفي أي بيئة.

حالات الاستخدام المستهدَفة

  • خدمات الاتصالات التفاعلية (RCS) والمراسلة الصوتية: تتوافق مع الإصدار 3.1 من ملف التعريف العام RCC.71 الصادر عن الرابطة العالمية لمشغّلي شبكات الهاتف الجوّال (GSMA) والإصدارات الأحدث، والذي يفرض استخدام برنامج الترميز xHE-AAC للمراسلة الصوتية بمعدل نقل بيانات منخفض.
  • البث المباشر للمحتوى الصوتي وبرامج البودكاست: يوفّر جودة صوتية عالية حتى عند ضعف الاتصال بشبكة الجوّال أو شبكة الأقمار الصناعية.

توفّر المنصات (المستوى 37.1 من واجهة برمجة التطبيقات أو أعلى)

يتطلّب توفير إمكانية ترميز xHE-AAC على النظام الأساسي المستوى 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 مزوّدًا بميزة تسريع الأداء على مستوى الأجهزة من مورّد مجموعة الشرائح بدلاً من برنامج الترميز على مستوى النظام الأساسي.
  • لا تتوافق الإصدارات القديمة من نظام التشغيل أو برامج ROM المعدَّلة مع ترميز xHE-AAC.
  • قبل ترميز مرفق لرسائل من جهاز إلى جهاز (مثل RCS أو الدردشة)، يجب أن تتحقّق التطبيقات أيضًا مما إذا كان جهاز الاستلام يعلن عن إمكانية فك ترميز USAC/xHE-AAC (على سبيل المثال، باستخدام ميزة اكتشاف إمكانات بروتوكول وصف الجلسة profile-level-id=55 / object=42) لمنع حدوث أخطاء في التشغيل التفاعلي على أجهزة الاستقبال القديمة.

فحص إمكانات MediaCodecList

للتحقّق مما إذا كان الجهاز الحالي يتيح ترميز xHE-AAC، تحقَّق من profileLevels لبرامج الترميز التي تتيح 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;
}

ضبط برنامج ترميز xHE-AAC وإنشاؤه

بعد التأكّد من توفّر xHE-AAC، اضبط MediaFormat على KEY_AAC_PROFILE بقيمة MediaCodecInfo.CodecProfileLevel.AACObjectXHE (القيمة 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;
}

الحدود القصوى لبرامج الترميز المتوافقة (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).