Отладка аудио

В этой статье рассказывается о полезных советах и приемах по отладке звука на устройствах Android.

Раковина

"Тройник" – это функция отладки AudioFlinger, доступная только в специальных сборках. Она позволяет сохранять короткий фрагмент недавнего аудио для последующего анализа. Это позволяет сравнивать то, что было воспроизведено или записано, с тем, что ожидалось.

В целях конфиденциальности приемник tee отключен по умолчанию как во время компиляции, так и во время выполнения. Чтобы использовать приемник tee, его нужно включить, выполнив повторную компиляцию и задав свойство. Не забудьте отключить эту функцию после завершения отладки. В рабочих сборках tee sink не должен быть включен.

Инструкции в этом разделе предназначены для Android 7.x и более поздних версий. Для Android 5.x и 6.x замените /data/misc/audioserver на /data/misc/media. Кроме того, необходимо использовать сборку userdebug или eng. Если вы используете сборку userdebug, отключите проверку с помощью следующей команды:

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

Настройка во время компиляции

  1. cd frameworks/av/services/audioflinger
  2. Изменить набор "Configuration.h".
  3. Раскомментируйте #define TEE_SINK.
  4. Пересоздайте libaudioflinger.so.
  5. adb root
  6. adb remount
  7. Отправьте или синхронизируйте новый файл libaudioflinger.so с файлом /system/lib на устройстве.

Настройка во время выполнения

  1. adb shell getprop | grep ro.debuggable
    Убедитесь, что результат выглядит так: [ro.debuggable]: [1]
  2. adb shell
  3. ls -ld /data/misc/audioserver

    Убедитесь, что вывод выглядит следующим образом:

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

    Если каталога нет, создайте его, выполнив следующие действия:

    mkdir /data/misc/audioserver
    chown media:media /data/misc/audioserver
    
  4. echo af.tee=# > /data/local.prop
    где значение af.tee – это число, описанное ниже.
  5. chmod 644 /data/local.prop
  6. reboot

Значения для свойства af.tee

Значение атрибута af.tee – это число от 0 до 7, представляющее собой сумму нескольких битов, по одному на каждый признак. Описание каждого бита приведено в коде по адресу AudioFlinger::AudioFlinger() в AudioFlinger.cpp, но вкратце:

  • 1 – вход;
  • 2 – выход FastMixer.
  • 4 – AudioRecord и AudioTrack для каждой дорожки.

Пока нет бита для глубокого буфера или обычного микшера, но вы можете получить похожие результаты, используя "4".

Тестирование и получение данных

  1. Запустите проверку аудио.
  2. adb shell dumpsys media.audio_flinger
  3. Найдите в выходных данных dumpsys строку, похожую на следующую:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    Это PCM-файл в формате WAV.
  4. Затем adb pull нужные файлы /data/misc/audioserver/*.wav. Обратите внимание, что названия дампов, относящихся к определенным трекам, не появляются в выходных данных dumpsys, но сохраняются в /data/misc/audioserver после закрытия трека.
  5. Прежде чем делиться файлами дампа с другими пользователями, проверьте их на наличие конфиденциальной информации.

Рекомендации

Вот несколько советов, которые помогут вам получать более полезные результаты:

  • Отключите звуки нажатия клавиш и касания экрана, чтобы они не мешали тестированию.
  • Увеличьте громкость до максимума.
  • Отключите приложения, которые воспроизводят звук или записывают его с микрофона, если они не нужны для тестирования.
  • Дампы, относящиеся к определенному треку, сохраняются только при закрытии трека. Чтобы получить дампы, относящиеся к определенному треку, может потребоваться принудительно закрыть приложение.
  • Выполните dumpsys сразу после теста, так как объем памяти для записи ограничен.
  • Чтобы не потерять файлы дампа, периодически загружайте их на хост. Сохраняется только ограниченное количество файлов дампа. Когда это количество достигнуто, более старые файлы удаляются.

Восстановить

Как отмечалось выше, функцию tee sink не следует оставлять включенной. Чтобы восстановить сборку и устройство, выполните следующие действия:

  1. Отмените изменения в исходном коде для Configuration.h.
  2. Пересоздайте libaudioflinger.so.
  3. Отправьте или синхронизируйте восстановленный файл libaudioflinger.so с файлом /system/lib на устройстве.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

Макросы ALOGx

Стандартный API ведения журналов на языке Java в Android SDK – android.util.Log.

Соответствующий API на языке C в Android NDK: __android_log_print объявлен в <android/log.h>.

В нативной части фреймворка Android мы предпочитаем макросы с именами ALOGE, ALOGW, ALOGI, ALOGV и т. д. Они объявлены в <utils/Log.h>, и в этой статье мы будем называть их ALOGx.

Все эти API просты в использовании и понятны, поэтому они широко распространены на платформе Android. В частности, процесс mediaserver, в который входит звуковой сервер AudioFlinger, активно использует ALOGx.

Однако у ALOGx и его друзей есть ограничения:

  • Они подвержены "спаму журнала": буфер журнала является общим ресурсом, поэтому он может легко переполниться из-за несвязанных записей в журнале, что приведет к потере информации. Вариант ALOGV по умолчанию отключен во время компиляции. Но, конечно, даже это может привести к спаму в журнале, если он включен.
  • Системные вызовы ядра могут блокироваться, что может привести к инверсии приоритетов и, как следствие, к нарушениям и неточностям измерений. Это особенно важно для потоков, критичных ко времени, таких как FastMixer и FastCapture.
  • Если определенный журнал отключен, чтобы уменьшить количество спама в журналах, то любая информация, которая могла бы быть записана в этот журнал, будет потеряна. Нельзя включить определенный журнал после того, как станет ясно, что он мог бы быть полезен.

NBLOG, media.log и MediaLogService

API NBLOG и связанные с ними media.logпроцесс и MediaLogServiceсервис образуют новую систему регистрации медиаконтента, специально разработанную для решения перечисленных выше проблем. Мы будем использовать термин "media.log" для обозначения всех трех, но строго говоря, NBLOG – это Logging API C++, media.log – название процесса Linux, а MediaLogService – сервис Android binder для просмотра журналов.

media.log «хронология» – это серия записей в журнале, относительный порядок которых сохранен. По соглашению каждый поток должен использовать собственную временную шкалу.

Преимущества

Преимущества системы media.log:

  • Не засоряет основной журнал, пока это не потребуется.
  • Его можно изучить, даже если mediaserver аварийно завершает работу или зависает.
  • Неблокирующий по хронологии.
  • Меньше влияет на эффективность. (Конечно, любой способ ведения журнала в той или иной степени влияет на работу системы.)

Архитектура

На схеме ниже показано, как связаны процессы mediaserver и init до внедрения media.log.

Архитектура до файла media.log

Рисунок 1. Архитектура до media.log

Важные моменты:

  • initfork и execmediaserver.
  • init обнаруживает смерть mediaserver и при необходимости повторно разветвляется.
  • Журналы ALOGx не показываются.

На диаграмме ниже показана новая взаимосвязь компонентов после добавления в архитектуру свойства media.log.

Архитектура после media.log

Рисунок 2. Архитектура после media.log

Важные изменения

  • Клиенты используют API NBLOG для создания записей в журнале и добавления их в кольцевой буфер в общей памяти.
  • MediaLogService может в любой момент сбросить содержимое циклического буфера.
  • Круговой буфер разработан таким образом, что повреждение общей памяти не приведет к сбою MediaLogService. При этом он сможет сохранить ту часть буфера, которая не была повреждена.
  • Кольцевой буфер не блокируется и не блокирует запись новых и чтение существующих записей.
  • Для записи в кольцевой буфер или чтения из него не требуются системные вызовы ядра (за исключением необязательных временных меток).

Поддерживаемые страны

В Android 4.4 есть лишь несколько точек регистрации в AudioFlinger, которые используют систему media.log. Новые API не так просты в использовании, как ALOGx, но и не слишком сложны. Рекомендуем вам изучить новую систему ведения журналов, чтобы использовать ее в тех случаях, когда она необходима. В частности, его рекомендуется использовать для потоков AudioFlinger, которые должны выполняться часто, периодически и без блокировки, например для потоков FastMixer и FastCapture.

Как использовать презентацию

Как добавить журналы

Сначала добавьте в код журналы.

В цепочках 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::LockedWriter вместо NBLog::Writer. Однако это нивелирует основное преимущество API – его неблокирующее поведение.

Полная документация по API NBLog доступна на странице 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 покажет два процесса:
  • media.log
  • mediaserver

Запишите идентификатор процесса mediaserver.

Как посмотреть хронологию

Вы можете вручную запросить дамп журнала в любое время. Эта команда показывает журналы всех активных и недавних временных шкал, а затем очищает их:

dumpsys media.log

Обратите внимание, что временные шкалы независимы друг от друга и их нельзя объединить.

Восстановление журналов после сбоя медиасервера

Теперь попробуйте завершить процесс mediaserver: kill -9 #, где # – это идентификатор процесса, который вы записали ранее. В основном файле logcat должен появиться дамп из media.log, в котором будут показаны все журналы, предшествующие сбою.

dumpsys media.log