# 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 原生投屏 - 音频支持 --- *三协议并行,不受系统权限限制,覆盖全部桌面端。*