Latensi Audio

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 latensi input dan output yang rendah, dan cara menghindari latensi pemanasan.

Mengukur latensi

Latensi input dan output audio sulit diukur secara terpisah karena Anda harus mengetahui secara pasti kapan 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, mendeteksi sinyal tersebut, dan mengukur waktu antara pengiriman dan penerimaannya. Atau, Anda dapat menginstal aplikasi pengujian latensi ini, yang menjalankan uji latensi bolak-balik menggunakan uji Larsen. Anda juga dapat melihat kode sumber untuk aplikasi pengujian latensi.

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

Memvalidasi 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 waktu proses. Namun, Anda dapat menggunakan tombol fitur hardware berikut untuk mengetahui apakah perangkat memberikan jaminan latensi:

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 membuat asumsi mengenai performa audio

Waspadailah 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 menyediakan 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 perlu 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 seperti yang 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 mencakup 96, 128, 160, 192, 240, 256, atau 512 frame, tetapi nilai lainnya juga mungkin ada.

Meminimalkan latensi output

Gunakan frekuensi sampel yang optimal saat membuat pemutar audio

Untuk memperoleh latensi terendah, Anda harus menyuplai data audio yang cocok dengan frekuensi sampel dan ukuran buffer yang optimal untuk 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 menyediakannya 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 channel dalam satuan milihertz (1 Hz = 1000 mHz).

Gunakan Ukuran Buffer yang Optimal saat Mengantrekan Data Audio

Ukuran buffer yang optimal dapat diperoleh menggunakan cara yang sama dengan frekuensi sampel yang optimal, yaitu dengan 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-beda pada semua perangkat dan build Android.

Hindari menambahkan 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:

  1. Buka aplikasi Anda kemudian jalankan perintah berikut:
  2. adb shell ps | grep your_app_name
    
  3. Catat ID proses aplikasi Anda.
  4. Sekarang, putar audio dari aplikasi Anda. Anda memiliki waktu sekitar tiga detik untuk menjalankan perintah berikut dari terminal:
  5. adb shell dumpsys media.audio_flinger
    
  6. Pindai ID proses Anda. Jika melihat F di kolom Name, artinya track latensi rendah digunakan (F adalah singkatan dari fast track).

Meminimalkan latensi pemanasan

Saat Anda mengantrekan data audio untuk pertama kali, 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 ketika audio harus dihasilkan, Anda dapat beralih ke buffer antrean yang memuat data audio sebenarnya.

Catatan: Output audio yang terus-menerus akan meningkatkan penggunaan 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 mengetahui informasi selengkapnya

  1. Latensi Audio untuk Developer Aplikasi
  2. Kontributor Latensi Audio
  3. Mengukur Latensi Audio
  4. Pemanasan Audio
  5. Latensi (audio)
  6. Waktu tunda bolak-balik