RK Android16 wifi 投屏失败问题排查

目录

一.背景

二.排查过程

三.具体修改

四.拓展知识(RTSP是啥)


一.背景

RK项目投屏电脑失败,具体操作如下:

Test condition:1.笔记本与待测设备连接同一WiFi网络

2.进入"控制面板" > "网络和Internet" > "网络和共享中心",将网络类型改为"家庭网络

3.控制面板-投影到此电脑-点击"启动连接应用以投影到此电脑"

Package Path:qdisk:/Project/Module Project Files/Smart/RK3576/BA02/SH603Z/AP/NA/Fimware/Release/SH603ZAAPNAR01A01_BA02BP01K0M01_AP16.0.0.01.001_V02

Recurrence Probability:100%

1.使用笔记本电脑按操作设置好投影功能

2.设备与笔记本电脑连接同一WiFi

3.设备点击settings-Connected devices-Connection preferences-Cast,点击连接搜索到的笔记本设备,查看是否能勾投屏成功

Expected Result:

3.投屏成功,笔记本电脑屏幕显示待测设备屏幕信息

Contrast Test:\

Actual Result:

3.点击PC|进行连接无法成功

二.排查过程

首先整个设备投屏电脑过程的流程图如下

然后我们分析流程如下:

由于点击投屏的时候是几百毫秒后投屏失败,说明肯定是p2p连接成功了,并且是像电脑进行协商请求了,电脑给拒绝了,所以就是在RTSP这块有问题

然后根据日志进行详细排查

这份日志是绝佳的"案发现场铁证"!它百分之百证实了我们前面所有的推论!

在日志中,5 次尝试投屏(全部失败),每一次都完美记录了:上层发出了错误的 24

帧协商报文(idx=15),导致底层编码器在请求了几帧画面后被被迫关闭(shutting

down video encoder)。

下面为你逐条提取日志中的 3 大核心铁证:

铁证一:协商报文里明确写着 idx=15(720p 24帧)

看日志中的 第 17946 行(以及 19773、23381、24730、27911 行,每次尝试都一样):

行 17946: 07-18 10:07:47.415 732 2357 I WifiDisplaySource: M4 wfd_video_formats: 00 00 01 10 00008000 00000000 00000000 00 0000 0000 00 none none (profile=0 level=4 type=0 idx=15)

↑ ↑

【十六进制 Mask 00008000】 【明确写着 idx=15】

  • idx=15:在 Wi-Fi Display (WFD) 规范中,CEA Index 15 正好代表 1280x720p 24fps!

  • 00008000:转成二进制第 15 位是 1,代表只勾选了 24 帧。

  • 结论:这就是上层代码 WifiDisplaySource.cpp 在发"假消息"的现场抓包证据!

铁证二:电视(Sink)其实支持 30 帧,但被手机强行诱导选了 24 帧

看日志中的 第 17941 行(电视发给手机的能力):

行 17941: 07-18 10:07:47.415 732 2357 I WifiDisplaySource: Sink wfd_video_formats: 40 00 01 10 0001bdeb ...

↑

电视支持的掩码 0001bdeb

  • 电视发来的掩码 0001bdeb 包含 0x00000020(代表电视完全支持 720p 30帧)。

  • 但是手机的 WifiDisplaySource.cpp 因为写死了 idx=15,死板地挑了 24 帧(idx=15)发给电视。

铁证三:编码器刚启动,就被迫异常关闭(shutting down)

看日志中的 第 18005 ~ 18567 行(一次完整的崩溃周期):

行 18005: 10:07:47.515 I Converter: using audio bitrate of 128000 bps, video bitrate of 5000000 bps <-- 1. 编码器启动

行 18325: 10:07:47.649 I Converter: start cast and request IDR Frame <-- 2. 开始请求关键帧推流

行 18546: 10:07:50.111 I Converter: shutting down video encoder <-- 3. 2.4秒后,收到挂断,编码器被迫关闭!

行 18567: 10:07:50.118 I Converter: encoder (video/avc) shut down. <-- 4. H.264 视频编码器正式死亡

从 10:07:47 到 10:07:50,仅仅过了 2 秒钟:

  1. 底层 Converter 按照固定代码(30帧)初始化了编码器,并开始发 IDR 帧。

  2. 电视在校验完 RTSP 参数(24帧 vs 30帧)后,砸过来断开指令。

  3. Converter 收到上层通知,打印 shutting down video encoder,投屏宣告失败。

💡 总结:日志完美印证了排查结论

你抓到的这 50 行日志,完整复现了循环失败的过程: 发送错误 M4(idx=15) \rightarrow Converter 按照 30帧 启动

\rightarrow 电视发现矛盾挂断 \rightarrow Converter 关闭(shutting down) \rightarrow

重试下一轮...

这直接解释了为什么当你把 WifiDisplaySource.cpp 里的 idx=15 改成 idx=5(720p 30帧) 后,问题就迎刃而解了!

根据上述排查,绘制出异常的流程图如下:

三.具体修改

由于底层修改太过麻烦,而且可能要动硬件,所以我们在Framework层进行修改,patch如下:

复制代码
diff --git a/SYS_CODE/frameworks/av/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/SYS_CODE/frameworks/av/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 42f4595..63154c3 100644
--- a/SYS_CODE/frameworks/av/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/SYS_CODE/frameworks/av/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -74,13 +74,13 @@
     mSupportedSourceVideoFormats.disableAll();
 
     mSupportedSourceVideoFormats.setNativeResolution(
-            VideoFormats::RESOLUTION_CEA, 15);  // 1280x720 p23
+            VideoFormats::RESOLUTION_CEA, 5);  // 1280x720 p30
 
