ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Android系统级音频捕获:通过ADB集成Tinycap实现命令行录音

2026/8/26 22:37:40 拓冰建站 浏览量
Android系统级音频捕获:通过ADB集成Tinycap实现命令行录音 1. 项目概述为什么要在Android SDK层面支持ADB录音在Android应用开发、系统测试乃至安全评估的日常工作中我们经常遇到一个看似简单却颇为棘手的需求如何方便、稳定地从设备上获取高质量的音频流无论是为了分析应用交互音效、录制通话质量测试样本还是进行自动化语音识别测试直接通过ADBAndroid Debug Bridge从系统层面捕获音频都是一个极具吸引力的方案。然而标准的Android SDK和ADB工具链并未直接提供一条像adb shell screenrecord录制视频那样简洁的“一键录音”命令。这就是“修改SDK支持ADB录音”这个项目标题背后所指向的核心痛点。它不是一个简单的应用层录音功能开发而是深入到Android系统框架和工具链层面通过扩展SDK特别是ADB及其相关组件的能力实现一条诸如adb shell tinycap /sdcard/test.wav这样的命令让开发者或测试人员能够绕过应用权限限制直接抓取设备的主音频输出或麦克风输入。其价值在于提供了系统级的、可脚本化的音频捕获能力极大地提升了音频相关调试和测试的效率与深度。2. 核心需求与方案选型解析2.1 需求拆解我们到底需要什么一个完整的“ADB录音”方案需要满足以下几个核心需求系统级访问能够捕获系统混音后的最终音频输出如媒体播放、游戏音效、通知声或全局的麦克风输入而非局限于单个应用。命令行驱动通过ADB命令触发和控制便于集成到自动化脚本、CI/CD流水线或远程调试场景中。格式灵活支持输出常见的音频格式如WAV、PCM方便后续用FFmpeg等工具进行处理或分析。低延迟与高保真尽量减少系统开销保证录音数据的实时性和完整性避免因音频管线复杂引入失真或延迟。权限最小化理想情况下不需要root权限即可使用以适配更广泛的测试设备。2.2 方案对比为什么选择修改SDK与集成Tinycap面对这个需求通常有几个备选方案方案A开发一个独立的录音APK。这是最直观的做法但缺点明显需要安装、需要界面或后台服务、受Android权限模型限制尤其是Android 10以上作用域存储、难以通过纯命令行精细控制。方案B利用media.provider或dumpsys media.audio_flinger。这些命令可以获取一些音频状态信息但无法直接输出原始的音频数据流。方案C修改Android系统源码添加一个新的ADB命令如adb shell audiorecord。这是最彻底、最优雅的方式但涉及AOSPAndroid Open Source Project源码的修改、编译和刷机门槛极高且难以应用到非原生系统或已上市设备。方案D修改SDK中的ADB组件或工具并集成一个已有的命令行录音工具如tinycap。这是我们项目选择的路径。它平衡了功能、难度和实用性功能强大tinycap是TinyALSA项目的一部分能够直接与Linux内核的ALSAAdvanced Linux Sound Architecture框架交互捕获最底层的PCM数据实现系统级录音。集成度高通过修改SDK的构建脚本可以将编译好的tinycap可执行文件打包进system/bin或vendor/bin目录使其成为设备系统的一部分通过ADB Shell直接调用。相对可行无需修改AOSP核心框架主要工作在SDK的构建系统和设备系统镜像打包阶段对开发者更友好。因此本项目的核心思路是在Android SDK或更具体地说在构建系统镜像时的环境中交叉编译tinycap工具并将其集成到设备的系统分区中从而通过ADB Shell提供一条强大的录音命令。3. 环境准备与工具链搭建3.1 理解Android SDK与NDK的定位开始之前必须厘清几个概念Android SDK主要提供应用开发工具如Android Studio、平台API库、系统镜像、模拟器和调试工具包括ADB。它不直接包含编译原生C/C代码的完整工具链。Android NDK原生开发工具包包含了交叉编译器如aarch64-linux-android-gcc、库和头文件专门用于编译能在Android设备ARM/ARM64 CPU上运行的原生程序。我们的工作主要依赖于NDK提供的交叉编译工具链但最终目标是将产物集成到由SDK工具如emulator、fastboot管理的系统环境中。3.2 获取与配置NDK交叉编译工具链下载NDK从Android开发者官网或通过Android Studio的SDK Manager下载NDK。建议选择一个长期支持版本如r25c避免使用过新可能有不兼容问题的版本。定位工具链NDK目录下提供了预构建的工具链。我们通常使用standalone方式或直接使用toolchains目录下的编译器。更简单的方法是使用NDK自带的make_standalone_toolchain.py脚本旧版或直接使用build/tools下的工具。以NDK r25c为例更通用的方法是直接指定编译器路径。# 假设NDK解压路径为 /home/user/android-ndk-r25c export NDK_HOME/home/user/android-ndk-r25c # 将交叉编译器的路径加入PATH这里以aarch6464位ARM为例 export TOOLCHAIN$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64 export CC$TOOLCHAIN/bin/aarch64-linux-android31-clang export CXX$TOOLCHAIN/bin/aarch64-linux-android31-clang export SYSROOT$TOOLCHAIN/sysroot注意aarch64-linux-android31-clang中的31代表目标API级别。tinycap作为系统工具通常需要较高的API级别以访问必要的系统属性或路径但底层ALSA接口是Linux内核的相对稳定。选择与你的目标设备系统API相近或稍低的级别。获取tinycap源码tinycap是tinyalsa项目的一部分。你可以从GitHub克隆tinyalsa仓库。git clone https://github.com/tinyalsa/tinyalsa.git cd tinyalsa3.3 为Android交叉编译Tinyalsatinyalsa源码目录结构清晰tinycap.c就在根目录下。我们需要编写一个简单的Android.mk或使用CMake来指导交叉编译。这里展示一个最直接的命令行编译方式它绕开了复杂的构建系统适合快速验证。准备编译命令进入tinyalsa源码目录执行以下命令。关键点在于通过-I指定头文件路径通过-L和-l指定库。# 确保环境变量已设置CC, SYSROOT等 $CC tinycap.c -o tinycap \ -I./include \ -I$SYSROOT/usr/include \ -L$SYSROOT/usr/lib \ -ltinyalsa \ -static \ -pie-I./include包含tinyalsa自己的头文件。-I$SYSROOT/usr/include包含Android NDK系统根目录中的标准头文件。-L$SYSROOT/usr/lib -ltinyalsa链接libtinyalsa.so。这里有个大坑NDK的sysroot里默认可能没有libtinyalsa.so。这是因为tinyalsa虽然是AOSP的一部分但并非NDK的标准公开库。-static静态链接。这是解决上述“坑”的最直接办法。我们不依赖动态库而是把tinyalsa的源码一起编译进来。但tinycap.c本身只包含了tinycap的工具实现我们需要找到libtinyalsa的源码并一起编译或者更简单——直接采用AOSP中编译tinyalsa的方法。更可行的实践从AOSP源码树中编译。最可靠的方式是在完整的AOSP源码环境中进行。因为AOSP的external/tinyalsa/目录下已经提供了完整的Android.bp构建文件。如果你有AOSP源码切换到该目录执行mm或mma命令即可为当前选择的午餐目标lunch target编译tinycap和libtinyalsa。编译产物如tinycap会输出在$ANDROID_PRODUCT_OUT/system/bin/目录下。这正是我们需要的、与当前系统镜像匹配的可执行文件。实操心得对于大多数开发者可能没有完整的AOSP环境。一个折中的办法是从Google的AOSP镜像仓库如https://android.googlesource.com/platform/external/tinyalsa/单独下载tinyalsa的AOSP版本源码。这个版本通常包含了适配Android构建系统Android.bp的文件。你可以尝试在NDK环境下仿照其Android.bp编写一个简单的CMakeLists.txt或直接修改Makefile进行交叉编译。核心是要确保能编译出静态链接的、不依赖外部libtinyalsa.so的tinycap二进制文件。这可能需要你将pcm.c、mixer.c等tinyalsa核心源文件加入到编译列表中。4. 集成Tinycap到系统镜像成功编译出tinycap后我们得到了一个ARM/ARM64架构的Linux可执行文件。下一步是让它出现在设备的/system/bin目录下。4.1 对于模拟器AVD如果你主要针对Android模拟器进行开发测试集成步骤相对简单将tinycap推送到模拟器启动你的AVD然后使用ADB推送。adb root # 模拟器通常支持root adb remount # 重新挂载system分区为可写 adb push tinycap /system/bin/ adb shell chmod 755 /system/bin/tinycap # 添加执行权限 adb shell chown root:shell /system/bin/tinycap # 设置正确的属主和属组 adb reboot # 重启使更改生效有时不重启也可但重启更稳妥注意高版本Android模拟器的system分区也可能是只读的adb remount可能失败。你可以尝试在启动模拟器时加入-writable-system参数或者使用emulator -avd avd_name -writable-system来启动。但这并非官方长期支持的特性可能会遇到问题。验证重启后执行adb shell which tinycap或adb shell tinycap --help如果编译时支持--help来验证是否安装成功。4.2 对于物理设备需Root对于已Root的物理设备过程与模拟器类似但风险更高且不同设备system分区的解锁和重挂载方式可能不同。启用Root权限ADB在设备开发者选项中开启“USB调试安全设置”或类似选项并在电脑上执行adb root。重挂载System分区执行adb remount。如果失败可能需要通过自定义Recovery如TWRP手动挂载/system为可写或者使用adb shell mount -o rw,remount /system命令具体参数可能因设备而异。推送与授权同模拟器步骤将tinycap推送到/system/bin/并设置权限。重启设备强烈建议重启。直接修改/system分区不重启可能导致系统不稳定。重要警告修改物理设备的/system分区有变砖风险且会破坏OTA更新能力。务必在充分备份或使用备用测试机上进行操作。4.3 构建自定义系统镜像最正规的方法对于需要量产或深度定制的场景最正规的做法是将tinycap的编译和集成纳入到你的系统固件构建流程中。在AOSP或设备厂商源码树中集成将tinyalsa包或至少tinycap添加到你的设备产品定义device.mk文件中确保它被编译并打包进system.img。# 例如在 device/xxx/yyy/device.mk 中添加 PRODUCT_PACKAGES \ tinycap重新编译系统镜像执行make -j$(nproc)重新构建。tinycap会自动出现在$OUT/system/bin/目录下的system.img中。刷机使用fastboot flash system system.img将新镜像刷入设备。这种方法一劳永逸但要求你拥有完整的设备源码和构建环境。5. 使用Tinycap进行ADB录音实操假设tinycap已经成功部署到设备的/system/bin你现在可以通过ADB Shell使用它了。5.1 基本录音命令最基础的命令格式是adb shell tinycap file_path [-D card] [-d device] [-c channels] [-r rate] [-b bits] [-p period_size] [-n period_count]file_path录音文件保存路径如/sdcard/recording.wav。注意Android 11及以上版本应用默认无法直接访问sdcard根目录建议使用应用私有目录或/data/local/tmp等临时目录。-D card声卡编号默认为0。可以通过adb shell cat /proc/asound/cards查看可用声卡。-d device设备编号默认为0。对应声卡下的子设备。-c channels声道数1为单声道2为立体声默认为2。-r rate采样率Hz如44100、48000、16000等默认为48000。-b bits采样位深16或32默认为16。-p period_size周期大小帧数影响延迟和CPU使用率高级参数。-n period_count周期数量高级参数。一个典型的录制系统声音的命令adb shell tinycap /sdcard/Music/system_audio.wav -c 2 -r 48000 -b 16执行此命令后tinycap会开始录音并在终端保持阻塞状态直到你按下CtrlC中断它录音才会停止并保存文件。5.2 录制特定音频流与设备选择Android设备可能有多个声卡和音频设备如“扬声器”、“听筒”、“蓝牙”、“USB音频”。要录制特定音频流需要先确定正确的card和device。列出音频设备adb shell cat /proc/asound/pcm输出类似00-00: ASoC PCM (*) : : playback 1-4 : capture 1-2 00-01: ASoC PCM (*) : : playback 1-4 : capture 1-2 ...更直观的方法是使用tinyalsa套件里的另一个工具tinymix如果已编译安装adb shell tinymix -D 0这可以查看声卡0的所有混音器控件帮助你识别哪个设备对应播放或录音。试错与确定通常录制系统播放音频what you hear可能对应card 0, device 0。录制麦克风输入可能对应card 0, device XX是一个用于捕获的设备。这需要结合设备硬件和驱动具体测试。一个方法是先开始一个媒体播放然后尝试用不同的-d参数运行tinycap看哪个能录到声音。5.3 高级用法时长限制与后台录制限制录音时长tinycap本身没有内置时长参数。但可以通过Shell命令组合实现adb shell “timeout 10 tinycap /sdcard/10s.wav”这条命令会录制10秒后自动停止。timeout命令在大多数Android设备的Shell中可用。后台录制与停止由于tinycap在前台运行你可以将其放入后台并稍后终止。# 在adb shell中操作 adb shell $ tinycap /sdcard/long_rec.wav [1] 12345 # 记录下PID 12345 # ... 进行一些操作 ... $ kill 12345 # 停止录音或者从电脑端通过ADB发送信号adb shell “tinycap /sdcard/long_rec.wav ” # 找到进程PID adb shell pidof tinycap # 假设返回 12345 adb shell kill 123456. 常见问题排查与实战技巧6.1 编译与部署问题问题现象可能原因解决方案编译时找不到alsa/asoundlib.h头文件路径错误或NDK sysroot不包含ALSA头文件1. 确认-I$SYSROOT/usr/include路径正确。2. Android NDK的sysroot可能确实没有完整ALSA头文件。尝试从AOSP源码的external/alsa-lib/include复制头文件或直接使用tinyalsa项目自带的include目录它已经包含了必要的接口定义。链接时找不到-ltinyalsaNDK未提供libtinyalsa.so采用静态编译。修改编译命令将tinyalsa的.c源文件如pcm.c,mixer.c直接加入编译列表而不是链接动态库。或者从已Root的设备/system/lib(64)/中提取libtinyalsa.so并将其放在链接路径中。adb push到/system/bin失败提示“Read-only file system”system分区不可写模拟器尝试以-writable-system参数启动。物理机1. 执行adb root和adb remount。2. 若失败检查设备是否已真正Root并尝试在ADB Shell中手动以root身份执行mount -o rw,remount /system。风险高。执行tinycap时提示“Permission denied”文件权限不正确adb shell chmod 755 /system/bin/tinycap。确保属主为root。6.2 运行时与录音问题问题现象可能原因解决方案运行tinycap无任何输出也不录音1. 命令参数错误。2. 默认声卡/设备无信号或不可用。3. 文件路径不可写。1. 检查命令格式确保文件路径正确且设备有足够空间。2. 尝试指定不同的-D和-d参数。先尝试录制麦克风-d可能为1或更高。3. 换一个路径如/data/local/tmp/test.wav。录制的文件大小为0或很小录音被立即中断或没有捕获到音频数据1. 确保命令执行后终端在等待状态没有立即返回。需要按CtrlC来结束。2. 确认音频源正在播放/输入。尝试播放一个已知的音频文件。3. 检查是否因为系统音频策略如Android 10以上的音频捕获策略阻止了录制。可能需要调整设备音频路由或使用其他方法触发音频播放。录音有杂音、爆音或断断续续1. 缓冲区设置-p,-n不合适。2. 系统负载过高。3. 采样参数与设备不匹配。1. 尝试调整-p增大和-n增大参数这增加了音频缓冲区可以减少因调度延迟导致的断流但会增加延迟。2. 关闭不必要的后台应用。3. 尝试标准的采样率组合如-r 48000 -b 16 -c 2。无法录制特定应用的声音如某游戏Android系统的音频隔离策略从Android 5.0开始为了安全普通应用和ADB Shell默认无法捕获其他应用播放的音频。这通常需要系统级权限或修改系统配置。tinycap录制的是“混音后”的输出但某些设备驱动或系统策略可能限制了全局捕获。这是一个硬性限制可能无法在非Root或未修改系统的设备上解决。6.3 实战技巧与心得先测试麦克风由于录制系统播放音频可能受策略限制初次测试时建议先尝试录制麦克风输入。对着麦克风说话或制造声音更容易验证tinycap是否工作正常。命令可以尝试adb shell tinycap /sdcard/mic.wav -d 1-d 1常代表第一个捕获设备。使用tinymix探路如果编译部署了tinymix它是一个强大的调试工具。通过adb shell tinymix -D 0查看所有控件你可以尝试在录音前打开某些音频通路或调整音量。例如有些设备需要打开“Loopback Mixer”或“Stereo ADC”等控件才能将内部音频路由到捕获设备。文件格式与处理tinycap默认输出的是原始的PCM数据.raw但如果你指定了.wav后缀它会在文件开头写入一个简单的WAV头。为了获得更标准的WAV文件或者需要进行格式转换最佳搭档是ffmpeg。你可以将tinycap输出的PCM数据通过管道传给ffmpeg如果设备上有或者先将PCM文件拉取到电脑再用ffmpeg处理。# 在设备上直接录制并拉取到电脑假设设备上有ffmpeg但通常没有 # 更常见的做法录制PCM文件然后拉取到电脑转换 adb shell tinycap /sdcard/rec.pcm -r 16000 -c 1 -b 16 adb pull /sdcard/rec.pcm . ffmpeg -f s16le -ar 16000 -ac 1 -i rec.pcm rec.wav自动化脚本集成将adb shell tinycap命令封装进Shell脚本或Python脚本可以轻松实现定时录音、条件触发录音等功能非常适合自动化测试场景。记得在脚本中处理好进程的启动和终止。权限与SELinux在较新的Android设备上即使Root了SELinux策略也可能阻止tinycap访问音频设备。你可能会在logcat中看到“avc: denied”相关的SELinux拒绝信息。这需要修改SELinux策略文件*.te这属于更高级的系统定制范畴风险极大。通过以上步骤你基本上就打通了从编译、部署到使用tinycap进行ADB录音的全链路。这个过程涉及了Android系统底层、交叉编译、文件系统权限等多个层面的知识虽然有些曲折但成功实现后你将获得一个极其强大的音频调试和取证工具其价值远超一个普通的应用内录音功能。