Latensi adalah waktu yang dibutuhkan sinyal untuk mencapai sistem. Ada beberapa jenis umum latensi yang terkait dengan aplikasi audio:
- Latensi output audio adalah waktu dari sampel audio dibuat oleh suatu aplikasi sampai sampel tersebut diputar melalui colokan headphone atau speaker internal.
- Latensi input audio adalah waktu dari sinyal audio diterima oleh input audio perangkat, misalnya mikrofon sampai data audio tersebut tersedia untuk suatu aplikasi.
Latensi bolak-balik adalah penjumlahan dari latensi input, waktu pemrosesan aplikasi, dan latensi output.
- Latensi sentuh adalah waktu dari pengguna menyentuh layar sampai peristiwa sentuh tersebut diterima oleh suatu aplikasi.
- Latensi pemanasan adalah waktu yang diperlukan untuk memulai pipeline audio saat data pertama kali diantrekan di dalam buffer.
Halaman ini menjelaskan cara mengembangkan aplikasi audio dengan input dan output latensi rendah, dan cara menghindari latensi pemanasan.
Mengukur latensi
Latensi input dan output audio sulit diukur secara terpisah karena Anda harus mengetahui secara pasti waktu sampel pertama kali dikirim ke jalur audio (meskipun ini dapat dilakukan menggunakan sirkuit pengujian cahaya dan osiloskop). Jika latensi audio bolak-balik diketahui, Anda dapat menggunakan aturan praktis ini: latensi input (dan output) audio adalah setengah dari latensi audio bolak-balik pada jalur tanpa pemrosesan sinyal.
Latensi audio bolak-balik sangat bervariasi, bergantung model perangkat dan build Android. Anda dapat memperoleh gambaran kasar tentang latensi bolak-balik untuk perangkat Nexus dengan membaca pengukuran yang dipublikasikan.
Anda dapat mengukur latensi audio bolak-balik dengan membuat aplikasi yang menghasilkan sinyal audio, memproses sinyal tersebut, dan mengukur waktu antara pengiriman dan penerimaannya.
Karena latensi terendah dicapai pada jalur audio dengan pemrosesan sinyal minimal, Anda juga dapat menggunakan Audio Loopback Dongle, yang memungkinkan pengujian dijalankan melalui konektor headset.
Praktik terbaik untuk meminimalkan latensi
Validasikan performa audio
Compatibility Definition Document (CDD) Android menguraikan persyaratan hardware dan software perangkat Android yang kompatibel. Lihat Kompatibilitas Android untuk mengetahui informasi selengkapnya tentang program kompatibilitas secara keseluruhan, dan CDD untuk dokumen CDD sebenarnya.
Dalam CDD, latensi bolak-balik ditetapkan sebesar 20 md atau kurang (meskipun umumnya musisi meminta 10 md). Hal ini karena ada kasus penggunaan penting yang dimungkinkan dengan 20 md.
Saat ini tidak ada API untuk menentukan latensi audio pada jalur apa pun di perangkat Android pada runtime. Namun, Anda dapat menggunakan flag fitur hardware berikut untuk mengetahui apakah perangkat memberikan jaminan untuk latensi:
-
android.hardware.audio.low_latency
menunjukkan latensi output berkelanjutan selama 45 md atau kurang. -
android.hardware.audio.pro
menunjukkan latensi bolak-balik berkelanjutan selama 20 md atau kurang.
Kriteria untuk melaporkan flag tersebut ditetapkan dalam CDD di bagian 5.6 Latensi Audio dan 5.10 Audio Profesional.
Berikut cara memeriksa semua fitur ini di Java:
Kotlin
val hasLowLatencyFeature: Boolean = packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY) val hasProFeature: Boolean = packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO)
Java
boolean hasLowLatencyFeature = getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY); boolean hasProFeature = getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO);
Terkait hubungan antara beberapa fitur audio, fitur android.hardware.audio.low_latency
merupakan prasyarat untuk android.hardware.audio.pro
. Perangkat dapat mengimplementasikan
android.hardware.audio.low_latency
dan bukan android.hardware.audio.pro
, tetapi tidak
sebaliknya.
Jangan buat asumsi tentang performa audio
Waspadai asumsi berikut untuk membantu menghindari masalah latensi:
- Jangan berasumsi bahwa speaker dan mikrofon yang digunakan di perangkat seluler secara umum memiliki akustik yang baik. Karena ukuran yang kecil, akustik perangkat seluler biasanya buruk sehingga pemrosesan sinyal ditambahkan untuk memperbaiki kualitas suara. Pemrosesan sinyal ini menimbulkan latensi.
- Jangan berasumsi bahwa callback input dan output Anda disinkronkan. Untuk mendapatkan input dan output simultan, handler penyelesaian antrean buffer terpisah digunakan untuk setiap sisi. Urutan relatif semua callback atau sinkronisasi jam audio tidak dijamin, sekalipun kedua sisi menggunakan frekuensi sampel yang sama. Aplikasi Anda perlu melakukan buffer data dengan sinkronisasi buffer yang tepat.
- Jangan berasumsi bahwa frekuensi sampel sebenarnya akan sama persis dengan frekuensi sampel nominal. Misalnya, jika frekuensi sampel nominal adalah 48.000 Hz, maka normal jika jam audio maju dengan frekuensi yang sedikit berbeda dengan
CLOCK_MONOTONIC
sistem operasi. Hal ini karena jam audio dan jam sistem mungkin berasal dari kristal berbeda. - Jangan berasumsi bahwa frekuensi sampel pemutaran sebenarnya akan sama persis dengan frekuensi sampel rekaman sebenarnya, khususnya jika endpoint-nya berada di jalur terpisah. Misalnya, jika Anda merekam audio dari mikrofon perangkat pada frekuensi sampel nominal 48.000 Hz, dan memutarnya di audio USB pada frekuensi sampel nominal 48.000 Hz, maka frekuensi sampel sebenarnya mungkin akan sedikit berbeda satu sama lain.
Konsekuensi dari jam audio yang berpotensi independen adalah diperlukannya konversi frekuensi sampel asinkron. Teknik sederhana (meskipun tidak ideal untuk kualitas audio) untuk konversi frekuensi sampel asinkron adalah dengan menduplikasi atau menurunkan sampel sesuai keperluan hingga mendekati titik perpotongan-nol. Konversi yang lebih canggih dimungkinkan.
Meminimalkan latensi input
Bagian ini memberikan saran untuk membantu Anda mengurangi latensi input audio saat merekam dengan mikrofon internal atau mikrofon headset eksternal.
- Jika aplikasi Anda memantau input, sarankan agar pengguna menggunakan headset
(misalnya, dengan menampilkan Best with headphones di layar saat pertama kali dijalankan). Perlu diperhatikan, sekadar menggunakan headset tidak menjamin latensi terendah. Anda mungkin harus
melakukan langkah lain untuk menghapus pemrosesan sinyal yang tidak diinginkan dari jalur audio, misalnya
menggunakan preset
VOICE_RECOGNITION
saat merekam. - Bersiaplah untuk menangani frekuensi sampel nominal 44.100 dan 48.000 Hz sebagaimana dilaporkan oleh getProperty(String) untuk PROPERTY_OUTPUT_SAMPLE_RATE. Frekuensi sampel lainnya dimungkinkan, tetapi jarang.
- Bersiaplah untuk menangani ukuran buffer yang dilaporkan oleh getProperty(String) untuk PROPERTY_OUTPUT_FRAMES_PER_BUFFER. Ukuran buffer standar di antaranya 96, 128, 160, 192, 240, 256, atau 512 frame, tetapi nilai lainnya juga mungkin ada.
Meminimalkan latensi output
Gunakan frekuensi sampel optimal saat membuat pemutar audio
Untuk memperoleh latensi terendah, Anda harus menyuplai data audio yang cocok dengan frekuensi sampel dan ukuran buffer optimal perangkat. Untuk mengetahui informasi selengkapnya, lihat Mendesain untuk Mengurangi Latensi.
Di Java, Anda dapat memperoleh frekuensi sampel yang optimal dari AudioManager seperti ditunjukkan dalam contoh kode berikut:
Kotlin
val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager val sampleRateStr: String? = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE) var sampleRate: Int = sampleRateStr?.let { str -> Integer.parseInt(str).takeUnless { it == 0 } } ?: 44100 // Use a default value if property not found
Java
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); String sampleRateStr = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); int sampleRate = Integer.parseInt(sampleRateStr); if (sampleRate == 0) sampleRate = 44100; // Use a default value if property not found
Setelah mengetahui frekuensi sampel yang optimal, Anda dapat menyuplainya saat membuat aplikasi pemutar. Contoh ini menggunakan OpenSL ES:
// create buffer queue audio player void Java_com_example_audio_generatetone_MainActivity_createBufferQueueAudioPlayer (JNIEnv* env, jclass clazz, jint sampleRate, jint framesPerBuffer) { ... // specify the audio source format SLDataFormat_PCM format_pcm; format_pcm.numChannels = 2; format_pcm.samplesPerSec = (SLuint32) sampleRate * 1000; ... }
Catatan: samplesPerSec
mengacu pada frekuensi sampel per saluran dalam
milihertz (1 Hz = 1000 mHz).
Gunakan ukuran buffer optimal untuk mengantrekan data audio
Ukuran buffer optimal dapat diperoleh dengan cara yang sama seperti frekuensi sampel optimal, yakni menggunakan AudioManager API:
Kotlin
val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager val framesPerBuffer: String? = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER) var framesPerBufferInt: Int = framesPerBuffer?.let { str -> Integer.parseInt(str).takeUnless { it == 0 } } ?: 256 // Use default
Java
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER); int framesPerBufferInt = Integer.parseInt(framesPerBuffer); if (framesPerBufferInt == 0) framesPerBufferInt = 256; // Use default
Properti
PROPERTY_OUTPUT_FRAMES_PER_BUFFER
menunjukkan jumlah frame audio
yang dapat ditampung oleh buffer HAL (Hardware Abstraction Layer). Anda perlu membuat buffer audio untuk memuat perkalian jumlah ini secara persis. Jika Anda menggunakan jumlah frame audio yang benar, callback akan terjadi pada interval yang teratur, dan hal itu akan mengurangi jitter.
Untuk menentukan ukuran buffer, sebaiknya gunakan API, bukan menggunakan nilai hardcode, karena ukuran buffer HAL berbeda di semua perangkat dan build Android.
Jangan tambahkan antarmuka output yang melibatkan pemrosesan sinyal
Hanya antarmuka ini yang didukung oleh mixer cepat:
- SL_IID_ANDROIDSIMPLEBUFFERQUEUE
- SL_IID_VOLUME
- SL_IID_MUTESOLO
Antarmuka berikut tidak diizinkan karena melibatkan pemrosesan sinyal dan akan menyebabkan permintaan fast-track Anda ditolak:
- SL_IID_BASSBOOST
- SL_IID_EFFECTSEND
- SL_IID_ENVIRONMENTALREVERB
- SL_IID_EQUALIZER
- SL_IID_PLAYBACKRATE
- SL_IID_PRESETREVERB
- SL_IID_VIRTUALIZER
- SL_IID_ANDROIDEFFECT
- SL_IID_ANDROIDEFFECTSEND
Saat membuat aplikasi pemutar, pastikan Anda hanya menambahkan antarmuka fast, seperti ditunjukkan pada contoh berikut:
const SLInterfaceID interface_ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME };
Verifikasi bahwa Anda menggunakan track latensi rendah
Selesaikan langkah-langkah ini untuk memverifikasi apakah Anda berhasil memperoleh track rendah-latensi:
- Buka aplikasi Anda kemudian jalankan perintah berikut:
- Catat ID proses aplikasi Anda.
- Sekarang, putar audio dari aplikasi Anda. Anda memiliki waktu sekitar tiga detik untuk menjalankan perintah berikut dari terminal:
- Pindai ID proses Anda. Jika melihat F di kolom Name, artinya track latensi rendah digunakan (F adalah singkatan dari fast track).
adb shell ps | grep your_app_name
adb shell dumpsys media.audio_flinger
Minimalkan latensi pemanasan
Saat Anda mengantrekan data audio untuk pertama kalinya, sirkuit audio perangkat memerlukan sedikit waktu, tetapi tetap saja signifikan, untuk melakukan pemanasan. Untuk menghindari latensi pemanasan ini, Anda dapat mengantrekan buffer data audio yang berisi silence, seperti ditunjukkan dalam contoh berikut:
#define CHANNELS 1 static short* silenceBuffer; int numSamples = frames * CHANNELS; silenceBuffer = malloc(sizeof(*silenceBuffer) * numSamples); for (i = 0; i<numSamples; i++) { silenceBuffer[i] = 0; }
Pada tahap saat audio seharusnya dihasilkan, Anda dapat beralih mengantrekan buffer yang berisi data audio sebenarnya.
Catatan: Output audio yang terus-menerus akan meningkatkan pemakaian daya secara signifikan. Pastikan Anda menghentikan output dengan metode onPause(). Pertimbangkan juga untuk menjeda output silence setelah pengguna tidak aktif selama beberapa saat.
Kode contoh tambahan
Untuk mendownload aplikasi contoh yang menampilkan latensi audio, lihat Contoh NDK.
Untuk informasi selengkapnya
- Latensi Audio untuk Developer Aplikasi
- Kontributor Latensi Audio
- Mengukur Latensi Audio
- Pemanasan Audio
- Latensi (audio)
- Waktu tunda bolak-balik