在 Android 中重定向音频/创建备用声音路径
Posted
技术标签:
【中文标题】在 Android 中重定向音频/创建备用声音路径【英文标题】:Redirecting audio / creating alternate sound paths in Android 【发布时间】:2014-01-28 06:39:08 【问题描述】:有没有人有在 android 中重定向音频或创建新声音路径的经验(使用 OpenSL ES、ALSA 等)?最终目标是创建一个虚拟麦克风来代替外部麦克风,在那里人们可以播放音频文件,就好像他们对着麦克风说话一样。使用Audiosource.MIC
访问麦克风的应用程序应使用此备用流。它没有必要与语音通话一起工作,我相信实现这种功能更难,因为这一切都在收音机内完成。
关于从哪里开始有什么想法吗?我已经对 OpenSL 和 ALSA 进行了一些研究,但看起来我需要打包新固件 (ROM) 才能定义自定义音频路径。如果可以避免,我想创建一个应用程序级解决方案。电话是“根”的(有 su 二进制文件)。目标设备是三星 Galaxy S4 Google 版 (GT-i9505G)。具体来说,我正在寻找 i9505G 的音频驱动程序配置/源代码或任何参考资料。
提前致谢!
edit - 我检查了 CyanogenMod 10.2 源代码树,以及 jfltexx 驱动程序和内核。以下是 kernel/samsung/jf/sound 的内容:http://pastebin.com/7vK8THcZ。这在任何地方都有记录吗?
【问题讨论】:
这可能是特定于平台的(例如 Qualcomm、NVidia、Samsung Exynos,...),因为可用的 ALSA 控件因不同平台而异。即使您有 root 访问权限,应用程序级别的解决方案也可能是不可能的。我曾经在 Qualcomm 平台上实现了一个新的 AudioSource,以允许应用程序记录当前播放的音频,并且 IIRC 我必须在平台 ALSA 驱动程序、音频 HAL 和 UCM(ALSA 用例管理器)配置文件中进行更改,以及在 frameworks/base 或 frameworks/av 中。 @Michael 我也希望能够录制当前播放的音频,您能否详细说明或指出一些参考资料作为起点?我很高兴有人尝试过这个,关于麦克风部分的信息很少(或者我可能还不够努力!)。我希望如果我能让麦克风部分正常工作,那么创建一个用于记录系统音频输出的源会相对简单。您是否知道驱动程序是 AOSP 的一部分,还是我必须在其他地方(即 Cyanogen 分支)找到它们?谢谢。 我无法再访问该代码。但我在this answer 中概括了我所做的事情。 This 和 this 是涉及的一些文件(在我正在使用的平台上)。 @JRC:我们在我使用过的一些手机上拥有此功能。它是一个流分离器类,允许多个录制客户端访问来自一个物理输入设备的相同数据,并由平台供应商(在本例中为 ST-Ericsson)作为 libaudioflinger 的一部分实现。我不太记得它是如何实现的,因为我没有参与编写它;当我们收到涉及记录的错误报告时,我才查看它。 @JRC:据我所知没有。这不是 Android 的标准功能。这是平台供应商向 OEM 提供的专有定制。 【参考方案1】:我曾经在基于 Qualcomm 的 APQ8064 平台(似乎与您的目标设备中的平台几乎相同)的手机上实现了您所追求的功能。下面是我可以从中回忆的摘要,因为我不再可以访问我编写的代码,或者我可以轻松进行此类修改的环境。所以如果这个答案读起来像是一堆零碎的记忆,那是因为它就是这样。
此信息也可能或多或少适用于其他 Qualcomm 平台(如 MSM8960 或 MSM8974),但很可能对其他供应商的平台(NVidia Tegra、Samsung Exynos、TI OMAP 等)完全无用。
简要说明:我使用的方法是指录音应用程序获得的音频将经过 Android 多媒体框架和/或平台的多媒体 DSP 中的混音/音量控制。因此,如果您以 75% 的音量播放某些内容、录制它,然后以 75% 的音量播放录音,它可能最终听起来很安静。如果您想获得未处理的 PCM 数据(在解码之后,但在混音/音量控制之前),您将不得不考虑其他方法,例如自定义AudioFlinger
,但这不是我尝试过的,也不能提供相关信息。
几个感兴趣的地点:
The platform's audio drivers。特别是msm-pcm-routing.c file。
The ALSA UCM (Use-Case Manager) settings file。这只是一个示例 UCM 设置文件。这些文件有许多变体,具体取决于所使用的确切平台,因此您的名称可能略有不同(尽管它应该以 snd_soc_msm_
开头),其内容也可能与我链接到的一个。Kitkat 及更高版本的注意事项: UCM 设置文件用于 Jellybean(可能还有 ICS)。我的理解是这些设置已移至 Kitkat 上名为 mixer_paths.xml
的文件中。内容几乎相同,只是格式不同。
The audio HAL code。 ALSA 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 根据用例(音乐播放、语音通话、录音等)、您附加的附件等选择。
如果您在msm-pcm-routing.c
中的msm_qdsp6_widgets table 中查找"AFE_PCM_RX Audio Mixer"
,您会看到它指的是一个看起来像这样的list of mixer controls named 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 (AFE_PCM_RX
) 的前端 DAI。要了解它们之间的关系,请参阅these diagrams。AFE_PCM_RX
和AFE_PCM_TX
是高通公司一些平台上的一对 DAI,它们实现了一种虚拟/代理设备。您所做的是将音频输入AFE_PCM_RX
,然后由多媒体DSP (QDSP) 处理,然后您可以通过AFE_PCM_TX
将其读回。这用于实现 USB 和 WiFi 音频路由,以及 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 的所有内容都将输入到 AFE_PCM_RX
后端 DAI。要回读它,您可以设置一个 UCM 动词来执行类似 'MultiMedia1 Mixer AFE_PCM_TX':1:1
的操作,然后您将从 pcmC0D0c
读取(这应该是默认的 ALSA 捕获设备)。
一个简单的测试是从您的手机中提取 UCM 设置文件(应该位于 /system/etc/
下的某处)并修改 "HiFi"
动词的 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 中启用了所有调试打印(即在您可以找到它的所有 cpp 文件中取消注释 #define LOG_NDEBUG 0
),它将对您有所帮助,以便您可以查看选择了哪些 UCM 动词/修饰符。
我上面描述的修改有点乏味,因为您必须涵盖所有相关动词和修饰符的所有 MultiMedia
前端 DAI。
IIRC,我能够将其简化为每个动词/修饰符仅一行:
'AFE_PCM_RX Port Mixer SLIM_0_RX':1:1
如果您查看 "HiFi
"、"HiFi Low Power
"、"HiFi Lowlatency"
动词,您会发现它们都使用 SLIMBUS_0_RX
后端 DAI,所以我通过使用 @ 987654392@ 让我可以建立从后端 DAI 到另一个后端 DAI 的连接。如果您查看msm-pcm-routing.c
中的afe_pcm_rx_port_mixer_controls
和intercon
表,您会注意到AFE_PCM_RX Port Mixer
没有SLIM_0_RX
条目,因此您必须自己添加它们(这只是复制问题-粘贴一些现有的行并更改名称)。
您可能需要进行的其他一些更改:
在frameworks/base 和frameworks/av(例如AudioManager
、AudioService
、AudioSystem
)中,您必须添加一个新的AudioSource
常量并确保它在所有必要的地方。
在使用新的AudioSource
时,您必须在 UCM 设置文件中添加一些新的动词/修饰符才能正确设置 ALSA 控件。
在音频 HAL 中,您必须进行一些更改,以便在使用新的 AudioSource
时选择新的动词/修饰语。请注意,有一个名为 AudioPolicyManagerBase
的 AudioPolicyManagerALSA
基类,您可能还需要对其进行修改(它是 located elsewhere in the source tree)。
【讨论】:
真的很好的解释。这很有帮助,因为我目前也在基于 MSM 的 android 设备上开发类似的数字音频捕获功能。 :) 这对语音通话有用吗,(所有虚拟麦克风的东西)因为我有很多涉及这个的想法。 嗯,不完全是。可能涉及不同的 ALSA 控制和其他步骤。参见例如***.com/questions/14432521/background-music-for-call/… 和 ***.com/questions/15204570/… ALSA UCM 设置的新链接:android.googlesource.com/device/lge/mako/+/jb-mr1-dev/… @Michael,请您参考一下这个问题:***.com/questions/42251267/… 看来它可以从您的知识中受益匪浅。如果我可以让 AudioSource.VOICE_DOWNLINK 录音在 Nexus 5X 上工作,它会解决我的问题。或者你能想到的更好的方法。我正在开发自定义 ROM,因此我可以更改任何需要的内容。以上是关于在 Android 中重定向音频/创建备用声音路径的主要内容,如果未能解决你的问题,请参考以下文章
如何在 LoginListener 中的 onSecurityInteractiveLogin 方法中重定向 - Symfony2