WFD_RTSP交互包分析

本文详细解析了WFD(Wi-Fi Display)协议中的RTSP交互过程,从M1到M7的消息交互,包括握手、能力协商、会话建立及数据传输等关键步骤。

在WFD交互过程中,在Source端或者Sink端抓取tcpdump,通过数据包分析软件Wireshark或者Omnipeek即可以直观的分析RTSP协议交互的过程。


关于WFD协议和代码追踪请参考阅读:
Wi-Fi Display协议介绍
WFD连接过程代码分析(Sink端)

0.准备

本次分析过程在Sink端抓取tcpdump,通过Wireshark软件分析RTSP交互M1~M7消息交互

  • Source端设备->Android Phone
  • Sink端设备->Android TV
  • Wireshark包分析软件

1.抓包

在Source端抓取tcpdump

adb shell
tcpdump -i any -s 0 -w /data/vendor/wifi/file.pcap
adb pull /data/vendor/wifi/file.pcap ./

//注:
//-i any 表示抓取所有接口(waln0、p2p0等)
//data/vendor/wifi/file.pcap 为设备端存储的路径

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.包过滤

使用Wireshark打开file.pcap,在Filter(过滤器)输入过滤条件

ip.addr==192.168.49.1 and rtsp

//注:
//ip.addr==192.168.49.1 为WiFi P2P连接GO(Group Owner)的IP地址,此处搜索GC(Group Client)的IP地址192.168.49.141也可以
//rtsp 为协议类型

  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

3.包分析

下列图中

  • Source端IP地址为192.168.49.1(承担P2P GO角色)
  • Sink端IP地址为192.168.49.141(承担P2P GC角色)

3.1 RTSP M1 Message

WFD RTSP交互开始于WFD Source端发送M1,M1 Message属于固定交互模式,Source端发送Request给Sink端,Sink端收到后回复Response。

M1 Request

如下图所示,Source发送给Sink在消息体里面包含

  • Request: OPTIONS * RTSP/1.0\r\n 用于标记此条消息的用途是询问对方options
  • CSeq:1\r\n 由发送者分配,用于计数(标记)Source端发送的Request消息
  • Server: AllShareCast/Galaxy/3.2/NIBC\r\n
  • Require: org.wfa.wfd1.0\r\n 作为tag,用于询问对方支持的WFD options

在这里插入图片描述
注:WFD协议规定每一个字段都以“\r\n”结尾

M1 Response

如下图所示,Sink发送给Source在消息体里面包含

  • Response: RTSP/1.0 200 OK\r\n 状态码200用于接收成功
  • Date: Tue, 19 Nov 2019 12:35:04 +0000\r\n 时间信息
  • User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n
  • CSeq: 1\r\n 回复Request发送过来的CSeq值,用于标明是对CSeq=1这条消息的回复
  • Public: org.wfa.wfd1.0, GET_PARAMETER, SET_PARAMETER\r\n 协议中标明Sink端在接收到Source端Request消息后固定的答复内容

在这里插入图片描述

3.2 RTSP M2 Message

当M1交互完成后,开始M2交互,也属于固定交互模式,Sink端发送Request给Source端,Source端收到后回复Response

M2 Request

如下图所示,Sink发送给Source在消息体里面包含

  • Request: OPTIONS * RTSP/1.0\r\n 用于标记此条消息的用途是询问对方options
  • Date: Tue, 19 Nov 2019 12:35:04 +0000\r\n 时间信息
  • User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n
  • CSeq: 1\r\n 由发送者分配,用于计数(标记)Sink端发送的Request消息
  • Require: org.wfa.wfd1.0\r\n 作为tag,用于询问对方支持的WFD options

在这里插入图片描述

M2 Response

如下图所示,Source发送给Sink在消息体里面包含

  • Respose: RTSP/1.0 200 OK\r\n 状态码200用于接收成功
  • CSeq: 1\r\n 回复Request发送过来的CSeq值,用于标明是对CSeq=1这条消息的回复
  • Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMETER\r\n 协议中标明Source端在接收到Sink端Request消息后固定的答复内容

在这里插入图片描述

3.3 RTSP M3 Message

M1和M2交互类似日常见面的打招呼,你Hi一句,我点个头回复一句Hello。接下来进行的M3交互,询问Sink端的能力和支持的功能。

M3 Request

如下图所示,Source发送给Sink在消息体里面包含

  • Request: GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n 用于标明获取Sink端的参数
  • CSeq: 2\r\n 用于标注Source发出的第二条Request
  • Content-type: text/parameters 用于标明消息体中包含parameters
  • Content-length: 338 表示parameters长度
  • Line-based text data: text/parameters (15 lines) 下面列出具体的参数
    • wfd_video_formats\r\n 视频格式
    • wfd_audio_codecs\r\n 音频格式
    • … …

在这里插入图片描述

M3 Response

