1. 项目背景与目标
最近接手了一个将Miracast投屏功能适配到opsD2000设备的任务。Miracast作为无线显示标准,允许用户将手机、电脑等设备的屏幕内容无线投射到电视或显示器上。我们的目标是在opsD2000平台上实现稳定可靠的Miracast接收端功能。
opsD2000采用的是GK6320芯片方案,但原生的Miracast实现存在一些问题。我们需要将GK6320的castengine_cast_framework、wifi和castengine_wifi_display三个仓库的代码替换到底包中,并进行必要的适配工作。
2. 代码准备与环境搭建
2.1 代码仓库替换
首先需要准备以下代码:
- opsD2000设备底包
- GK6320的castengine_cast_framework仓库代码
- GK6320的wifi仓库代码
- GK6320的castengine_wifi_display仓库代码
替换操作很简单,就是用GK6320的三个仓库代码替换掉opsD2000底包中对应的部分。这一步看似简单,但后续会带来一系列适配问题。
2.2 编译环境配置
在编译过程中遇到了一个模块依赖检查的问题。系统会检查模块依赖是否合法,但这个检查在我们的场景下会导致编译失败。解决方法是通过修改check_build_target.py文件来跳过这个检查:
python复制#!/usr/bin/env python3
import sys
if __name__ == "__main__":
# 直接生成空的输出文件(满足Ninja依赖)
output_file = None
for i in range(len(sys.argv)):
if sys.argv[i] == "--output" and i+1 < len(sys.argv):
output_file = sys.argv[i+1]
break
if output_file:
with open(output_file, "w") as f:
f.write("Deps check skipped")
sys.exit(0)
这个修改虽然绕过了依赖检查,但需要特别注意:这只是一个临时解决方案,在正式发布版本中应该解决实际的依赖问题,而不是简单地跳过检查。
3. 驱动适配与接口管理
3.1 P2P设备接口创建问题
在测试阶段,首先需要确认驱动是否支持wpa创建管理接口。通过添加日志发现,wpas_p2p_add_p2pdev_interface函数没有被调用。这意味着框架层需要负责创建管理接口。
在wpa_supplicant.c中添加了以下调试日志:
c复制#ifdef CONFIG_P2P
wpa_dbg(wpa_s, MSG_INFO, "tttt wpa_s->global->p2p == NULL is %d", wpa_s->global->p2p == NULL);
wpa_dbg(wpa_s, MSG_INFO, "tttt wpa_s->global->p2p_disabled is %d", wpa_s->global->p2p_disabled);
wpa_dbg(wpa_s, MSG_INFO, "tttt wpa_s->conf->p2p_disabled is %d", wpa_s->conf->p2p_disabled);
wpa_dbg(wpa_s, MSG_INFO, "tttt wpa_s->drv_flags is %lu", wpa_s->drv_flags);
wpa_dbg(wpa_s, MSG_INFO, "tttt wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVIC is %d",
(int)(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE));
if (wpa_s->global->p2p == NULL &&
!wpa_s->global->p2p_disabled && !wpa_s->conf->p2p_disabled &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
wpas_p2p_add_p2pdev_interface(wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
wpa_printf(MSG_INFO, "P2P: Failed to enable P2P Device interface");
/* Try to continue without. P2P will be disabled. */
}
#endif /* CONFIG_P2P */
3.2 管理接口创建方案
由于opsD2000设备的硬件限制,创建独立的p2p0接口失败了。经过分析,我们决定复用现有的wlan0接口作为管理接口。这需要修改NON_SEPERATE_P2P宏相关的代码,让逻辑走到else分支,并将接口名称从p2p0改为wlan0。
这个修改虽然解决了接口创建问题,但也带来了一些限制:
- 不能同时进行普通WiFi连接和Miracast投屏
- 性能可能会受到影响
- 需要特别注意接口状态管理
4. 连接问题排查与解决
4.1 手机端连接失败
在复用wlan0接口后,P2P服务能够正常启动,手机也能发现设备。但是连接时出现了失败,日志显示:
code复制03-25 15:26:41.179 1583 1584 I C05200/wpa_supplicant: P2P-GO-NEG-FAILURE status=-1
问题原因在于GK6320设备不会直接创建组,而是通过协商确定谁是GO(Group Owner)。这种协商机制在opsD2000上不稳定,导致反复协商失败。
解决方案是用GK6780设备的castengine_wifi_display代码替换底包中的对应部分。GK6780的实现会直接创建组,避免了协商过程。修改后手机投屏功能可以正常工作了。
4.2 Windows设备发现问题
虽然手机投屏成功了,但Windows PC无法发现设备。通过查阅资料,需要在wpa_supplicant.conf中添加配置:
code复制device_type=7-0050F204-1
这个配置指定了设备类型,使Windows能够正确识别设备。但添加后发现Windows可以搜索到设备,却连接失败。
进一步调试发现需要将device_type改为:
code复制device_type=10-0050F204-5
这个值参考了大屏设备的配置,修改后Windows可以成功连接,但投屏仍然失败。
4.3 投屏失败问题分析
从日志中可以看到连接建立后很快又断开:
code复制AP-STA-CONNECTED
...3秒后...
AP-STA-DISCONNECTED
通过wireshark抓包分析,发现与正常设备相比,RTSP协议交互数据量明显不足。特别是GET PARAMETER命令的回复存在差异。
问题可能出在视频格式协商上。opsD2000回复的视频格式参数可能不被客户端接受,导致客户端主动断开连接。
5. 最终解决方案
5.1 视频格式参数硬编码
为了解决视频格式兼容性问题,我们修改代码将wfd_video_formate和wfd2_video_formate参数硬编码为兼容性更好的值:
c复制// 修改视频格式参数
wfd_video_formate = "none none none none none"
wfd2_video_formate = "none none none none none"
这个修改虽然不够优雅,但确实解决了投屏失败的问题。在实际应用中,应该根据设备能力动态生成这些参数,而不是简单地硬编码。
5.2 完整适配流程总结
- 替换代码仓库:用GK6320的三个关键仓库替换底包中的对应部分
- 解决编译问题:修改check_build_target.py跳过依赖检查
- 接口适配:复用wlan0作为管理接口
- 连接优化:使用GK6780的wifi_display代码解决协商问题
- 设备发现:调整device_type参数兼容Windows
- 视频格式:硬编码视频格式参数确保兼容性
6. 经验总结与注意事项
6.1 调试技巧
- 日志是最重要的调试工具,在关键路径添加详细的日志
- 使用wireshark抓包分析协议交互过程
- 对比正常设备和问题设备的行为差异
- 分阶段验证,先确保基础功能正常再解决高级问题
6.2 常见问题处理
- 接口创建失败:检查驱动支持情况,考虑复用现有接口
- 设备无法发现:确认device_type配置正确
- 连接不稳定:分析协商过程,必要时修改组创建策略
- 投屏失败:检查视频格式等参数兼容性
6.3 性能优化建议
- 避免硬编码参数,实现动态能力协商
- 优化接口管理,减少状态切换开销
- 实现适当的缓冲和重传机制
- 监控资源使用情况,避免内存泄漏
这个适配过程虽然遇到了不少挑战,但通过系统性的分析和调试,最终实现了稳定可用的Miracast功能。在实际项目中,这种底层适配工作需要耐心和细致的调试,同时也需要对相关协议和系统架构有深入的理解。
