- MiracastService.kt 初始化顺序修复(mediaRenderer 在 AirDisplayProtocol 之前) - 补充误删的 protocolManager.setListener() 回调 - 所有 12 个 lateinit 变量使用前初始化验证 此提交对应全面代码审查发现的问题
13 KiB
13 KiB
AirDisplay 系统架构
概览
三协议并行架构,根据场景自动选择或用户手动指定:
┌─────────────────────────────────────────────────────────────┐
│ Android 端 (AirDisplay) │
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ 协议栈 & 自动选择 ││
│ │ ││
│ │ ┌──────────────┐ ┌──────────────┐ ┌────────────────┐││
│ │ │ Miracast │ │ ADP │ │ AirPlay │││
│ │ │ (保留) │ │ (私有协议) │ │ (Mac 原生) │││
│ │ │ │ │ │ │ │││
│ │ │ WFD IE │ │ mDNS 发现 │ │ UxPlay 移植 │││
│ │ │ RTSP→RTP→TS │ │ TCP 帧协议 │ │ H.264+AAC │││
│ │ │ Wi-Fi Direct │ │ P2P/LAN │ │ FairPlay │││
│ │ └──────┬───────┘ └──────┬───────┘ └───────┬────────┘││
│ │ └────────────────┼──────────────────┘ ││
│ │ ▼ ││
│ │ 共用 MediaCodec 解码 + 渲染 ││
│ │ UIBC 触摸回传 (已有) ││
│ │ DeviceName 配置 (已有) ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ 自动选择逻辑: │
│ Wi-Fi Direct + WFD IE 可用 → Miracast │
│ Wi-Fi Direct + WFD IE 失败 → 降级 ADP (P2P) │
│ 同局域网 → ADP (LAN) │
│ Mac 投屏请求 → AirPlay │
│ 用户手动选择 → 指定协议 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Desktop Client (独立仓库 airdisplay-client) │
│ │
│ 技术栈: Rust + Tauri v2 │
│ 目标平台: Windows / macOS / Linux │
│ │
│ ┌───────────┐ ┌────────────┐ ┌─────────────────────────┐ │
│ │ 屏幕采集 │→ │ 视频编码 │→ │ 网络层 │ │
│ │ │ │ │ │ │ │
│ │ Windows │ │ NVENC │ │ mDNS 发现 (mdns-sd) │ │
│ │ DXGI │ │ (NVIDIA) │ │ ADP 协议 (自定义帧协议) │ │
│ │ macOS │ │ Video │ │ TCP 可靠传输 │ │
│ │ CGDisplay│ │ Toolbox │ │ │ │
│ │ Linux │ │ Intel QSV │ │ QUIC 备选 (低延迟) │ │
│ │ PipeWire │ │ x264 软编 │ │ │ │
│ └───────────┘ └────────────┘ └─────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Tauri UI (React/TypeScript) ││
│ │ ├─ 自动发现设备列表 (mDNS) ││
│ │ ├─ 连接/断开控制 ││
│ │ ├─ 协议选择 (ADP 默认 / Miracast 备选) ││
│ │ ├─ 分辨率/帧率/延迟模式设置 ││
│ │ └─ 连接状态 & 统计信息 ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Mac 端 (无额外客户端) │
│ │
│ 控制中心 → 屏幕镜像 → 选择 AirDisplay │
│ 使用 Apple 内置 AirPlay 协议 │
│ 无需安装额外软件 │
│ 备选:也可安装 airdisplay-client 走 ADP 协议 │
└─────────────────────────────────────────────────────────────┘
协议设计
1. Miracast (已实现,保留)
现有代码保持不变:
WiFiDirectManager.kt— P2P Group 创建 + WFD IE 反射 (失败不阻塞)RtspServer.kt/RtspSession.kt— RTSP 握手RtpReceiver.kt/TsDemuxer.kt— RTP/TS 媒体管道- 用于 Android TV / 系统签名设备 / WFD IE 兼容的环境
改动:WFD IE 反射失败时不再终止流程,自动降级到 ADP。
2. AirDisplay Protocol (ADP) v1
自定义轻量屏幕投屏协议。设计目标:低延迟、简单可靠、跨平台。
发现阶段
| 场景 | 发现方式 |
|---|---|
| Wi‑Fi Direct P2P | P2P Group 创建后,在 192.168.49.1:7935 启动 TCP 监听 |
| 同局域网 | mDNS 注册 _airdisplay._tcp 端口 7935 |
连接阶段 (TCP 7935)
[Client] ──TCP 连接──> [Server]
[Server] ADP/1.0 200 OK
Capabilities: {
"max_width": 1920,
"max_height": 1080,
"codecs": ["h264"],
"features": ["uibc", "audio"]
}
[Client] ADP/1.0 HANDSHAKE
Settings: {
"width": 1920,
"height": 1080,
"fps": 30,
"codec": "h264",
"bitrate": 20000000
}
[Server] ADP/1.0 READY
数据阶段 (TCP 持久连接)
帧格式:
┌──────────────────────────────────────────────────────────┐
│ Type(1) │ Reserved(1) │ Length(2) │ Timestamp(4) │
├──────────────────────────────────────────────────────────┤
│ Payload (变长) │
└──────────────────────────────────────────────────────────┘
Type 定义:
0x01 = Capability 协商 (JSON)
0x02 = H.264 NAL 单元 (Annex B)
0x03 = H.265 NAL 单元 (保留)
0x04 = 音频帧 (AAC/Opus)
0x05 = UIBC 事件 (触摸/鼠标/键盘)
0x06 = Keepalive
0x07 = 分辨率/参数变更
UIBC 格式
与现有 UibcServer.kt 兼容。
3. AirPlay
使用 UxPlay (MIT License) 移植到 Android NDK。
UxPlay 是一个开源的 AirPlay 接收端实现,支持:
- AirPlay Mirroring (H.264 视频)
- AirPlay Audio (ALAC/AAC)
- FairPlay 解密 (需要系统证书)
- macOS/iOS 屏幕镜像 & 扩展
移植策略:
airdisplay/native/uxplay/— CMakeLists.txt + 源码- JNI 桥接 — UxPlay 的 H.264 NAL 通过 JNI 传回 Android 层
- 共享
MediaRenderer.kt— 与 ADP/Miracast 共用 MediaCodec 解码
Android 端代码结构
app/src/main/java/com/qwenpaw/miracast/
├── AirDisplayService.kt ← 前台服务 (改自 MiracastService)
├── protocol/
│ ├── ProtocolManager.kt ← 协议选择逻辑 (新增)
│ ├── AirDisplayProtocol.kt ← ADP 协议处理器 (新增)
│ ├── MdnsService.kt ← mDNS 注册 (新增)
│ └── AirPlayBridge.kt ← AirPlay JNI 桥接 (新增)
├── wifidirect/
│ └── WiFiDirectManager.kt ← P2P 管理 (改造)
├── rtsp/ ← 保留 (Miracast 用)
│ ├── RtspServer.kt
│ ├── RtspSession.kt
│ └── WfdParser.kt
├── media/
│ ├── RtpReceiver.kt
│ ├── TsDemuxer.kt
│ └── MediaRenderer.kt ← 共享解码+渲染
├── uibc/
│ └── UibcServer.kt
├── DeviceNameManager.kt
├── ResolutionManager.kt
├── LatencyManager.kt
└── ui/
├── MainActivity.kt
├── SettingsActivity.kt
└── ...
网络拓扑
P2P 模式: 手机(GO) ←── Wi‑Fi Direct ──→ PC
IP: 192.168.49.1
LAN 模式: 手机 ──── Wi‑Fi Router ────→ PC
↑ mDNS ↑ mDNS
Desktop Client 技术方案
技术栈
| 层面 | 方案 | 说明 |
|---|---|---|
| 语言 | Rust | 跨平台原生、零开销抽象、安全 |
| 桌面框架 | Tauri v2 | Rust 后端 + Web 前端,打包 < 10MB |
| 异步运行时 | tokio | 全异步 I/O |
| 前端框架 | React + TypeScript | 组件化 UI |
| 构建工具 | Vite | HMR 快速开发 |
屏幕采集
| 平台 | 方案 | Rust crate |
|---|---|---|
| Windows | DXGI Desktop Duplication | dxgi-rs / captrs |
| macOS | CGDisplay Stream | core-graphics (sys) |
| Linux (Wayland) | PipeWire | pipewire-rs |
| Linux (X11) | X11 SHM GetImage | x11 / scrap |
视频编码
| 编码器 | 方式 | 适用平台 |
|---|---|---|
| NVENC | 硬件 | Windows (NVIDIA) |
| VideoToolbox | 硬件 | macOS |
| Intel QSV | 硬件 | Windows/Linux (Intel) |
| x264 | 软件 | 全平台保底 |
| VAAPI | 硬件 | Linux (AMD/Intel) |
协议实现
adp-clientcrate — ADP 协议客户端库- TCP 连接管理 + 重连
- 帧序列化 (Header + Payload)
- Keepalive
- UIBC 事件发送
mdns-resolver— mDNS 设备发现- 监听
_airdisplay._tcp服务 - 自动刷新设备列表
- 监听
Tauri UI 功能
- 发现页: 自动扫描局域网内 AirDisplay 设备
- 连接页: 选中设备 → 连接 → 显示投屏状态
- 设置页: 分辨率/帧率/延迟模式/协议选择
- 状态栏: 连接状态、FPS、延迟、码率
Rust 依赖
[dependencies]
tauri = "2"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
mdns-sd = "0.12"
tracing = "0.1"
anyhow = "1"
# 屏幕采集 (平台相关)
[target.'cfg(target_os = "windows")'.dependencies]
captrs = "0.3"
[target.'cfg(target_os = "macos")'.dependencies]
core-graphics = "0.24"
[target.'cfg(target_os = "linux")'.dependencies]
# PipeWire / x11
# 编码
ffmpeg-next = "7"
实现路线
Phase 1: ADP MVP (当前)
- Android:
AirDisplayProtocol.kt— ADP 协议处理器 - Android:
MdnsService.kt— mDNS 注册 - Android: 改造
WiFiDirectManager— WFD IE 失败不阻塞 - Android:
ProtocolManager.kt— 协议选择 - Desktop: 创建
airdisplay-client仓库 + Rust/Tauri 脚手架 - Desktop: ADP 协议客户端 + mDNS 发现
- Desktop: 屏幕采集 + x264 软编
- Desktop: Tauri UI
- ✅ 端到端第一次投屏
Phase 2: 优化
- 硬件编码支持 (NVENC/VideoToolbox/QSV)
- 延迟调优参数
- UIBC 触摸回传
- 分辨率/帧率自适应
Phase 3: AirPlay
- UxPlay 移植到 Android NDK
- Mac 原生投屏
- 音频支持
三协议并行,不受系统权限限制,覆盖全部桌面端。