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 jumlah 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:

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 PROPERTI_OUTPUT_FRAMES_PER_BUFFER. Ukuran buffer standar mencakup 96, 128, 160, 192, 240, 256, atau 512 frame, tetapi nilai lainnya juga memungkinkan.

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:

  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).

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 contoh aplikasi yang menampilkan latensi audio, lihat Contoh NDK.

Untuk 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