Перенаправление аудио/создание альтернативных звуковых дорожек в Android

Есть ли у кого-нибудь опыт (с использованием OpenSL ES, ALSA и т.д.) с перенаправлением звука или созданием новых звуковых дорожек в Android? Конечной целью является создание виртуального микрофона для замены внешнего микрофона, где можно воспроизводить аудиофайлы, как если бы они говорили в микрофон. Приложения, обращающиеся к микрофону с помощью AudioSource.MIC, должны использовать этот альтернативный поток. Для этого не нужно работать с голосовыми вызовами, я считаю, что достижение такого рода функций сложнее, чем все это делается в радио.

Любые идеи о том, с чего начать? Я провел некоторое исследование с OpenSL и ALSA, но похоже, что мне нужно будет упаковать новую прошивку (ROM), чтобы определить пользовательские пути аудио. Если этого можно избежать, я бы хотел создать решение на уровне приложения. Телефоны "укоренены" (имеют двоичные файлы su). Целевым устройством для этого является Samsung Galaxy S4 Google Edition (GT-i9505G). В частности, я ищу конфигурацию звукового драйвера/исходный код или любые ссылки для i9505G.

Спасибо заранее!

edit - Я проверил исходное дерево CyanogenMod 10.2 вместе с драйверами jfltexx и ядром. Вот содержимое ядра /samsung/jf/sound: http://pastebin.com/7vK8THcZ. Является ли это документированным где угодно?

Ответы

Ответ 1

Я однажды реализовал функциональные возможности, которые вы используете на телефоне на платформе Qualcomm APQ8064 (которая, похоже, почти та же платформа, что и на вашем целевом устройстве). Ниже приведено резюме того, что я могу вспомнить из этого, так как у меня больше нет доступа к написанному мной коду или к среде, где я могу легко выполнять такие модификации. Поэтому, если этот ответ читается как беспорядок фрагментарных воспоминаний, это потому, что это именно то, что есть.

Эта информация может также применяться более или менее к другим платформам Qualcomm (например, MSM8960 или MSM8974), но, скорее всего, она будет совершенно бесполезной для платформ других производителей (NVidia Tegra, Samsung Exynos, TI OMAP и т.д.).

Краткое примечание. Метод, который я использовал, означает, что звук, который получает приложение для записи, прошел через управление микшированием/громкостью в мультимедийной системе Android и/или платформе мультимедиа DSP. Поэтому, если вы играете что-то с объемом 75%, записываете его, а затем воспроизводите запись на 75% громкости, это может показаться довольно тихим. Если вы хотите получить необработанные данные PCM (после декодирования, но до смешивания/регулировки громкости), вам придется изучить другой подход, например. настраивая AudioFlinger, но это не то, что я пробовал или могу предоставить информацию.


Несколько интересных мест:

Звуковые драйверы платформы. В частности, файл msm-pcm-routing.c.

Файл настроек ALSA UCM (Use-Case Manager). Это всего лишь пример файла настроек UCM. Существует много вариантов этих файлов в зависимости от используемой точной платформы, поэтому у вас может быть несколько другое имя (хотя оно должно начинаться с snd_soc_msm_), и его содержимое, вероятно, также будет немного отличаться от того, с которым я связан.
ПРИМЕЧАНИЕ для Kitkat и более поздних версий: Файлы настроек UCM использовались на Jellybean (и, возможно, ICS). Я понимаю, что эти настройки были перенесены в файл с именем mixer_paths.xml на Kitkat. Содержимое практически одинаково, только в другом формате.

Код аудио HAL. ALCA UCM присутствует в libalsa-intf, а код AudioHardware/AudioPolicyManager/ALSADevice присутствует в audio-alsa. Обратите внимание, что этот код предназначен для Jellybean, так как это последняя версия, с которой я знаком. Структура каталогов (и, возможно, некоторые из файлов/классов) отличается от Kitkat.

Если вы откроете файл настроек UCM и выполните поиск "HiFiPROXY Rx", вы найдете что-то вроде этого:

SectionVerb
Name "HiFiPROXY Rx"

EnableSequence
    'AFE_PCM_RX Audio Mixer MultiMedia1':1:1
EndSequence

DisableSequence
    'AFE_PCM_RX Audio Mixer MultiMedia1':1:0
EndSequence

# ALSA PCMs
CapturePCM 0
PlaybackPCM 0
EndSection

Это определяет глагол (по существу, основу использования аудио файла, а также модификаторы, которые могут применяться поверх глаголов для таких вещей, как одновременное воспроизведение и запись) с именем "HiFiPROXY Rx" (прокрутка HiFi используется для большинства глаголов не-голосового вызова, PROXY относится к используемому аудиоустройству, а Rx означает вывод) и указывает, какие ALSA-элементы управления должны записывать и что писать для них, когда использование файлу следует включить/отключить. Наконец, он перечисляет устройства воспроизведения/записи ALSA PCM для использования в этом прецеденте. Например, PlaybackPCM 0 означает, что должно использоваться устройство воспроизведения 0 (предполагается, что карта ALSA является той, которая представляет встроенный аппаратный кодек, который обычно является карточкой 0). Эти глаголы выбираются аудио HAL на основе прецедента (воспроизведение музыки, голосовой вызов, запись,...), какие аксессуары вы подключили и т.д.