如下图所示,Sink发送给Source在消息体里面包含

  • Response: RTSP/1.0 200 OK\r\n 状态码200用于接收成功
  • Date: Tue, 19 Nov 2019 12:35:04 +0000\r\n 时间信息
  • User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n
  • CSeq: 2\r\n 回复Request发送过来的CSeq值,用于标明是对CSeq=2这条消息的回复
  • Content-type: text/parameters
  • Content-length: 327
  • Line-based text data: text/parameters (8 lines)
    • wfd_video_formats: 48 00 02 02 0001DEFF 157C7FFF 00000FFF 00 0000 0000 00 none none\r\n 视频编码格式
    • wfd_audio_codecs: LPCM 00000003 00\r\n 音频编码格式
    • wfd_content_protection: none\r\n 不支持HDCP加密
    • wfd_coupled_sink: 00 none\r\n 不支持有主Sink和次Sink耦合
    • wfd_uibc_capability: none\r\n 不支持UIBC
    • wfd_standby_resume_capability: none\r\n 不支持standby
    • wfd_lg_dlna_uuid: none\r\n
    • wfd_client_rtp_ports: RTP/AVP/UDP;unicast 15550 0 mode=play\r\n Sink端RTP交互端口为15550

在这里插入图片描述

3.4 RTSP M4 Message

M3交互Source端了解到Sink端的编解码能力后,Source依据自身的能力和Sink端的能力决定使用编解码格式等,通过M4发送给Sink端,Sink端如果验证后支持,则回复ok,如不支持,则M3继续协商。

M4 Request

如下图所示,Source发送给Sink在消息体里面包含

  • Request: SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n 用于设置使用的音视频格式等
  • CSeq: 3\r\n 用于标注Source发出的第三条Request
  • Content-type: text/parameters
  • Content-length: 248
  • Line-based text data: text/parameters (4 lines)
    • wfd_video_formats: 00 00 02 02 00000080 00000000 00000000 00 0000 0000 00 none none\r\n 使用这个视频格式
    • wfd_audio_codecs: LPCM 00000002 00\r\n 使用这个音频格式
    • wfd_presentation_URL: rtsp://192.168.49.1/wfd1.0/streamid=0 none\r\n 用于设置WFD会话
    • wfd_client_rtp_ports: RTP/AVP/UDP;unicast 15550 0 mode=play\r\n

在这里插入图片描述

M4 Response

如下图所示,Sink发送给Source在消息体里面包含

  • Response: RTSP/1.0 200 OK\r\n 状态码200用于接收成功
  • Date: Tue, 19 Nov 2019 12:35:04 +0000\r\n
  • User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n
  • CSeq: 3\r\n 回复Request发送过来的CSeq值,用于标明是对CSeq=3这条消息的回复

在这里插入图片描述

3.5 RTSP M5 Message

M4交互完毕后,开始建立WFD会话,即M5的交互

M5 Request

如下图所示,Source发送给Sink在消息体里面包含

  • Request: SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n
  • CSeq: 4\r\n 用于标注Source发出的第四条Request
  • Content-type: text/parameters
  • Content-length: 27
  • Line-based text data: text/parameters (1 lines)
    • wfd_trigger_method: SETUP\r\n 开始WFD会话建立

在这里插入图片描述

M5 Response

如下图所示,Sink发送给Source在消息体里面包含

  • Response: RTSP/1.0 200 OK\r\n 状态码200用于接收成功
  • Date: Tue, 19 Nov 2019 12:35:04 +0000\r\n 时间信息
  • User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n
  • CSeq: 4\r\n 回复Request发送过来的CSeq值,用于标明是对CSeq=4这条消息的回复

在这里插入图片描述

3.6 RTSP M6 Message

M5后,Sink端给Source端发送M6 Request

M6 Request

如下图所示,Sink发送给Source在消息体里面包含

  • Request: SETUP rtsp://192.168.49.1/wfd1.0/streamid=0 RTSP/1.0\r\n
  • Date: Tue, 19 Nov 2019 12:35:04 +0000\r\n 时间信息
  • User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n
  • CSeq: 2\r\n 用于标注Sink发出的第二条Request
  • Transport: RTP/AVP/UDP;unicast;client_port=15550-15551 Sink端RTP交互端口为15550,RTCP交互端口为15551

在这里插入图片描述

M6 Response

如下图所示,Source发送给Sink在消息体里面包含

  • Response: RTSP/1.0 200 OK\r\n 状态码200用于接收成功
  • CSeq: 2\r\n 回复Request发送过来的CSeq值,用于标明是对CSeq=2这条消息的回复
  • Session: 1957747793;timeout=30 标明会话ID为1957747793和超时
  • Transport: RTP/AVP/UDP;unicast;client_port=15550-15551;server_port=19000-19001 //重述Client(Sink)端的端口,并标明Source(Server)RTP交互端口为19000,RTCP交互端口为19001

在这里插入图片描述

3.7 RTSP M7 Message

M6交互完毕后,M7告知Source端一切准备就绪,开始发送数据

M7 Request

