W tym artykule znajdziesz kilka wskazówek dotyczących debugowania dźwięku na Androidzie.
Umywalka z blatem
„Tee sink” to funkcja debugowania AudioFlinger, dostępna tylko w niestandardowych wersjach, która służy do przechowywania krótkiego fragmentu ostatniego dźwięku na potrzeby późniejszej analizy. Umożliwia to porównanie tego, co zostało faktycznie odtworzone lub nagrane, z tym, co było oczekiwane.
Ze względów bezpieczeństwa tee sink jest domyślnie wyłączony zarówno w czasie kompilacji, jak i w czasie wykonywania. Aby korzystać z tee sink, musisz go włączyć, ponownie kompilując kod i ustawiając właściwość. Po zakończeniu debugowania wyłącz tę funkcję. W kompilacji produkcyjnej nie należy pozostawiać włączonego tee sink.
Instrukcje w tej sekcji dotyczą systemu Android 7.x i nowszych. W przypadku Androida 5.x i 6.x zastąp /data/misc/audioserver tekstem /data/misc/media. Dodatkowo musisz użyć wersji userdebug lub eng. Jeśli używasz kompilacji userdebug, wyłącz weryfikację:
adb root && adb disable-verity && adb reboot
Konfiguracja w czasie kompilacji
cd frameworks/av/services/audioflinger- Edytuj
Configuration.h. - Odkomentuj
#define TEE_SINK. - Zbuduj ponownie
libaudioflinger.so. adb rootadb remount- Prześlij nowe
libaudioflinger.solub zsynchronizuj je z/system/liburządzenia.
Konfiguracja środowiska wykonawczego
adb shell getprop | grep ro.debuggable
Sprawdź, czy dane wyjściowe mają postać:[ro.debuggable]: [1]adb shellls -ld /data/misc/audioserver
Sprawdź, czy dane wyjściowe:
drwx------ media media ... media
Jeśli katalog nie istnieje, utwórz go w ten sposób:
mkdir /data/misc/audioserverchown media:media /data/misc/audioserverecho af.tee=# > /data/local.prop
gdzie wartośćaf.teeto liczba opisana poniżej.chmod 644 /data/local.propreboot
Wartości właściwości af.tee
Wartość af.tee to liczba z zakresu od 0 do 7, która jest sumą kilku bitów (po jednym na każdą cechę).
Aby poznać krótkie wyjaśnienie każdego elementu, zobacz kod w pliku AudioFlinger::AudioFlinger() w folderze AudioFlinger.cpp:
- 1 = dane wejściowe
- 2 = wyjście FastMixer
- 4 = AudioRecord i AudioTrack na ścieżkę
Nie ma jeszcze bitu dla głębokiego bufora ani normalnego miksera, ale podobne wyniki można uzyskać, używając opcji „4”.
Testowanie i pozyskiwanie danych
- Uruchom test dźwięku.
adb shell dumpsys media.audio_flinger- W wyjściu
dumpsysposzukaj wiersza takiego jak ten:
tee copied to /data/misc/audioserver/20131010101147_2.wav
To jest plik PCM .wav. - Następnie
adb pulldowolne pliki/data/misc/audioserver/*.wav, które Cię interesują; pamiętaj, że nazwy plików z dumpem poszczególnych ścieżek nie pojawiają się w wyjściudumpsys, ale są nadal zapisywane w pliku/data/misc/audioserverpo zamknięciu ścieżki. - Zanim udostępnisz pliki z danymi, sprawdź, czy nie zawierają one informacji, które mogą naruszać prywatność.
Sugestie
Aby uzyskać bardziej przydatne wyniki, spróbuj:
- Wyłącz dźwięki dotykowe i kliknięcia klawiszy, aby zmniejszyć przerwy w wyświetlanych wynikach.
- Maksymalizacja wszystkich wolumenów.
- Wyłącz aplikacje, które emitują dźwięk lub nagrywają dźwięk z mikrofonu, jeśli nie są potrzebne do testu.
- Dane z konkretnej ścieżki są zapisywane tylko wtedy, gdy ścieżka jest zamknięta. Aby zapisać dane z konkretnej ścieżki, może być konieczne przymusowe zamknięcie aplikacji.
- Wykonaj
dumpsysbezpośrednio po teście. Dostępna jest ograniczona ilość miejsca na nagrania. - Aby mieć pewność, że nie stracisz plików dump, okresowo przesyłaj je do hosta. Zachowuje się tylko ograniczoną liczbę plików z danymi. Po osiągnięciu tego limitu starsze pliki z danymi są usuwane.
Przywróć
Jak już wspomnieliśmy, funkcja ujścia nie powinna być włączona. Aby przywrócić wersję i urządzenie:
- Cofnij zmiany w kodzie źródłowym do wersji
Configuration.h. - Zbuduj ponownie
libaudioflinger.so. - Prześlij przywrócone dane
libaudioflinger.sodo/system/libna urządzeniu za pomocą protokołu Push lub synchronizacji. adb shellrm /data/local.proprm /data/misc/audioserver/*.wavreboot
media.log
Makra ALOGx
Standardowym interfejsem API do rejestrowania w języku Java w pakiecie SDK Androida jest android.util.Log.
Odpowiadający interfejs API języka C w Android NDK to __android_log_print, który jest deklarowany w pliku <android/log.h>.
W rodzimej części platformy Android preferujemy makra o nazwach ALOGE, ALOGW, ALOGI, ALOGV itp. Są one deklarowane w <utils/Log.h> i w celu tego artykułu będziemy się do nich odnosić zbiorczo jako ALOGx.
Wszystkie te interfejsy API są łatwe w użyciu i dobrze rozumiane, dlatego są powszechnie stosowane na platformie Android. W szczególności proces mediaserver, który obejmuje serwer dźwiękowy AudioFlinger, intensywnie korzysta z ALOGx.
Istnieją jednak pewne ograniczenia dotyczące ALOGx i znajomych:
-
Są one podatne na „spam w logach”: bufor logów jest zasobem współdzielonym, więc może łatwo przepełnić się z powodu niezwiązanych wpisów w logach, co spowoduje utratę informacji. Wariant
ALOGVjest domyślnie wyłączony w czasie kompilacji. Ale oczywiście nawet to może powodować spam w logach, jeśli jest włączone. -
Podstawowe wywołania systemu jądra mogą być blokowane, co może spowodować odwrócenie priorytetów i w konsekwencji zakłócenia i nieścisłości pomiarów. Jest to szczególnie ważne w przypadku wątków, w których liczy się czas, takich jak
FastMixeriFastCapture. - Jeśli konkretny dziennik jest wyłączony, aby ograniczyć spam w dziennikach, wszystkie informacje, które zostałyby w nim zarejestrowane, są tracone. Nie można włączyć określonego dziennika wstecznie, po tym, jak okaże się, że był on interesujący.
NBLOG, media.log i MediaLogService
Interfejsy API NBLOG i powiązany proces media.log oraz usługa MediaLogService tworzą nowszy system rejestrowania multimediów i są specjalnie zaprojektowane, aby rozwiązywać wymienione powyżej problemy. W dalszej części tekstu będziemy używać terminu „media.log” w przypadku wszystkich trzech plików, ale ściśle mówiąc NBLOG to interfejs API do rejestrowania w C++, media.log to nazwa procesu Linuxa, a MediaLogService to usługa bindera Androida do sprawdzania dzienników.
„Oś czasu” media.log to seria wpisów w logu, których względna kolejność jest zachowana.
Zgodnie z zasadą każdy wątek powinien mieć własną oś czasu.
Zalety
Zalety systemu media.log:
- Nie zaśmieca głównego dziennika, chyba że jest to konieczne.
- Może być analizowany nawet wtedy, gdy
mediaserverulega awarii lub zawiesza się. - nie blokuje osi czasu;
- zapewnia mniejsze zakłócenia skuteczności; (Oczywiście żadna forma rejestrowania nie jest całkowicie nieinwazyjna).
Architektura
Diagram poniżej pokazuje związek procesu mediaserver z procesem init przed wprowadzeniem procesu media.log:
Rysunek 1. Architektura przed wprowadzeniem media.log
Ważne informacje:
initforks i execsmediaserver.initwykrywa, żemediaservernie działa, i w razie potrzeby tworzy nową gałąź.ALOGxlogowanie się nie wyświetla.
Schemat poniżej pokazuje nowe relacje między komponentami po dodaniu do architektury elementu media.log:
Rysunek 2. Architektura po media.log
Ważne zmiany:
-
Klienci używają interfejsu API
NBLOGdo tworzenia wpisów dziennika i dołączania ich do pętli w pamięci współdzielonej. -
MediaLogServicemoże w każdej chwili zrzucić zawartość pętli. -
Bufor cykliczny jest zaprojektowany w taki sposób, że jakakolwiek usterka w wspólnej pamięci nie spowoduje awarii
MediaLogServicei nadal będzie można z niego odczytać tyle danych z bufora, na które nie wpłynęła usterka. - Pętla buforowa jest nieblokująca i nieblokująca blokady zarówno w przypadku zapisywania nowych wpisów, jak i odczytywania istniejących wpisów.
- Do zapisywania i odczytywania z bufora pętli nie są wymagane żadne wywołania systemowe jądra (inne niż opcjonalne sygnatury czasowe).
Gdzie można płacić
W Androidzie 4.4 jest tylko kilka punktów logowania w AudioFlinger, które korzystają z systemu media.log. Chociaż nowe interfejsy API nie są tak łatwe w użyciu jak ALOGx, nie są też bardzo skomplikowane.
Zachęcamy do zapoznania się z nowym systemem rejestrowania danych na wypadek, gdyby okazał się on niezbędny.
Jest to szczególnie zalecane w przypadku wątków AudioFlinger, które muszą być uruchamiane często, okresowo i bez blokowania, takich jak wątki FastMixer i FastCapture.
Instrukcje korzystania
Dodawanie logów
Najpierw musisz dodać do kodu logi.
W wątkach FastMixer i FastCapture używaj kodu takiego jak ten:
logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();
Ta linia czasu NBLog jest używana tylko przez wątki FastMixer i FastCapture, więc nie ma potrzeby wzajemnego wykluczania.
W innych wątkach AudioFlinger używaj mNBLogWriter:
mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();
W przypadku wątków innych niż FastMixer i FastCapture osi czasu wątku NBLog mogą używać zarówno sam wątek, jak i operacje bindera. NBLog::Writer nie zapewnia żadnej niejawnej wzajemnej wykluczalności na osi czasu, dlatego upewnij się, że wszystkie logi występują w kontekście, w którym jest zablokowany semafor wątku mLock.
Po dodaniu dzienników ponownie skompiluj AudioFlinger.
Uwaga: aby zapewnić bezpieczeństwo wątku, wymagana jest osobna oś czasu NBLog::Writer na każdy wątek, ponieważ osi czasu nie uwzględniają narzuconych blokad. Jeśli chcesz, aby więcej niż 1 wątek używało tej samej osi czasu, możesz zabezpieczyć kod za pomocą istniejącego semaforu (jak opisano powyżej w przypadku funkcji mLock). Zamiast funkcji NBLog::Writer możesz też użyć funkcji opakowującej NBLog::LockedWriter.
Jednak powoduje to utratę głównej zalety tego interfejsu API, czyli braku blokowania.
Pełny interfejs API NBLog znajdziesz na stronie frameworks/av/include/media/nbaio/NBLog.h.
Włączanie pliku media.log
media.log jest domyślnie wyłączona. Jest aktywna tylko wtedy, gdy wartość właściwości ro.test_harness to 1. Aby go włączyć:
adb rootadb shellecho ro.test_harness=1 > /data/local.propchmod 644 /data/local.propreboot
Połączenie zostaje utracone podczas ponownego uruchamiania:
adb shell
ps media będzie teraz wyświetlać 2 procesy:
- media.log
- mediaserver
Zapisz sobie identyfikator procesu mediaserver.
Wyświetlanie osi czasu
W każdej chwili możesz ręcznie poprosić o zrzut dzienników. To polecenie wyświetla dzienniki ze wszystkich aktywnych i ostatnich osi czasu, a potem je czyści:
dumpsys media.log
Pamiętaj, że osi czasu są niezależne od siebie i nie ma możliwości ich łączenia.
Przywracanie logów po wyłączeniu mediaserver
Teraz spróbuj zatrzymać proces mediaserver: kill -9 #, gdzie # to identyfikator procesu zapisany wcześniej. W głównym pliku media.log powinieneś zobaczyć zrzut z pliku media.log, który zawiera wszystkie logi prowadzące do awarii.logcat
dumpsys media.log