-    // Enable all resolutions up to 1280x720 p23
+    // The encoder is configured for 30 fps, so do not negotiate 720p24.
     mSupportedSourceVideoFormats.enableResolutionUpto(
-            VideoFormats::RESOLUTION_CEA, 15,
-            VideoFormats::PROFILE_CHP,  // Constrained High Profile
-            VideoFormats::LEVEL_32);    // Level 3.2
+            VideoFormats::RESOLUTION_CEA, 5,
+            VideoFormats::PROFILE_CBP,  // Constrained Baseline Profile
+            VideoFormats::LEVEL_31);    // Matches the encoder output
 }
 
 WifiDisplaySource::~WifiDisplaySource() {
@@ -577,6 +577,8 @@
         chosenVideoFormat.disableAll();
         chosenVideoFormat.setNativeResolution(
                 mChosenVideoResolutionType, mChosenVideoResolutionIndex);
+        chosenVideoFormat.setResolutionEnabled(
+                mChosenVideoResolutionType, mChosenVideoResolutionIndex, true);
         chosenVideoFormat.setProfileLevel(
                 mChosenVideoResolutionType, mChosenVideoResolutionIndex,
                 mChosenVideoProfile, mChosenVideoLevel);

四.拓展知识(RTSP是啥)

简单来说:RTSP(Real-Time Streaming Protocol,实时流协议)就像是无线投屏里的"遥控器"和"商务谈判官"。

在投屏过程中,它不负责传输画面本身(画面是用 RTP 协议发传输的),它只负责发送控制命令和谈判参数。

一、 用生活中的通俗比喻理解 RTSP

把无线投屏比作 "两个人打视频电话":

  • RTSP(控制协议):相当于通话前的沟通和通话中的控制指令。

  • "喂,能听到吗?"

  • "你家电视能放 720p 的视频吗?"

  • "好的,那我准备按播放键了(PLAY)!"

  • "不看了,挂断吧(TEARDOWN)!"

  • RTP(媒体传输协议):相当于真正通过网络传输的摄像头画面和语音数据包。

二、 RTSP 在 Wi-Fi 投屏里具体做了什么?(4 大核心作用)

在手机(RK3576)和电视建立好 Wi-Fi 直连后,RTSP 会在背景建立一个专属的控制通道(TCP 端口 7236),顺次完成以下 4 件事:

1. 能力谈判 (M1\~M5)\] --\> \[2. 通道建立 (SETUP)\] --\> \[3. 启动播放 (PLAY)\] --\> \[4. 维持心跳/挂断 (TEARDOWN)

  1. 商务谈判:协商音视频格式(M1 ~ M5 报文)
  • 这是本次 Bug 发生的重灾区!

  • 手机通过 RTSP 问电视:"我支持 H.264 编码,你能解 720p 30 帧吗?"

  • 电视回复:"可以,我也支持 720p 30 帧。"

  • 双方达成一致。

  1. 搭桥开路:建立媒体通道(SETUP 报文)
  • 手机对电视说:"一会儿我把视频画面发到你的 19000 端口,音频发到你的 19002 端口,你准备好接受了吗?"

  • 电视回复:"准备好了,端口已打开。"

  1. 遥控开关:控制播放状态(PLAY / PAUSE 报文)
  • 手机发出指令:PLAY(电视开始接收画面并播放)。

  • 手机发出指令:PAUSE(暂停投屏)。

  1. 维持心跳与挂断(GET_PARAMETER / TEARDOWN 报文)
  • 心跳:投屏过程中,RTSP 每隔几秒发一个微弱的信号,确保"你还活着",防止断连。

  • 挂断:当你点击手机上的"停止投屏"时,RTSP 会发一条 TEARDOWN,电视收到后关闭解码器,退回主界面。

三、 RTSP 与 RTP 的分工对照表

很多小白容易把 RTSP 和视频流搞混,看下面这张表就彻底明白了:

| 维度 | RTSP (控制协议) | RTP (媒体数据协议) |

| :------------ | :----------------------- | :---------------------- |

| **形象比喻** | 司令部的**指挥电话/命令** | 前线的**运粮车/视频像素** |

| **传输内容** | 纯文本指令(如 `PLAY`, `SETUP`) | 压缩后的 H.264 视频帧、AAC 音频帧 |

| **传输网络** | TCP(保证指令 100% 准确不丢包) | UDP(追求速度,丢一两帧画面不影响) |

| **在本次故障中的角色** | **代码写错了谈判内容**(声明了 24 帧) | 实际上运送的是 30 帧的数据车,导致电视拒收 |

四、 回看本次问题

在你的 RK3576 项目中:

  1. 底层 Converter.cpp 已经准备好了 30 帧的视频流(RTP 准备就绪)。

  2. 但是上层 WifiDisplaySource.cpp 里的 RTSP 谈判官 跑去对电视说:"我们要发 24 帧哦!"

  3. 电视在 RTSP 的 SETUP 阶段 校验发现这名"谈判官"说假话,于是电视也通过 RTSP 协议 砸过来一条

TEARDOWN(终止会话命令),直接把投屏掐断了。

相关推荐
千里马学框架5 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台5 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone5 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc5 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo6 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077006 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼6 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone6 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen6 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone6 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui