Commit Graph

47 Commits

Author SHA1 Message Date
b8d0455e2e fix: AirPlay mDNS 发现修复 — MAC地址/公钥/gid
- MAC地址从网络接口获取真实地址 (非全零)
- Ed25519密钥对改为立即初始化 (非lazy) 确保pk在注册前可用
- 添加gid (group UUID) 关联 _airplay 和 _raop 服务
- _airplay 添加 statusFlags TXT 记录
2026-05-31 12:58:06 +08:00
f635303f2a fix: 重复导入 + pts 表达式语法修正 2026-05-31 12:47:33 +08:00
6753f12453 fix: AirPlayProtocol 编译错误修复
- StreamState 构造函数语法修正 (data class 参数不允许 val 声明)
- Byte 位运算需转 Int: and/or/xor 使用 .toInt() 再转回 Byte
- when 表达式赋值重写: 修复 val decrypted 不可重赋值问题
- X25519.scalarMult 公钥生成改用6参数版本 (base point)
- dd-plist: NSNumber 类型匹配, NSArray.getArray(), NSDictionary.put()
- PropertyListParser.parse(byte[]) 替代 InputStream
- clientEdPublicKey!! 非 null 断言
2026-05-31 12:25:30 +08:00
5ac2798b08 fix: dd-plist groupId 修正 com.googlecode.plist 2026-05-31 12:17:39 +08:00
abbef47934 feat: AirPlay 镜像接收端完整实现 + 启动超时日志修复
- 新增 AirPlay 协议实现 (AirPlayProtocol.kt)
  - RTSP/HTTP 服务器 (端口 7000)
  - /info 设备能力查询 (binary plist)
  - /pair-setup Ed25519 公钥交换
  - /pair-verify Curve25519 ECDH + Ed25519 签名验证
  - /fp-setup FairPlay 三步密钥交换
  - SETUP 流配置 (视频 type=110, 音频 type=96)
  - RECORD 启动 UDP 视频/音频接收器
  - AES-CTR-128 视频解密 + AES-CBC-128 音频解密
  - 视频帧复用 MediaRenderer H.264 解码管线

- 新增 AirPlay mDNS 注册 (AirPlayMdnsService.kt)
  - _airplay._tcp 服务广播 (features=0x5A7FFFF7,0x1E)
  - _raop._tcp 服务广播 (音频支持)
  - 完整 TXT 记录 (deviceid, pk, model, srcvers 等)

- 依赖: Bouncy Castle (Ed25519/X25519/AES), dd-plist (binary plist)

- 修复启动超时日志混乱:
  withTimeout+try-catch → scope.async+withTimeoutOrNull{await()}
  阻塞调用超时时 TimeoutCancellationException 不再穿越 catch 块

- AirDisplayManager 启动新增步骤6/7 (AirPlay 服务 + mDNS)
2026-05-31 12:12:22 +08:00
788e196d48 fix: 阻塞调用包裹 withContext(IO) 使 withTimeout 可正确中断
- 步骤1 wifiDirect.initialize() 是同步阻塞调用,withTimeout 无法中断
- 改为 withTimeout(5000L) { withContext(Dispatchers.IO) { ... } }
- 超时后协程在 IO 线程被取消,TimeoutCancellationException 正确到达 catch
- 步骤2-5 同样加 withContext 防御性包裹
2026-05-31 11:39:12 +08:00
ee29bd01bf fix: 启动步骤加 withTimeout 超时保护,防止单个协议卡死整体
- 每个启动步骤外包 withTimeout:
  步骤1(wifiDirect.init): 5s
  步骤2(adp.start): 5s
  步骤3(mdns.register): 3s
  步骤4(rtsp.start): 5s
  步骤5(startDiscovery): 3s