Если вы посмотрите "AFE_PCM_RX Audio Mixer" в msm_qdsp6_widgets table в msm-pcm-routing.c, вы увидите, что это относится к список элементов управления микшера с именем afe_pcm_rx_mixer_controls, который выглядит следующим образом:

static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
    SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_AFE_PCM_RX,
    MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
    msm_routing_put_audio_mixer),
    SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_AFE_PCM_RX,
    ... and so on...

В этом списке DAI переднего конца вам разрешено подключаться к заднему концу DAI (AFE_PCM_RX). Чтобы получить представление о том, как они относятся друг к другу, см. эти диаграммы.
AFE_PCM_RX и AFE_PCM_TX - это пара DAI на некоторых платформах Qualcomm, которые реализуют своего рода фиктивное/прокси-устройство. Что вы делаете, это передать аудио в AFE_PCM_RX, который затем обрабатывается мультимедийным DSP (QDSP), а затем вы можете прочитать его обратно через AFE_PCM_TX. Это используется для реализации маршрутизации аудио и аудио USB и Wi-Fi, а также A2DP IIRC.

Вернемся к строке AFE_PCM_RX Audio Mixer MultiMedia1: это говорит о том, что вы кормите MultiMedia1 в AFE_PCM_RX Audio Mixer. MultiMedia1 используется для нормального воспроизведения/записи и соответствует pcmC0D0 (вы должны иметь возможность отображать устройства на вашем телефоне с помощью adb shell cat /proc/asound/devices). Существуют и другие DAI переднего конца, такие как MultiMedia3 и MultiMedia5, которые используются в особых случаях, таких как воспроизведение с низкой задержкой и воспроизведение звука с низким энергопотреблением.
Когда вы подаете MultiMedia1 на AFE_PCM_RX Audio Mixer все, что вы пишете на устройство воспроизведения 0 на карточке 0, будет отправлено в DAI AFE_PCM_RX. Чтобы прочитать его, вы можете настроить глагол UCM, который делает что-то вроде 'MultiMedia1 Mixer AFE_PCM_TX':1:1, а затем вы читаете от pcmC0D0c (который должен быть устройством захвата ALSA по умолчанию).


Простым тестом было бы вытащить файл настроек UCM с вашего телефона (он должен быть расположен где-то под /system/etc/) и изменить текст "HiFi" verb EnableSequence следующим образом:

'AFE_PCM_RX Audio Mixer MultiMedia1':1:1
'AFE_PCM_RX Audio Mixer MultiMedia3':1:1
'AFE_PCM_RX Audio Mixer MultiMedia5':1:1

(и аналогично в DisableSequence, но с :1:0 в конце каждой строки).

Затем перейдите к модификатору "Capture Music" (это слабо названный модификатор для нормальной записи) и измените SLIM_0_TX на AFE_PCM_TX.

Скопируйте измененный файл настроек UCM обратно на телефон (требуется разрешение root) и перезагрузите телефон. Затем запустите некоторое воспроизведение (подключите проводную гарнитуру/наушники и отключите звуки касания, чтобы глагол с низкой задержкой не был выбран) и начните запись с AudioSource.MIC. Затем проверьте запись и посмотрите, удалось ли записать звуковой сигнал воспроизведения. Если нет, то, возможно, был выбран слабый звуковой глагол, и вам придется изменить глагол "HiFi Low Power" аналогично тому, что вы сделали с глаголом "HiFi". Это поможет вам, если у вас есть все отладочные отпечатки, включенные в аудио HAL (т.е. uncomment #define LOG_NDEBUG 0 во всех файлах cpp, где вы можете их найти), чтобы вы могли видеть, какие UCM-глаголы/модификаторы выбираются.


Модификация, описанная выше, немного утомительна, так как вы должны охватить все DAI-интерфейсы MultiMedia для всех соответствующих глаголов и модификаторов.
IIRC, я смог упростить это только в одной строке на глагол/модификатор:

'AFE_PCM_RX Port Mixer SLIM_0_RX':1:1

Если вы посмотрите на глаголы "HiFi ", "HiFi Low Power", "HiFi Lowlatency", вы увидите, что все они используют DAI конца SLIMBUS_0_RX, поэтому я пользуюсь этим, используя AFE_PCM_RX Port Mixer, который позволяет мне установить соединение с DAI заднего конца на другой DAI задней части. Если вы посмотрите таблицы afe_pcm_rx_port_mixer_controls и intercon в msm-pcm-routing.c, вы заметите, что нет записи SLIM_0_RX для AFE_PCM_RX Port Mixer, поэтому вам придется добавить их сами (это просто вопрос копирования- вставка некоторых существующих строк и изменение имен).


Некоторые другие изменения, которые вам, вероятно, придется сделать:

  • В frameworks/base и frameworks/av (например, AudioManager, AudioService, AudioSystem) вам нужно будет добавить новую константу AudioSource и убедиться, что она распознается во всех необходимых местах.

  • В файле настроек UCM вам нужно добавить несколько новых глаголов/модификаторов, чтобы правильно настроить элементы управления ALSA, когда используется ваш новый AudioSource.

  • В аудио HAL вам придется внести некоторые изменения, чтобы ваши новые глаголы/модификаторы выбирались при использовании нового AudioSource. Обратите внимание, что существует базовый класс AudioPolicyManagerALSA, называемый AudioPolicyManagerBase, который также может потребоваться изменить (он расположенный в другом месте в исходном дереве).