이 문서에서는 Android 오디오 디버깅을 위한 몇 가지 팁과 요령을 설명합니다.
티 싱크
"티 싱크"는 나중에 분석할 수 있도록 최근 오디오의 짧은 조각을 유지하기 위해 사용자 정의 빌드에서만 사용할 수 있는 AudioFlinger 디버깅 기능입니다. 이를 통해 실제로 재생되거나 녹음된 것과 예상한 것을 비교할 수 있습니다.
개인 정보 보호를 위해 티 싱크는 컴파일 타임과 런타임 모두에서 기본적으로 비활성화되어 있습니다. 티 싱크를 사용하려면 다시 컴파일하고 속성을 설정하여 활성화해야 합니다. 디버깅을 마친 후에는 이 기능을 비활성화해야 합니다. 티 싱크는 프로덕션 빌드에서 활성화된 상태로 두어서는 안 됩니다.
이 섹션의 지침은 Android 7.x 이상에 대한 것입니다. Android 5.x 및 6.x의 경우 /data/misc/audioserver
를 /data/misc/media
로 바꿉니다. 또한 userdebug 또는 eng 빌드를 사용해야 합니다. userdebug 빌드를 사용하는 경우 다음을 사용하여 verity를 비활성화하십시오.
adb root && adb disable-verity && adb reboot
컴파일 타임 설정
-
cd frameworks/av/services/audioflinger
-
Configuration.h
편집.h . -
#define TEE_SINK
주석 처리를 제거하십시오. -
libaudioflinger.so
를 다시 빌드하십시오. -
adb root
-
adb remount
- 새
libaudioflinger.so
를 장치의/system/lib
에 푸시하거나 동기화합니다.
런타임 설정
-
adb shell getprop | grep ro.debuggable
출력이[ro.debuggable]: [1]
확인합니다. -
adb shell
-
ls -ld /data/misc/audioserver
출력이 다음과 같은지 확인합니다.
drwx------ media media ... media
디렉터리가 없으면 다음과 같이 만듭니다.
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
-
echo af.tee=# > /data/local.prop
여기서af.tee
값은 아래에 설명된 숫자입니다. -
chmod 644 /data/local.prop
-
reboot
af.tee
속성 값
af.tee
의 값은 0에서 7 사이의 숫자로 기능당 하나씩 여러 비트의 합을 나타냅니다. 각 비트에 대한 설명은 AudioFlinger.cpp
의 AudioFlinger::AudioFlinger()
에 있는 코드를 참조하세요.
- 1 = 입력
- 2 = FastMixer 출력
- 4 = 트랙별 AudioRecord 및 AudioTrack
딥 버퍼나 노멀 믹서는 아직 비트가 없지만 "4"를 사용하면 비슷한 결과를 얻을 수 있습니다.
데이터 테스트 및 획득
- 오디오 테스트를 실행합니다.
-
adb shell dumpsys media.audio_flinger
- 다음과 같은
dumpsys
출력에서 라인을 찾으십시오.
tee copied to /data/misc/audioserver/20131010101147_2.wav
이것은 PCM .wav 파일입니다. - 그런 다음
adb pull
는 관심 있는/data/misc/audioserver/*.wav
파일을 가져옵니다. 트랙별 덤프 파일 이름은dumpsys
출력에 나타나지 않지만 트랙이 닫힐 때 여전히/data/misc/audioserver
에 저장됩니다. - 다른 사람과 공유하기 전에 개인 정보 문제에 대한 덤프 파일을 검토하십시오.
제안
더 유용한 결과를 얻으려면 다음 아이디어를 시도하십시오.
- 테스트 출력의 중단을 줄이기 위해 터치 사운드 및 키 클릭을 비활성화합니다.
- 모든 볼륨을 최대화합니다.
- 테스트에 관심이 없는 경우 마이크에서 소리를 내거나 녹음하는 앱을 비활성화합니다.
- 트랙별 덤프는 트랙이 닫힌 경우에만 저장됩니다. 트랙별 데이터를 덤프하려면 앱을 강제 종료해야 할 수 있습니다.
- 테스트 직후에
dumpsys
를 수행하십시오. 사용 가능한 녹음 공간이 제한되어 있습니다. - 덤프 파일을 잃지 않으려면 주기적으로 호스트에 업로드하십시오. 제한된 수의 덤프 파일만 보존됩니다. 해당 제한에 도달하면 이전 덤프가 제거됩니다.
복원하다
위에서 언급했듯이 티 싱크 기능은 활성화된 상태로 두어서는 안 됩니다. 다음과 같이 빌드 및 장치를 복원합니다.
- 소스 코드 변경 사항을
Configuration.h
로 되돌립니다. -
libaudioflinger.so
를 다시 빌드하십시오. - 복원된
libaudioflinger.so
를 장치의/system/lib
에 푸시하거나 동기화합니다. -
adb shell
-
rm /data/local.prop
-
rm /data/misc/audioserver/*.wav
-
reboot
미디어.로그
ALOGx 매크로
Android SDK의 표준 Java 언어 로깅 API는 android.util.Log 입니다.
Android NDK의 해당 C 언어 API는 <android/log.h>
에 선언된 __android_log_print
입니다.
Android 프레임워크의 기본 부분 내에서 ALOGE
, ALOGW
, ALOGI
, ALOGV
등의 매크로를 선호합니다. 이들은 <utils/Log.h>
에 선언되어 있으며 이 기사의 목적을 위해 집합적으로 ALOGx
라고 부를 것입니다. .
이러한 모든 API는 사용하기 쉽고 이해하기 쉬우므로 Android 플랫폼 전체에 널리 퍼져 있습니다. 특히 mediaserver
사운드 서버를 포함하는 미디어 서버 프로세스는 ALOGx
광범위하게 사용합니다.
그럼에도 불구하고 ALOGx
와 친구들에게는 몇 가지 제한 사항이 있습니다.
- "로그 스팸"에 취약합니다. 로그 버퍼는 공유 리소스이므로 관련 없는 로그 항목으로 인해 쉽게 오버플로되어 정보가 누락될 수 있습니다.
ALOGV
변형은 기본적으로 컴파일 타임에 비활성화됩니다. 그러나 물론 활성화된 경우에도 스팸 로그가 발생할 수 있습니다. - 기본 커널 시스템 호출이 차단되어 우선 순위가 역전되어 결과적으로 측정 장애 및 부정확성이 발생할 수 있습니다. 이는
FastMixer
및FastCapture
와 같은 시간이 중요한 스레드에서 특히 중요합니다. - 로그 스팸을 줄이기 위해 특정 로그를 비활성화하면 해당 로그에 의해 캡처된 모든 정보가 손실됩니다. 로그가 흥미로웠을 것이 분명해진 후에 는 특정 로그를 소급하여 활성화할 수 없습니다.
NBLOG, media.log 및 MediaLogService
NBLOG
API와 관련 media.log
프로세스 및 MediaLogService
서비스는 함께 미디어에 대한 새로운 로깅 시스템을 형성하며 특히 위의 문제를 해결하도록 설계되었습니다. "media.log"라는 용어를 느슨하게 사용하여 세 가지 모두를 나타내지만 엄밀히 말하면 NBLOG
는 C++ 로깅 API, media.log
는 Linux 프로세스 이름, MediaLogService
는 로그 검사를 위한 Android 바인더 서비스입니다.
media.log
"타임라인"은 상대적 순서가 유지되는 일련의 로그 항목입니다. 관례에 따라 각 스레드는 자체 타임라인을 사용해야 합니다.
이익
media.log
시스템의 장점은 다음과 같습니다.
- 필요할 때까지 메인 로그를 스팸하지 않습니다.
-
mediaserver
가 충돌하거나 중단된 경우에도 검사할 수 있습니다. - 타임라인에 따라 차단되지 않습니다.
- 성능에 대한 방해가 적습니다. (물론 어떤 형태의 로깅도 완전히 방해가 되지 않습니다.)
건축물
아래 다이어그램은 media.log
가 도입되기 전의 mediaserver
프로세스와 init
프로세스의 관계를 보여줍니다.

그림 1. media.log 이전의 아키텍처
주목할만한 점:
-
init
포크 및 execmediaserver
. -
init
는mediaserver
의 죽음을 감지하고 필요에 따라 다시 포크합니다. -
ALOGx
로깅은 표시되지 않습니다.
아래 다이어그램은 media.log
가 아키텍처에 추가된 후 구성 요소의 새로운 관계를 보여줍니다.

그림 2. media.log 이후의 아키텍처
중요한 변경 사항:
- 클라이언트는
NBLOG
API를 사용하여 로그 항목을 구성하고 공유 메모리의 순환 버퍼에 추가합니다. -
MediaLogService
는 언제든지 순환 버퍼의 내용을 덤프할 수 있습니다. - 순환 버퍼는 공유 메모리의 손상으로 인해
MediaLogService
가 충돌하지 않고 손상의 영향을 받지 않는 버퍼를 최대한 많이 덤프할 수 있도록 설계되었습니다. - 순환 버퍼는 새 항목을 쓰고 기존 항목을 읽을 때 차단되지 않고 잠금이 없습니다.
- 순환 버퍼에 쓰거나 읽는 데 커널 시스템 호출이 필요하지 않습니다(선택적 타임스탬프 제외).
사용처
Android 4.4부터 AudioFlinger에는 media.log
시스템을 사용하는 로그 지점이 몇 개 없습니다. 새로운 API가 ALOGx
만큼 사용하기 쉽지는 않지만 그렇다고 아주 어렵지도 않습니다. 꼭 필요한 경우에 대비하여 새로운 로깅 시스템을 학습하는 것이 좋습니다. 특히 FastMixer
, FastCapture
쓰레드와 같이 차단 없이 자주, 주기적으로 실행되어야 하는 AudioFlinger 쓰레드에 추천합니다.
사용하는 방법
로그 추가
먼저 코드에 로그를 추가해야 합니다.
FastMixer
및 FastCapture
스레드에서 다음과 같은 코드를 사용합니다.
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
이 NBLog
타임라인은 FastMixer
및 FastCapture
스레드에서만 사용되므로 상호 배제가 필요하지 않습니다.
다른 AudioFlinger 스레드에서는 mNBLogWriter
사용:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
FastMixer
및 FastCapture
이외의 스레드의 경우 스레드의 NBLog
타임라인은 스레드 자체와 바인더 작업 모두에서 사용할 수 있습니다. NBLog::Writer
는 타임라인당 어떠한 암시적 상호 배제도 제공하지 않으므로 스레드의 뮤텍스 mLock
이 유지되는 컨텍스트 내에서 모든 로그가 발생하는지 확인하십시오.
로그를 추가한 후 AudioFlinger를 다시 빌드하십시오.
주의: 타임라인은 설계상 뮤텍스를 생략하므로 스레드 안전성을 보장하기 위해 스레드별로 별도의 NBLog::Writer
타임라인이 필요합니다. 둘 이상의 스레드가 동일한 타임라인을 사용하도록 하려면 기존 뮤텍스로 보호할 수 있습니다(위의 mLock
에 대해 설명됨). 또는 NBLog::Writer
대신 NBLog::LockedWriter
래퍼를 사용할 수 있습니다. 그러나 이는 이 API의 주요 이점인 비차단 동작을 무효화합니다.
전체 NBLog
API는 frameworks/av/include/media/nbaio/NBLog.h
에 있습니다.
media.log 활성화
media.log
는 기본적으로 비활성화되어 있습니다. ro.test_harness
속성이 1
때만 활성화됩니다. 다음을 통해 활성화할 수 있습니다.
adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot
재부팅하는 동안 연결이 끊어지므로 다음을 수행합니다.
adb shell
ps media
명령은 이제 두 가지 프로세스를 표시합니다.- 미디어.로그
- 미디어 서버
나중에 사용할 수 있도록 mediaserver
의 프로세스 ID를 기록해 두십시오.
타임라인 표시
언제든지 수동으로 로그 덤프를 요청할 수 있습니다. 이 명령은 모든 활성 및 최근 타임라인의 로그를 표시한 다음 지웁니다.
dumpsys media.log
설계상 타임라인은 독립적이며 타임라인을 병합할 수 있는 기능이 없습니다.
미디어 서버 종료 후 로그 복구
이제 mediaserver
프로세스를 종료해 보십시오. kill -9 #
, 여기서 #은 앞에서 기록해 둔 프로세스 ID입니다. 메인 logcat
의 media.log
에서 덤프가 표시되어야 하며, 충돌로 이어지는 모든 로그를 보여줍니다.
dumpsys media.log