- MiracastService.kt 初始化顺序修复(mediaRenderer 在 AirDisplayProtocol 之前) - 补充误删的 protocolManager.setListener() 回调 - 所有 12 个 lateinit 变量使用前初始化验证 此提交对应全面代码审查发现的问题
310 lines
13 KiB
Markdown
310 lines
13 KiB
Markdown
# 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](https://github.com/FDH2/UxPlay) (MIT License) 移植到 Android NDK。
|
||
|
||
UxPlay 是一个开源的 AirPlay 接收端实现,支持:
|
||
- AirPlay Mirroring (H.264 视频)
|
||
- AirPlay Audio (ALAC/AAC)
|
||
- FairPlay 解密 (需要系统证书)
|
||
- macOS/iOS 屏幕镜像 & 扩展
|
||
|
||
**移植策略**:
|
||
1. `airdisplay/native/uxplay/` — CMakeLists.txt + 源码
|
||
2. JNI 桥接 — UxPlay 的 H.264 NAL 通过 JNI 传回 Android 层
|
||
3. 共享 `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-client` crate — ADP 协议客户端库
|
||
- TCP 连接管理 + 重连
|
||
- 帧序列化 (Header + Payload)
|
||
- Keepalive
|
||
- UIBC 事件发送
|
||
- `mdns-resolver` — mDNS 设备发现
|
||
- 监听 `_airdisplay._tcp` 服务
|
||
- 自动刷新设备列表
|
||
|
||
### Tauri UI 功能
|
||
|
||
- **发现页**: 自动扫描局域网内 AirDisplay 设备
|
||
- **连接页**: 选中设备 → 连接 → 显示投屏状态
|
||
- **设置页**: 分辨率/帧率/延迟模式/协议选择
|
||
- **状态栏**: 连接状态、FPS、延迟、码率
|
||
|
||
### Rust 依赖
|
||
|
||
```toml
|
||
[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 (当前)
|
||
1. Android: `AirDisplayProtocol.kt` — ADP 协议处理器
|
||
2. Android: `MdnsService.kt` — mDNS 注册
|
||
3. Android: 改造 `WiFiDirectManager` — WFD IE 失败不阻塞
|
||
4. Android: `ProtocolManager.kt` — 协议选择
|
||
5. Desktop: 创建 `airdisplay-client` 仓库 + Rust/Tauri 脚手架
|
||
6. Desktop: ADP 协议客户端 + mDNS 发现
|
||
7. Desktop: 屏幕采集 + x264 软编
|
||
8. Desktop: Tauri UI
|
||
9. ✅ 端到端第一次投屏
|
||
|
||
### Phase 2: 优化
|
||
- 硬件编码支持 (NVENC/VideoToolbox/QSV)
|
||
- 延迟调优参数
|
||
- UIBC 触摸回传
|
||
- 分辨率/帧率自适应
|
||
|
||
### Phase 3: AirPlay
|
||
- UxPlay 移植到 Android NDK
|
||
- Mac 原生投屏
|
||
- 音频支持
|
||
|
||
---
|
||
|
||
*三协议并行,不受系统权限限制,覆盖全部桌面端。*
|