Od Androida 17 QPR1 (poziom interfejsu API 37.1 lubBuild.VERSION_CODES_FULL.CINNAMON_BUN_1) Android wprowadza obsługę platformy dla kodowania Extended High Efficiency Advanced Audio Coding (xHE-AAC).
Zdefiniowany w normach ISO/IEC 23003-3 (MPEG-D USAC) i ISO/IEC 23003-4 (MPEG-D DRC) kodek xHE-AAC łączy ujednolicone kodowanie mowy i dźwięku z obowiązkową normalizacją głośności i wbudowaną kontrolą zakresu dynamicznego. Dekodowanie xHE-AAC było obsługiwane i wymagane przez dokument definicji zgodności (CDD) Androida w wielu wersjach platformy. Dodanie enkodera xHE-AAC (c2.android.xheaac.encoder i implementacje sprzętowe OEM) umożliwia nagrywanie wiadomości głosowych i audio o niskiej przepływności, strumieni audio na żywo oraz pakietów danych komunikacyjnych z doskonałą czystością mowy i stałą głośnością na różnych urządzeniach.
Zalety xHE-AAC
Tradycyjne nagrywanie głosu w aplikacjach do obsługi wiadomości na Androidzie zwykle wykorzystuje starszy kodek AAC-LC (AAC Low Complexity) przy 28 kbps. Przy niskich szybkościach transmisji (<32 kb/s) kodek AAC-LC wykazuje zauważalne artefakty ograniczające pasmo, niewyraźną jakość mowy i nieoptymalną wydajność kompresji. Użytkownicy końcowi słyszą stłumiony, cienki dźwięk, w którym trudno odróżnić spółgłoski. Muszą oni ponownie odtwarzać wiadomości lub wytężać słuch, aby zrozumieć mowę w głośnym otoczeniu. Poza tym niespójne poziomy głośności w klipach głosowych zmuszają użytkowników do częstego dostosowywania głośności urządzenia.
xHE-AAC pokonuje te ograniczenia, stosując bardziej zaawansowane algorytmy kodowania dźwięku, np. dynamiczne przełączanie między dedykowanym kodowaniem mowy a ogólnymi narzędziami do kodowania dźwięku, przy jednoczesnym rozszerzaniu zakresu częstotliwości za pomocą ulepszonej replikacji pasma widma (eSBR) i zapewnianiu możliwości parametrycznego kodowania stereo przy bardzo małym dodatkowym obciążeniu kodowania.
Wbudowany MPEG-D DRC zapewnia obowiązkową kontrolę głośności w przypadku xHE-AAC, aby odtwarzać treści z równomierną głośnością, oraz oferuje przetwarzanie kontroli zakresu dynamicznego, aby zapewnić użytkownikom jak najlepsze wrażenia podczas słuchania na dowolnej platformie i w dowolnym środowisku.
Docelowe przypadki użycia
- Usługi RCS (Rich Communication Services) i wiadomości głosowe: zgodne z GSMA RCC.71 Universal Profile w wersji 3.1 lub nowszej, która wymaga używania kodeka xHE-AAC w przypadku wiadomości audio o niskiej przepływności.
- Strumieniowanie dźwięku na żywo i podcasty: zapewnia wysoką jakość dźwięku nawet przy słabym połączeniu z siecią komórkową lub satelitarną.
Dostępność platformy (interfejs API na poziomie 37.1 lub wyższym)
Obsługa kodowania xHE-AAC na platformie wymaga interfejsu API na poziomie 37.1 (Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.CINNAMON_BUN_1 / pakietu SDK 3700001 lub nowszego).
Zapytanie o obsługę kodera xHE-AAC
Nie możesz zakładać, że kodowanie xHE-AAC jest dostępne na każdym urządzeniu, wywołując MediaCodec.createByCodecName(...) z parametrem "c2.android.xheaac.encoder".
- Niektóre urządzenia mogą udostępniać akcelerowany sprzętowo koder xHE-AAC od dostawcy chipsetu zamiast kodera oprogramowania platformy.
- Starsze wersje systemu operacyjnego lub dostosowane ROM-y nie obsługują kodowania xHE-AAC.
- Przed zakodowaniem załącznika do wiadomości peer-to-peer (np. RCS lub czatu) aplikacje powinny też sprawdzić, czy klient odbierający reklamuje obsługę dekodowania USAC/xHE-AAC (np. za pomocą wykrywania możliwości SDP
profile-level-id=55/object=42), aby zapobiec problemom z interoperacyjnością na starszych odbiornikach.
Sprawdzanie możliwości MediaCodecList
Aby sprawdzić, czy bieżące urządzenie obsługuje kodowanie xHE-AAC, sprawdź profileLevels koderów obsługujących 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; }
Konfigurowanie i tworzenie instancji kodera xHE-AAC
Po sprawdzeniu, czy xHE-AAC jest obsługiwany, skonfiguruj MediaFormat, ustawiając KEY_AAC_PROFILE na MediaCodecInfo.CodecProfileLevel.AACObjectXHE (wartość 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; }
Limity obsługiwanych programowych koderów (c2.android.xheaac.encoder)
Podczas korzystania z dostarczonego przez system kodera oprogramowania xHE-AAC (c2.android.xheaac.encoder) komponent zgłasza te limity możliwości:
- Liczba kanałów: do
2kanałów (mono / stereo). - Częstotliwości próbkowania:
44100 Hz,48000 Hz. - Zakres szybkości transmisji:
12,000 bps–400,000 bps(12–400 kb/s). - Multipleksowanie kontenera: zgodne z surowymi strumieniami elementarnymi MP4A i multipleksowaniem kontenera MP4/M4A na platformie (
MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4).