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(终止会话命令),直接把投屏掐断了。

相关推荐
晓梦林3 小时前
[ACTF2020 新生赛]BackupFile学习笔记
android·笔记·学习
ITmaster07314 小时前
告别 IDE?Android CLI 来了,开发进入 AI Agent 时代
android·ide·人工智能
aaajj5 小时前
【Android】获取设备音频
android
清泓y6 小时前
UE移动开发技术面试题
android·面试·ue5·ue4·游戏程序
DevRen6 小时前
Compose Snapshot 系统详解
android
艾莉丝努力练剑9 小时前
【MYSQL】MYSQL学习的一大重点:基本查询(下)
android·数据库·学习·mysql·面试·八股文
三少爷的鞋9 小时前
Android 中coroutineScope 和 supervisorScope 到底怎么选?先搞清楚 Exception 和 Result
android
其实防守也摸鱼11 小时前
KMP全栈开发:从Android到AI Agent的技术演进与实践
android·运维·网络·人工智能·学习·安全·macos
YM52e15 小时前
鸿蒙Flutter Padding内边距:EdgeInsets详解
android·学习·flutter·华为·harmonyos·鸿蒙