Proses debug audio

Artikel ini menjelaskan beberapa tips dan trik untuk men-debug audio Android.

Wastafel Tee

"Tee sink" bernilai fitur debug AudioFlinger, yang hanya tersedia di build kustom, untuk menyimpan fragmen pendek audio terbaru untuk analisis nanti. Hal ini memungkinkan perbandingan antara apa yang sebenarnya diputar atau direkam vs. apa yang diharapkan.

Untuk privasi, {i>tee sink<i} dinonaktifkan secara {i>default<i}, pada waktu kompilasi dan waktu proses. Untuk menggunakan {i>tee sink<i}, Anda harus mengaktifkannya dengan mengompilasi ulang, dan juga dengan menetapkan properti. Pastikan untuk menonaktifkan fitur ini setelah Anda melakukan {i>debugging<i}; {i>tee sink<i} tidak boleh dibiarkan diaktifkan di build produksi.

Petunjuk di bagian ini ditujukan untuk Android 7.x dan yang lebih baru. Untuk Android 5.x dan 6.x, ganti /data/misc/audioserver dengan /data/misc/media. Selain itu, Anda harus menggunakan userdebug atau ing. Jika Anda menggunakan build userdebug, nonaktifkan verity dengan:

adb root && adb disable-verity && adb reboot

Penyiapan waktu kompilasi

  1. cd frameworks/av/services/audioflinger
  2. Edit Configuration.h.
  3. Hapus tanda komentar #define TEE_SINK.
  4. Membuat ulang libaudioflinger.so.
  5. adb root
  6. adb remount
  7. Kirim atau sinkronkan libaudioflinger.so baru ke /system/lib perangkat.

Penyiapan run-time

  1. adb shell getprop | grep ro.debuggable
    Konfirmasi bahwa output-nya adalah: [ro.debuggable]: [1]
  2. adb shell
  3. ls -ld /data/misc/audioserver

    Pastikan output-nya:

    drwx------ media media ... media
    

    Jika direktori tidak ada, buat direktori seperti berikut:

    mkdir /data/misc/audioserver
    chown media:media /data/misc/audioserver
    
  4. echo af.tee=# > /data/local.prop
    Dengan nilai af.tee adalah angka yang dijelaskan di bawah.
  5. chmod 644 /data/local.prop
  6. reboot

Nilai untuk properti af.tee

Nilai af.tee adalah angka antara 0 dan 7, yang menyatakan adalah jumlah dari beberapa bit, satu per fitur. Lihat kode di AudioFlinger::AudioFlinger() di AudioFlinger.cpp untuk penjelasan setiap bit, secara singkat:

  • 1 = masukan
  • 2 = Output FastMixer
  • 4 = AudioRecord dan AudioTrack per trek

Belum ada bit untuk {i>deep buffer <i} atau mixer normal, tapi Anda bisa mendapatkan hasil yang serupa dengan menggunakan "4".

Menguji dan memperoleh data

  1. Jalankan pengujian audio.
  2. adb shell dumpsys media.audio_flinger
  3. Cari baris dalam output dumpsys seperti ini:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    File ini adalah file .wav PCM.
  4. Lalu adb pull file /data/misc/audioserver/*.wav apa pun yang diinginkan; perhatikan bahwa nama file dump khusus jalur tidak muncul dalam output dumpsys, tetapi masih disimpan ke /data/misc/audioserver setelah jalur ditutup.
  5. Tinjau file dump untuk mengetahui masalah privasi sebelum membagikannya kepada orang lain.

Saran

Coba ide ini untuk hasil yang lebih bermanfaat:

  • Nonaktifkan suara sentuhan dan klik tombol untuk mengurangi gangguan pada output pengujian.
  • Maksimalkan semua volume.
  • Menonaktifkan aplikasi yang mengeluarkan suara atau merekam dari mikrofon, jika tidak tertarik untuk pengujian Anda.
  • Dump khusus jalur hanya disimpan saat trek ditutup; Anda mungkin perlu menutup aplikasi secara paksa untuk membuang data khusus jalur
  • Lakukan dumpsys segera setelah pengujian; ruang perekaman yang tersedia terbatas.
  • Untuk memastikan Anda tidak kehilangan file {i>dump<i} Anda, mengunggahnya ke {i> host<i} secara berkala. Hanya sejumlah kecil file dump yang dipertahankan; dump yang lebih lama akan dihapus setelah batas tersebut tercapai.

Pulihkan

Seperti disebutkan di atas, fitur {i>tee sink<i} tidak boleh dibiarkan diaktifkan. Pulihkan build dan perangkat Anda sebagai berikut:

  1. Kembalikan perubahan kode sumber ke Configuration.h.
  2. Membuat ulang libaudioflinger.so.
  3. Kirim atau sinkronkan libaudioflinger.so yang dipulihkan ke /system/lib perangkat.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

Makro ALOGx

API logging bahasa Java standar di Android SDK adalah android.util.Log.

API bahasa C yang sesuai di Android NDK __android_log_print yang dideklarasikan di <android/log.h>.

Dalam bagian native framework Android, kita lebih suka makro bernama ALOGE, ALOGW, ALOGI, ALOGV, dll. Dideklarasikan di <utils/Log.h>, dan untuk tujuan artikel ini secara kolektif kita akan menyebutnya sebagai ALOGx.

Semua API ini mudah digunakan dan dipahami dengan baik, sehingga mudah digunakan di seluruh platform Android. Khususnya mediaserver yang mencakup server suara AudioFlinger, menggunakan ALOGx secara ekstensif.

Meskipun demikian, ada beberapa batasan untuk ALOGx dan teman:

  • Mereka rentan terhadap "spam log": {i>buffer<i} log adalah sumber daya bersama sehingga mudah meluap karena entri log yang tidak terkait, yang mengakibatkan informasi yang terlewat. Varian ALOGV dinonaktifkan pada waktu kompilasi secara default. Namun tentu saja hal ini dapat menghasilkan spam log jika sudah diaktifkan.
  • Panggilan sistem {i>kernel<i} yang mendasarinya bisa diblokir, dan mungkin mengakibatkan inversi prioritas dan akibatnya gangguan pengukuran dan dan ketidakakuratan data. Ini dari perhatian khusus untuk thread yang mendesak seperti FastMixer dan FastCapture.
  • Jika log tertentu dinonaktifkan untuk mengurangi spam log, maka informasi apa pun yang akan ditangkap oleh log tersebut akan hilang. Log tertentu tidak dapat diaktifkan secara surut, setelah menjadi jelas bahwa log tersebut akan menarik.

NBLOG, media.log, dan MediaLogService

NBLOG API dan media.log terkait dan MediaLogService bersama-sama membentuk sistem {i>logging<i} yang lebih baru untuk media, dan secara dirancang untuk mengatasi masalah di atas. Kita akan menggunakan istilah "media.log" untuk merujuk pada ketiganya, namun NBLOG adalah API logging C++, media.log adalah nama proses Linux, dan MediaLogService adalah layanan binder Android untuk memeriksa log.

"Linimasa" media.log adalah seri entri log yang urutan relatifnya dipertahankan. Berdasarkan konvensi, setiap thread harus menggunakan linimasanya sendiri.

Manfaat

Manfaat sistem media.log adalah:

  • Tidak mengirim spam ke log utama kecuali dan hingga diperlukan.
  • Dapat diperiksa bahkan saat mediaserver mengalami error atau hang.
  • Tidak memblokir per linimasa.
  • Menawarkan lebih sedikit gangguan terhadap performa. (Tentu saja tidak ada pencatatan log yang benar-benar tidak mengganggu.)

Arsitektur

Diagram di bawah menunjukkan hubungan proses mediaserver dan proses init, sebelum media.log diperkenalkan:

Arsitektur sebelum media.log

Gambar 1. Arsitektur sebelum media.log

Poin penting:

  • init fork dan exec mediaserver.
  • init mendeteksi kematian mediaserver, dan melakukan fork ulang sesuai kebutuhan.
  • Logging ALOGx tidak ditampilkan.

Diagram di bawah ini menunjukkan hubungan baru dari komponen-komponen, setelah media.log ditambahkan ke arsitektur:

Arsitektur setelah media.log

Gambar 2. Arsitektur setelah media.log

Perubahan penting:

  • Klien menggunakan NBLOG API untuk membuat entri log dan menambahkannya ke {i>buffer<i} sirkular dalam memori bersama.
  • MediaLogService dapat membuang konten buffer sirkular kapan saja.
  • {i>Buffer<i} sirkular dirancang sedemikian rupa sehingga setiap kerusakan memori bersama tidak akan membuat error MediaLogService, dan masih dapat digunakan untuk membuang sebanyak mungkin {i>buffer<i} yang tidak terpengaruh oleh kerusakan itu.
  • Buffer sirkular tidak memblokir dan bebas kunci untuk kedua penulisan entri baru dan membaca entri yang ada.
  • Tidak ada panggilan sistem kernel yang diperlukan untuk menulis ke atau membaca dari buffer sirkular (selain stempel waktu opsional).

Lokasi penggunaan

Mulai Android 4.4, hanya ada beberapa titik log di AudioFlinger yang menggunakan sistem media.log. Meskipun API baru ini tidak mudah digunakan sebagai ALOGx, tetapi tidak terlalu sulit. Sebaiknya Anda mempelajari sistem pencatatan log baru untuk mereka peristiwa ketika hal itu sangat diperlukan. Secara khusus, direkomendasikan untuk thread AudioFlinger yang harus sering berjalan, secara berkala, dan tanpa pemblokiran seperti FastMixer dan FastCapture thread.

Cara menggunakan

Tambahkan log

Pertama, Anda harus menambahkan log ke kode Anda.

Dalam thread FastMixer dan FastCapture, gunakan kode seperti ini:

logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();

Karena linimasa NBLog ini hanya digunakan oleh FastMixer dan FastCapture rangkaian pesan, tidak perlu pengecualian bersama.

Di thread AudioFlinger lainnya, gunakan mNBLogWriter:

mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();

Untuk rangkaian pesan selain FastMixer dan FastCapture, linimasa NBLog thread dapat digunakan oleh thread itu sendiri, dan oleh operasi binder. NBLog::Writer tidak menyediakan pengecualian timbal balik implisit per linimasa, jadi pastikan bahwa semua log terjadi dalam konteks tempat mLock mutex thread ditahan.

Setelah Anda menambahkan log, build ulang AudioFlinger.

Perhatian: Linimasa NBLog::Writer terpisah diperlukan per thread, untuk memastikan keamanan thread, karena linimasa menghilangkan mutex secara desain. Jika Anda ingin lebih dari satu thread menggunakan linimasa yang sama, Anda dapat melindunginya dengan mutex yang ada (seperti yang dijelaskan di atas untuk mLock). Atau Anda bisa gunakan wrapper NBLog::LockedWriter, bukan NBLog::Writer. Namun, hal ini meniadakan manfaat utama dari API ini: fungsi non-pemblokirannya perilaku model.

API NBLog lengkap ada di frameworks/av/include/media/nbaio/NBLog.h.

Aktifkan media.log

media.log dinonaktifkan secara default. Ini hanya aktif ketika properti ro.test_harness adalah 1. Anda dapat mengaktifkannya dengan:

adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot

Koneksi terputus selama reboot, jadi:

adb shell
Perintah ps media sekarang akan menampilkan dua proses:
  • media.log
  • server media

Catat ID proses mediaserver untuk nanti.

Menampilkan linimasa

Anda dapat meminta dump log secara manual kapan saja. Perintah ini menampilkan log dari semua linimasa yang aktif dan terbaru, lalu menghapusnya:

dumpsys media.log

Perhatikan bahwa sesuai dengan desain, lini masa bersifat independen, dan tidak ada fasilitas untuk menggabungkan linimasa.

Memulihkan log setelah server media dihentikan

Sekarang coba hentikan proses mediaserver: kill -9 #, dengan # adalah ID proses yang Anda catat sebelumnya. Anda akan melihat dump dari media.log di logcat utama, yang menampilkan semua log yang mengarah ke error tersebut.

dumpsys media.log