- 超时单独 catch TimeoutCancellationException,不中断后续步骤
2026-05-31 11:27:58 +08:00
36d2381208 fix: onStartCommand 编译错误 — return 位置冲突
- 将 try-when-return 结构拆分:onStartCommand 始终 return START_NOT_STICKY
- STOP 逻辑抽为 handleStop() 独立方法,用 return 提前退出
2026-05-31 11:19:52 +08:00
ac8582ccad fix: return@try 语法错误 — 改用 if(started) 包裹 STOP 逻辑 2026-05-31 11:18:59 +08:00
0bec77eef8 fix: STOP 竞态条件 + 防抖 + 停止顺序修正
- AirDisplayService: STOP 先设 started=false 防重复;stop/destroy 移入协程
- AirDisplayManager: stop() 同步设Idle + stopMediaStreaming,异步清理协议
- AirDisplayManager: destroy() 移除冗余 stop() 调用,只 cancel scope
- MainActivity: onStartStop 禁止重复 STOP(Idle时只发 START)
2026-05-31 11:11:51 +08:00
3d1c0438f7 fix: Log.i→Log.w 解决Honor日志不可见 + try-catch + 防熄屏 + 版本信息
日志修复:
- AirDisplayService: 全部 Log.i→Log.w,onStartCommand 外层 try-catch
- AirDisplayManager: initialize/start/stop 全部 Log.i→Log.w
- MainActivity: bindAndStart/serviceConnection 加 Log.w

小功能:
- MainActivity: FLAG_KEEP_SCREEN_ON 防前台熄屏
- SettingsScreen: 新增关于卡片(版本号/目标平台/协议/开发者)
2026-05-31 11:05:28 +08:00
5258cc48b9 fix: 设置可在服务未启动时访问 + 服务 restart 生命周期 + 启动日志
- DeviceNameManager/ResolutionManager 提升到 Activity 层,服务未启动时也能设置
- SettingsScreen 接受直接传入的 manager 而非依赖 service.manager
- AirDisplayService: STOP 时重置 started=false,下次 START 重新创建 Manager
- AirDisplayService: 改用 START_NOT_STICKY 避免系统自动重启
- AirDisplayManager.start(): 每个步骤独立 try/catch,单步失败不阻塞整体
- AirDisplayManager.start(): 添加详细的步骤日志(步骤1-5)
- Start 按钮:服务销毁后可重新 bind+start
2026-05-31 10:42:08 +08:00
b820c47f8e fix: service 绑定时 Compose 不重组 — 用 mutableStateOf 替代普通 field
核心问题: service 是普通 var,bindService 异步完成后赋值,Compose 无感知

修复:
- service 改为 mutableStateOf<AirDisplayService?>,Activity 层与 Compose 共享
- onServiceConnected 中写入 serviceState.value 触发重组
- AppContent 参数改为显式传递 service(解引用 state)
- 合并 startSvc/stopSvc 为 sendIntent(action)
- 移除多余的 bound 标志位
2026-05-31 10:33:19 +08:00
619709dd1d fix: 自动申请权限 + 图标消失 + 授权后自动切换
权限流程:
- 启动时自动弹出系统授权对话框(不再需要用户手动点击)
- 通过 SideEffect 桥接 Compose state,授权后自动切换到主界面
- 授权等待中显示加载指示器

图标修复:
- 合并两个 intent-filter 为一个(LAUNCHER + LEANBACK_LAUNCHER)
- 移除 singleTask launchMode 避免启动器图标异常

MainActivity 简化:
- 移除 recreate() 循环触发
- 移除多余的回调闭包
2026-05-31 10:28:48 +08:00
461dc799ef fix: 权限状态未触发 Compose 重组 — 改用 mutableStateOf
- permGranted 从普通 Boolean 改为 remember { mutableStateOf() }
- 权限授权后 Compose 正确重组,从权限页切换到主界面
- 服务启动逻辑移入 AppContent 的 LaunchedEffect(Unit)
- 权限回调通过 pendingOnGranted 闭包传递
2026-05-31 10:24:48 +08:00
441a8d97de fix: 崩溃修复 — 服务初始化顺序 + SurfaceView/Compose 层级
- AirDisplayService: 启动时立即初始化 manager(不依赖 Surface),避免 lateinit 崩溃
- MainActivity: SurfaceView 放在 Box 最底层,Compose UI 覆盖其上,解决层级冲突
- MainActivity: 用普通 Boolean 替代 mutableStateOf 管理权限状态,避免 Compose 重组丢失
- MainActivity: 移除 composable 中的 return,用 if-else 替代,避免提前退出
- MainActivity: LaunchedEffect 只触发一次服务绑定
2026-05-31 10:19:26 +08:00
7a764a16a4 fix: 编译错误 — 显式类型标注、补充缺失 import
- AirDisplayManager: SAM conversion 推断失败,改用显式 object 表达式
- MainActivity: 补充 android.util.Log import
- MainScreen: 补充 androidx.compose.ui.graphics.Color import
2026-05-31 10:08:57 +08:00
7ee5646894 refactor: 全面重写架构 — MVVM + Jetpack Compose 替换传统 XML UI
架构变更:
- 新增 AirDisplayManager: 业务逻辑协调器,统一管理所有协议模块生命周期,向外暴露 StateFlow
- 新增 AirDisplayService: 轻量前台服务容器,委托 AirDisplayManager 处理业务
- 新增 MainScreen/SettingsScreen: Jetpack Compose 声明式 UI,深色主题
- 新增 ui/theme/Color.kt: Compose 主题色定义
- DeviceNameManager: 增加 StateFlow 响应式名称广播

