DroidDeck源码构建完整教程:Docker+NDK交叉编译PulseAudio音频模块全流程
【免费下载链接】DroidDeck DroidDeck brings the SteamOS experience to Android 项目地址: https://gitcode.com/gh_mirrors/dr/DroidDeck
DroidDeck 是一款把 SteamOS 体验带到 Android 上的开源项目——在 Adreno 手柄/平板上运行 Steam Big Picture,并通过 ARM64 Proton 玩 Windows 游戏。这篇教程带你用 Docker + Android NDK 从零完成 DroidDeck 源码构建:交叉编译 PulseAudio 13.0 音频模块、打包进 pulseaudio.tzst 资源包,最终产出一份可安装的签名 APK,并附上常见报错的快速排查方法。

一、先搞清楚项目怎么跑的 🔍
在动手之前,理解"要构建出什么"能少走很多弯路。DroidDeck 的产物是一个 Android APK,核心能力由三层组成:
| 音频层 | 在 Android 上跑 PulseAudio 13.0 守护进程,用 AAudio/DirectAudio 作为音频输出 | app/src/main/assets/pulseaudio.tzst、app/src/main/jniLibs/arm64-v8a/ |
| Linux 运行层 | proot + preload 库,让 x86/ARM64 的 Linux 程序跑在 Android 上 | tools/linuxfs/、tools/proot/ |
| Android 应用层 | Kotlin 写的启动器、会话管理、组件管理 UI | app/src/main/java/com/droiddeck/launcher/ |
音频正是这次构建的主角:仓库里预置了为 Android bionic 编译好的 libpulse.so、libpulsecore-13.0.so、libpulsecommon-13.0.so(位于 app/src/main/jniLibs/arm64-v8a/),但我们必须自己用 NDK 交叉编译两个"音频输出模块"(sink)——它们把 PulseAudio 的音频流接到 Android 的 AAudio / DirectSound 驱动上。这就是整条构建链中最值得学的部分。
二、构建环境清单:一次备齐不返工 ✅
tools/build_local.sh 会在启动时逐项检查环境,缺一样都会直接报错退出。提前对照这张清单:
- Docker:用于运行 Ubuntu 24.04 交叉编译容器(构建 glibc 版 ARM64 preload 库)
- Java 17:Gradle 构建所需,设置 JAVA_HOME 指向 JDK 17
- Android SDK + NDK:设置 ANDROID_HOME(或 ANDROID_SDK_ROOT),且 sdk/ndk/ 下有完整 NDK;sdk/platform-tools/adb 必须存在
- 命令行工具:curl、tar、zstd、shasum、unzip
- gh(GitHub CLI):仅当仓库内存在固定的 release 依赖(Gamescope、wlroots、esync 包)时需要,脚本用它下载并做 sha256 校验
💡 脚本会自动在 sdk/ndk/ 里找版本号最高的完整 NDK(目录内含 source.properties)。如果你曾用 sdkmanager 安装到一半,可以显式设置 DROIDDECK_NDK_VERSION 指定版本。
三、获取源码
git clone https://gitcode.com/gh_mirrors/dr/DroidDeck
cd DroidDeck
四、Docker 交叉编译:glibc ARM64 预加载库
打开 tools/local-cross.Dockerfile 你会看到一个极简的 Dockerfile:基于 ubuntu:24.04,安装 binutils-aarch64-linux-gnu / gcc-aarch64-linux-gnu 交叉工具链。
tools/build_local.sh 首次运行时会自动构建镜像(标签 droiddeck-local-cross:24.04-v2,–platform linux/amd64,Apple 芯片的 Mac 上也能跑),随后在容器内完成三件事(tools/build_local.sh#L113-L171):
构建结束时会通过 trap 自动还原 pulseaudio.tzst 等被临时替换的文件,中断也不会污染你的工作区。
五、核心步骤:NDK 交叉编译 PulseAudio 13.0 音频模块
这是整篇文章的重点。构建脚本 tools/build_local.sh#L286-L305 分三步走:
1. 准备 PulseAudio 13.0 源码
脚本会自动下载官方 PulseAudio 13.0 源码包并缓存到 ~/.cache/droiddeck-build/;如果你想复用本地已有的源码树,设置环境变量即可跳过下载:
export DROIDDECK_PA13_SOURCE_DIR=/path/to/pulseaudio-13.0
脚本用 src/pulse/version.h.in 是否存在来验证源码目录是否有效。
2. 用 NDK 编译两个音频 sink
真正的编译由 tools/aaudio-sink/build.sh 完成,它做了几件很巧的事:
- 自动识别宿主机(darwin-arm64 / darwin-x86_64 / linux-x86_64 / linux-aarch64),选择 NDK 对应的预编译工具链(tools/aaudio-sink/build.sh#L15-L33),Mac 和 Linux 上无需任何额外配置;
- 跳过 PulseAudio 的 configure:用 tools/aaudio-sink/config.h 这份"手工版 config"提供版本号和特性宏(PACKAGE_VERSION 13.0、HAVE_MEMFD 等),再配合 sed 生成 version.h,直接对着上游头文件编译单个模块;
- 调用 NDK clang(API 26)编译出 module-aaudio-sink.so 和 module-directaudio-sink.so,链接目标就是仓库里预置的 libpulse* 三个库(tools/aaudio-sink/build.sh#L63-L64);
- 编译后做符号体检:确认 pa__init、pa__done 等 PulseAudio 加载器要求的 7 个导出符号齐全,且 NEEDED 依赖只允许是设备上一定存在的库(libaaudio.so、libc.so 等),多一个都直接失败。

3. 编译 DirectAudio 中继进程
tools/directaudio-relay/build.sh 会编译 directaudio-relay.c——一个独立的 bionic 辅助进程:它替无法直接持有音频流的驱动实例代管所有 AAudio 流,通过 Unix socket 与游戏进程交接共享环形缓冲区,并把麦克风共享给 Steam 客户端。构建参数要求 NDK r27、API 28,并带 -Wl,-z,max-page-size=16384 保证 16KB 大页兼容。
4. 塞进 pulseaudio.tzst 资源包
构建脚本会解开仓库中提交的 app/src/main/assets/pulseaudio.tzst 音频包,把两个新编译的模块安装到包内的 modules/arm64/ 目录,再用 zstd -19 最高压缩率重新打包(tools/build_local.sh#L317-L332)。注意脚本有防呆检查:如果提交的包里已经存在编译好的 sink,会直接报错退出,避免重复打包。
六、一条命令完成 APK 构建
环境就绪后,在项目根目录执行:
./tools/build_local.sh
默认构建 release 版(可用 DROIDDECK_BUILD_VARIANT=debug 切换),它还会依次完成:
全部通过后,终端会打印 APK 路径和 SHA-256 值。

七、安装到设备并验证 🚀
./tools/deploy_local.sh
该脚本会通过 adb 把刚构建的 APK 推送到已连接的设备。安装后打开应用、安装 Linux 运行时并启动会话,如果游戏声音正常输出、麦克风可用,说明你交叉编译的 PulseAudio 音频模块已经在工作了。
八、常见坑位快速排查 🛠️
| Android SDK not found | 未设置 ANDROID_HOME / ANDROID_SDK_ROOT,或 SDK 下没有 platform-tools/adb |
| No Android NDK found under … | NDK 不完整(sdkmanager 中断会留下没有 source.properties 的目录),重装或设置 DROIDDECK_NDK_VERSION |
| Docker 报 No such image 且重建卡住 | Docker Desktop 虚拟机刚重启、镜像仓库还没加载完;脚本内置了最多 1 分钟的等待重试,稍候即可 |
| 提示需要 GitHub CLI | 存在 release.env 固定依赖(Gamescope/wlroots/esync)时脚本用 gh 下载校验包,先安装 gh 并登录 |
| The committed audio bundle already contains a built ARM64 sink | 上次构建中断后 pulseaudio.tzst 没还原干净,git checkout — app/src/main/assets/pulseaudio.tzst 恢复即可 |
写在最后
DroidDeck 的本地构建把"交叉编译"这件看似专业的事拆成了三个清晰的环节:Docker 管 glibc 侧的 preload 库,NDK 管 bionic 侧的音频模块,Gradle 管最终的 APK 组装,而 tools/build_local.sh 用符号校验、依赖体检、签名验证把这些环节串成了一条可靠的流水线。走通这一遍,你不仅能得到属于自己的签名 APK,也拿到了理解 Android 交叉编译体系的一个完整样本——推荐顺手读一下 README.md 的 Build 章节和 docs/development/ 下的开发文档,继续深入。
【免费下载链接】DroidDeck DroidDeck brings the SteamOS experience to Android 项目地址: https://gitcode.com/gh_mirrors/dr/DroidDeck
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