如下图所示,Sink发送给Source在消息体里面包含

  • Request: PLAY rtsp://192.168.49.1/wfd1.0/streamid=0 RTSP/1.0\r\n
  • Date: Tue, 19 Nov 2019 12:35:06 +0000\r\n
  • User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n
  • CSeq: 3\r\n 用于标注Sink发出的第三条Request
  • Session: 1957747793

在这里插入图片描述

M7 Response

如下图所示,Source发送给Sink在消息体里面包含

  • Response: RTSP/1.0 200 OK\r\n 状态码200用于接收成功
  • CSeq: 3\r\n 回复Request发送过来的CSeq值,用于标明是对CSeq=3这条消息的回复
  • Session: 1957747793;timeout=30
  • Range: npt=now-\r\n

在这里插入图片描述

综上所述

MessageMethodDirect简述重点
M1OPTIONSSource -> Sink打招呼
M2OPTIONSSource <- Sink打招呼
M3GET_PARAMETERSource -> Sink你支持什么音视频格式wfd_video_formats/wfd_audio_codecs
M4SET_PARAMETERSource -> Sink我们使用这个格式吧
M5SETUPSource -> Sink建立连接吧
M6SETUPSource <- Sink建立连接吧client_port/server_port/Session ID
M7PLAYSource <- Sink开始发送数据吧

在M1-M7交互完毕,开始传输音视频数据过程中,由于一些外部原因(信号强弱)或者内部原因双方会动态调整使用的音视频格式,所以还有可能会交互GET_PARAMETER如下图所示,这里不再敖述。

在这里插入图片描述

参考:
【1】《Wi-Fi_Display_Technical_Specification_v2.1_0》

### 枚举类型 WFD_CLIENT_TYPE 定义及其含义解析 #### 枚举定义 WFD_CLIENT_TYPE 是一个枚举类型,主要用于标识 Wi-Fi Display (Miracast) 中不同类型的客户端设备。其具体定义通常位于相关 SDK 或驱动程序头文件中,以下是基于常见实现的一个假设性定义示例: ```c typedef enum _WFD_CLIENT_TYPE { WFD_CLIENT_TYPE_SOURCE = 0x0, WFD_CLIENT_TYPE_SINK = 0x1, WFD_CLIENT_TYPE_CLUSTER = 0x2, WFD_CLIENT_TYPE_UNKNOWN = 0xFF } WFD_CLIENT_TYPE; ``` 该枚举含了多个预定义常量值,分别表示不同的客户端角色[^1]。 --- #### 各类型含义详解 1. **WFD_CLIENT_TYPE_SOURCE** - 表示源设备(Source Device),通常是负责发送视频流和音频信号的一方。 - 这种类型的设备一般由智能手机、笔记本电脑或其他多媒体播放器担任。 - 源设备的主要职责是捕获屏幕内容并通过无线网络将其传递给接收端设备。 2. **WFD_CLIENT_TYPE_SINK** - 描述接收设备(Sink Device),也称为显示设备或目标设备。 - SINK 类型的典型代表括电视、投影仪以及支持 Miracast 功能的显示器等硬件装置。 - 此类设备的任务是从 SOURCE 获取媒体数据并渲染成可视化的图像输出。 3. **WFD_CLIENT_TYPE_CLUSTER** - 定义集群节点(Cluster Node),这类特殊形式的客户端既可能是 SOURCE 又可以充当 SINK 角色。 - CLUSTER 设备经常应用于复杂拓扑结构之中,例如会议室多屏互动方案或者家庭影院系统扩展应用场合下。 - 在实际部署过程中,CLUSTER 能够动态调整自身行为模式以适应实时变化的需求情境[^1]。 4. **WFD_CLIENT_TYPE_UNKNOWN** - 当前无法识别或未指定确切类型的占位符标志。 - 若某项操作尝试访问未知类别实例时可能会触发默认处理路径或是抛出异常告警信息提醒开发人员注意潜在风险因素存在[^1]。 --- #### 示例代码展示 以下给出一段 C++ 程序片段,说明如何利用这些枚举值来进行简单的分支判断逻辑编写工作: ```cpp #include <iostream> using namespace std; enum class WFD_CLIENT_TYPE : uint8_t { SOURCE = 0x0, SINK = 0x1, CLUSTER = 0x2, UNKNOWN = 0xFF }; void describe_client_type(WFD_CLIENT_TYPE type) { switch(type){ case WFD_CLIENT_TYPE::SOURCE: cout << "This client acts as a source device." << endl; break; case WFD_CLIENT_TYPE::SINK: cout << "This client serves as a sink/display device." << endl; break; case WFD_CLIENT_TYPE::CLUSTER: cout << "This client operates within a cluster environment." << endl; break; default: cout << "Unknown or unsupported client type detected!" << endl; } } int main(){ WFD_CLIENT_TYPE myType = static_cast<WFD_CLIENT_TYPE>(rand()%4); describe_client_type(myType); return 0; } ``` 上述代码随机生成了一个 `myType` 对象,并依据其实例化后的具体取值打印对应的文字描述信息。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值