用户体验改进:
- 服务与 Activity 生命周期解耦:退出 App 不停止投屏
- 清晰的启动/停止按钮(不再绑架在权限流程上)
- 设备信息卡片:名称、协议、分辨率、码率一目了然
- Wi-Fi Direct SSID/密码直观展示
- 4步连接指引引导用户
- 投屏中悬浮状态栏 + 一键断开
- 设置页直接编辑名称、切换分辨率预设/自动模式
- 权限请求独立界面,友好说明

删除旧代码:
- SettingsActivity (被 SettingsScreen 替代)
- activity_main.xml / activity_settings.xml (被 Compose 替代)
- Manifest 中 MiracastService → AirDisplayService

依赖更新:
- add: Compose BOM 2024.02, Material3, TV Compose, Compose Activity
- add: lifecycle-runtime-compose, lifecycle-viewmodel-compose
- compose compiler 1.5.10
2026-05-30 22:53:27 +08:00
0c9dc7f94b feat: 设备名默认主机名 + 分辨率默认屏幕分辨率 + ADP协议字段修正
- DeviceNameManager: 默认使用 Settings.Global.DEVICE_NAME (主机名),回退至 Build.MODEL
- ResolutionManager: 默认使用 WindowManager 获取设备实际屏幕分辨率
- AirDisplayProtocol: codecs/features 改为 JSONArray 格式(之前为 raw string,桌面端无法解析),支持 deviceNameProvider 注入
- MdnsService: maxWidth/maxHeight 支持动态配置,TXT 记录不再硬编码
- MiracastService: 向 AirDisplayProtocol/MdnsService 传递实际设备名和分辨率
- SettingsActivity: 标签文字更新为"主机名默认"
2026-05-30 22:04:00 +08:00
yuqianhe
1d747f6dc3 fix: Kotlin 编译错误根治
AirDisplayProtocol.kt:184 — acceptLoop() 返回 Unit,try-catch 类型推导为 Any,
在 async 块结尾添加 true (+ @Suppress UNREACHABLE_CODE),使闭包返回 Boolean

MdnsService.kt:112 — port = port 在 apply 块中参数名与 receiver 属性冲突,
改用 NsdServiceInfo.setPort() 显式调用 Java setter 避免歧义;
统一将参数名从 port 改为 servicePort 消除冲突隐患
2026-05-30 08:56:04 +00:00
yuqianhe
944987971f fix: Kotlin 编译错误
- AirDisplayProtocol.kt: async 返回类型加 <Boolean> 显式泛型
- MdnsService.kt: 移除与属性 getter 冲突的 fun isRegistered() 方法
- MdnsService.kt: onUnregistered → onServiceUnregistered(Android API 实际方法名)
2026-05-30 08:41:11 +00:00
yuqianhe
e302021958 fix: 三协议架构代码审查修复
- MiracastService.kt 初始化顺序修复(mediaRenderer 在 AirDisplayProtocol 之前)
- 补充误删的 protocolManager.setListener() 回调
- 所有 12 个 lateinit 变量使用前初始化验证

此提交对应全面代码审查发现的问题
2026-05-30 08:29:36 +00:00
yuqianhe
b92a296290 fix: 完善 setWfdInfo 反射异常诊断 — 区分 InvocationTargetException/SecurityException
现有日志显示"反射异常: null"(消息为 null),无法判断具体
错误类型。拆分为三级 catch:
- InvocationTargetException: 打印底层异常类名+消息+堆栈
- SecurityException: 明确提示系统权限不足
- Exception: 打印异常类名+消息+堆栈
2026-05-30 07:15:55 +00:00
yuqianhe
5c23f19a96 fix: 兼容性 WFD IE 设置 — 标准方法名 → OEM 变体 → 字段反射三级回退
基于 MagicOS 实际方法枚举结果:
- AOSP 标准名 setWfdEnabled → OEM 上叫 setEnabled
- 其他 setter (setDeviceType/setControlPort/…) 保持一致
- 新增三级尝试:标准名 → OEM 回退名 → 直接写字段
- 精简 callSetWfdInfo 为独立方法
- 移除不再需要的诊断方法枚举日志
2026-05-30 07:10:12 +00:00
yuqianhe
cb99db014e feat: 绕过 OEM WifiP2pWfdInfo 被裁剪的 setter → 字段反射+方法枚举
WifiP2pWfdInfo 类存在于 MagicOS 但 setWfdEnabled/setDeviceType
等标准 setter 被 OEM 移除。新策略:
1. 枚举所有公开方法 + 字段,诊断 OEM 实际 API
2. 先尝试 3 参构造 (boolean, int, int)
3. 回退到无参构造 + 反射直接写字段(消除对 setter 的依赖)
4. 枚举 WifiP2pManager 的 setWfdInfo/相关方法
5. 备选方法名 setWifiDisplayInfo
2026-05-30 06:55:44 +00:00
yuqianhe
af397dbe77 chore: cleanup stray echo file 2026-05-30 06:49:49 +00:00
yuqianhe
24face5c9c fix: Kotlin 编译错误 — Boolean.TYPE/Integer.TYPE 改用 javaPrimitiveType 2026-05-30 06:49:07 +00:00
yuqianhe
a1b821aa10 diagnostic: 添加 WFD_MARKER 强标记日志 + 分步日志
- Log.i 标记 WFD_MARKER 确保不会被 Log.d 级别过滤
- 每一步操作都加详细日志:类加载、实例创建、各方法调用
- 用 WFD_DEBUG 额外 tag 确保 grep wfd 也能匹配到
- catch 块全部用 Log.e 输出异常信息
- e.printStackTrace() 打印完整堆栈
- 用 WFD_MARKER_START/END 包裹方法体
2026-05-30 06:40:49 +00:00
yuqianhe
3ee99aa1b2 fix: WFD IE 反射参数类型修复 + 日志改为 Log.i
问题:getMethod 使用 Int::class.java (java.lang.Integer) 查
找方法,但方法参数是原生 int (Integer.TYPE),导致 NoSuchMethod
Exception 被静默吞掉,WFD IE 实际从未生效。

修复:
1. 所有原生类型参数改为 Boolean.TYPE / Integer.TYPE
2. 日志从 Log.d 改为 Log.i,确保 logcat 可见
3. 每步操作加详细日志,方便排查 OEM 裁剪情况
2026-05-30 06:30:11 +00:00
yuqianhe
1c9696d282 fix: 添加 WFD IE 设置使 Windows 能发现 Miracast 接收器
Wi-Fi Direct P2P Group 创建后还需设置 WFD (Wi-Fi Display)
Information Element,告诉 Windows 这个 P2P 设备是 Miracast 接收器。
没有这个 IE,Windows 的 Win+K 无法识别手机为无线显示器。

- trySetWfdInfo(): 反射调用 WifiP2pManager.setWfdInfo()
- 设置设备类型为 PRIMARY_SINK(Miracast 接收端)
- 设置控制端口 7236(RTSP 端口)
- 初始化时设置一次 + Group 创建成功后再次设置
2026-05-30 06:24:40 +00:00
yuqianhe
04b29e2ad4 fix: 添加 NEARBY_WIFI_DEVICES 权限 + P2P 创建重试
- 添加 android.permission.NEARBY_WIFI_DEVICES(Android 13+ 替代位置权限)
- ACCESS_FINE_LOCATION 设 maxSdkVersion=32(低版本用位置,高版本用附近设备)
- MainActivity 分 API 版本请求不同权限
- WiFiDirectManager.createGroup() 失败时自动重试(先 remove 再 retry)
- 改进权限提示信息,区分位置/附近设备/通知三种权限
2026-05-30 06:17:21 +00:00
yuqianhe
de2dbc763d fix: statusOverlay 类型从 LinearLayout 改 ScrollView
布局文件 activity_main.xml 中将 statusOverlay 从 LinearLayout 改为
ScrollView,但代码中仍声明为 LinearLayout,导致 ClassCastException。
改为 ScrollView 并添加对应 import。
2026-05-30 06:02:01 +00:00
yuqianhe
febd02c8fe feat: 手机使用体验 — 权限请求 + 使用指引 + P2P 信息 + Binder
新增功能:
- 运行时权限请求:位置权限(ACCESS_FINE_LOCATION)和通知权限
  (POST_NOTIFICATIONS),含理由说明和引导至系统设置
- 使用指引:主界面显示分步连接指南(Win+K 操作说明)
- P2P 连接信息:Wi-Fi Direct 组 SSID 和密码实时显示
- MiracastBinder:onBind() 返回非 null Binder,Activity 绑定后
  可直接调用服务方法
- ServiceStateListener:Activity 实时监听状态变更并更新界面
- 手机友好布局:ScrollView 适配小屏,步骤引导 + P2P 信息区
2026-05-30 05:53:04 +00:00
yuqianhe
a456cb40fe fix: Android 16 前台服务崩溃 — 移除 FOREGROUND_SERVICE_MEDIA_PLAYBACK 的 maxSdkVersion
Android 16 上系统强制校验 foregroundServiceType=mediaPlayback 对
应权限的声明。之前设了 maxSdkVersion=34 导致 API 35+ 上权限未
声明,startForeground 抛出 SecurityException。
移除限制后该权限在所有版本都声明,低版本自动忽略未知权限。
2026-05-30 05:41:23 +00:00
yuqianhe
93469db573 fix: 手机启动闪退 — leanback required=false + Theme.AppCompat
- leanback required=true → false,允许手机安装
- Theme.Leanback → Theme.AppCompat.NoActionBar,手机不崩溃
- 布局文件使用标准 View(SurfaceView/TextView/Button),无 Leanback 专属组件
- colors.xml 中的颜色属性在 AppCompat 主题中同样有效
2026-05-30 05:27:24 +00:00
yuqianhe
73f1da05e8 feat: 添加桌面图标入口(LAUNCHER category)方便测试
MainActivity 现在同时支持 LEANBACK_LAUNCHER(Android TV 主屏 Apps 行)
和 LAUNCHER(桌面图标),方便在开发调试时快速启动应用。
2026-05-30 05:23:30 +00:00
yuqianhe
701902e96a fix: WifiP2pConfig 旧构造函数在 API 34 已移除,改用默认构造函数+字段赋值 2026-05-30 05:12:45 +00:00
yuqianhe
11871fb37b fix: 修复 11 处 Kotlin 编译错误(Byte/Int 比较、类型匹配、未解析引用等)
MediaRenderer.kt:    Byte/Int 比较 → .toByte()(起始码/NAL 搜索)
RtpReceiver.kt:      bitrate Int→Long(8L/2L)
TsDemuxer.kt:        Byte/Int 比较 → .toByte()
RtspServer.kt:       isActive → coroutineContext.isActive
RtspSession.kt:      补 sessionId 参数;getState()→getCurrentState()
WfdParser.kt:        enum name→displayName(避 Enum 冲突)
SettingsActivity.kt: 补 import android.view.View
UibcServer.kt:       KEYCODE 缺失改用整数直接量
WiFiDirectBroadcastReceiver.kt: 缺失常量改用字符串直接量
WiFiDirectManager.kt:Builder API 三级兼容(API 30+ MacAddress / 23-29 旧构造函数)
2026-05-30 05:09:41 +00:00
yuqianhe
b8fa7926ae fix: minSdk=23 兼容性 — 自适应图标移至 mipmap-anydpi-v26,低版本用 PNG 回退
- ic_launcher.xml(adaptive-icon)从 mipmap-hdpi/xhdpi 移至 mipmap-anydpi-v26(仅 API 26+ 生效)
- 为 mipmap-mdpi/hdpi/xhdpi/xxhdpi/xxxhdpi 生成 PNG 回退图标(蓝底显示器图案)
- 修复 AAPT 编译错误: '<adaptive-icon> elements require a sdk version of at least 26'
2026-05-30 04:26:50 +00:00
yuqianhe
8a095eecc3 fix: 适配 Codespaces SDKMAN! 环境,不碰系统默认 java
- 移除 update-alternatives(对 SDKMAN! 无效)
- 纯 JAVA_HOME 方案:安装 JDK 17 到 /usr/lib/jvm,设置 JAVA_HOME
- 构建前用 /bin/java -version 硬性验证
- Gradle 通过 -Dorg.gradle.java.home 强制使用 JDK 17
- PATH 首位放 /bin 确保 gradlew 找到正确 JDK
2026-05-30 03:48:59 +00:00
yuqianhe
4acfeddaac fix: 彻底修复 Codespaces JDK 检测与 Gradle 构建
- JDK 检测: 用 glob 扫描 /usr/lib/jvm/java-17-openjdk-* 而非固定路径
- JDK 切换: 独立 switch_to_jdk17() — update-alternatives + JAVA_HOME + hash -r + 版本验证
- Gradle 强制: 通过 -Dorg.gradle.java.home= 硬性指定 JDK 17,绕过系统默认
- 构建前验证: java -version 确认 JDK 17,不通过则报错退出
- platform-tools 加入 PATH 供 adb 使用
- 移除 set -e,避免 update-alternatives 非零退出吞掉错误
2026-05-30 03:46:49 +00:00
yuqianhe
cc06758098 fix: 修复 Codespaces 脚本 JDK 版本切换 + platform-tools 安装卡死
- 安装 JDK 17 后用 update-alternatives 强制切换默认版本
- 显式设置 JAVA_HOME + PATH 确保 Gradle 使用正确的 JDK
- platform-tools 安装时 yes 管道直接喂给 sdkmanager 防卡死
2026-05-30 02:33:45 +00:00
yuqianhe
635a46899b chore: 添加 Codespaces APK 构建脚本 build.codespace.sh 2026-05-30 02:24:01 +00:00
yuqianhe
982584e470 docs: 更新 README 完整文档,覆盖五项改造详情
- Android 6-14 兼容说明
- 可配置设备名 + UIBC 触摸回传
- 分辨率/帧率设置 + SPS 自动检测
- 三级延迟模式配置表
- 完整技术栈说明、设置项使用指南、常见问题
2026-05-29 15:42:49 +00:00
yuqianhe
04fc7e53a4 V3: 分辨率/帧率设置+延迟优化
- ResolutionManager: 预设分辨率选择(640×480~1920×1080 @ 24/30/60fps)
  + 自动/手动模式持久化
- WfdParser.buildVideoFormats/buildWfdParameters: 动态分辨率参数
- SettingsActivity + activity_settings.xml: 分辨率选择UI(自动/手动RadioGroup+预设Spinner)
- TsDemuxer: H.264 SPS完整解析(width/height+cropping)自动分辨率检测
- LatencyManager: 三级延迟模式(Low/Medium/High)控制RTP缓冲/解码低延迟/丢帧策略
- MediaRenderer: updateLatencyConfig动态调参,条件启用KEY_LOW_LATENCY,智能丢帧
- RtpReceiver: 可配置bufferWatermark字段
- MiracastService: 串联ResolutionManager+LatencyManager到全栈
2026-05-29 15:39:28 +00:00
yuqianhe
9a2301cc1b V2: 三项改造完成
1. Android 兼容性改造
   - minSdk=23 (Android 6.0), targetSdk=34 (Android 14)
   - Manifest 条件声明: foregroundServiceType(tools:targetApi=34), FOREGROUND_SERVICE_MEDIA_PLAYBACK(maxSdkVersion=34)
   - API 级别守卫: KEY_LOW_LATENCY (Q+), 通知渠道 (O+)

2. 可配置设备名
   - DeviceNameManager (SharedPreferences 存储, 默认回退 Build.MODEL)
   - SettingsActivity (Leanback 设置界面)
   - WiFiDirectManager 反射 setDeviceInfo 尝试设置 P2P 设备名
   - RtspSession Server 头注入设备名
   - 通知/主界面显示设备名

3. UIBC 触摸回传
   - UibcServer (TCP 7237 接收 Windows 触控/鼠标/键盘事件)
   - WfdParser UIBC 能力协商 (buildUibcCapability/parseUibcCapability)
   - M3 握手协商 UIBC 能力
   - InputManager 注入+回调双模式
2026-05-29 15:28:20 +00:00
yuqianhe
c095c58dbe 🎉 初始提交:AirDisplay - Android TV 无线显示器
将 Android TV 变成支持 Microsoft 无线显示适配器 (Miracast) 的无线显示器。

包含完整协议栈:
- Wi-Fi Direct P2P Group Owner
- RTSP M1-M8 握手 (TCP 7236)
- RTP/UDP 媒体流接收
- MPEG2-TS 实时解复用
- MediaCodec 硬件解码渲染 (H.264/H.265 + AAC)

总计 27 文件 / ~3,900 行 Kotlin 代码
2026-05-29 15:03:03 +00:00