Miracast技术详解(二):RTSP协议


目录

RTSP概述

在上一篇博客中我们已经通过Wi-Fi P2P建立好了Source和Sink端的TCP连接,在Miracast后续的音视频传输过程中,将采用RTSP协议来对流媒体进行控制。因此接下来的步骤就到了RTSP协商、会话建立及流媒体传输的阶段。首先,什么是RTSP协议呢?

实时流协议(Real Time Streaming Protocol,RTSP)是一种网络应用协议,专为娱乐和通信系统的使用,以控制流媒体服务器。该协议用于创建和控制终端之间的媒体会话。媒体服务器的客户端发布VCR命令,例如播放,录制和暂停,以便于实时控制从服务器到客户端(视频点播)或从客户端到服务器(语音录音)的媒体流。

流数据本身的传输不是RTSP的任务。大多数RTSP服务器使用实时传输协议(RTP)和实时传输控制协议(RTCP)结合媒体流传输。关于流媒体传输用到的协议与过程,我们将会在下一篇博客中进行详解。

抓包准备

要分析RTSP的指令协商过程,最好的方法就是抓取TCP的数据包,并进行分析。Android上可以采用tcpdump工具(tcpdump详解)抓取TCP的包,然后通过Wireshark工具导入进行分析。

# 在Source端抓取tcpdump
adb shell
tcpdump -i any -p -s 0 -w /data/local/capture.pcap
# -i any 表示抓取所有接口(waln0、p2p0等)

最终抓取到的数据包如下图所示,通过Wireshark的过滤功能我们可以很方便的过滤RTSP协议的数据包:

image

WFD能力协商(Capability Negotiation)

在Source和Sink端的TCP连接成功建立之后,会马上进入到RTSP能力协商的阶段,主要涉及到RTSP M1-M4指令,双方将按照以下顺序发送与处理消息。
image

RTSP M1 Messages

由Source端发起一个RTSP OPTIONS M1请求,以确认Sink端所支持的RTSP方法请求。Request和Response如下所示:

Request(Source -> Sink)

OPTIONS * RTSP/1.0/r/n
Date: Wed, 11 Dec 2019 08:31:54 +0000/r/n
Server: stagefright/1.2 (Linux;Android 8.1.0)/r/n
CSeq: 1/r/n
Require: org.wfa.wfd1.0/r/n
/r/n

Response(Sink -> Source)

RTSP/1.0 200 OK/r/n
CSeq: 1/r/n
Public: org.wfa.wfd1.0, GET_PARAMETER, SET_PARAMETER/r/n
/r/n

RTSP M2 Messages

在Sink回复完M1指令后,会由Sink端发起一个RTSP OPTIONS M2请求,以确认Source端所支持的RTSP方法请求。Request和Response如下所示:

Request(Sink -> Source)

OPTIONS * RTSP/1.0/r/n
CSeq: 0/r/n
User-Agent: wfdsinkemu/r/n
Require: org.wfa.wfd1.0/r/n
/r/n

Response(Source -> Sink)

RTSP/1.0 200 OK/r/n
Date: Wed, 11 Dec 2019 08:31:54 +0000/r/n
Server: stagefright/1.2 (Linux;Android 8.1.0)/r/n
CSeq: 0/r/n
Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMETER/r/n
/r/n

RTSP M3 Messages

在Source端回复完M2指令后,会由Source端发起GET_PARAMETER M3请求,以查询Sink端的属性以及能力,所查询的属性列表在请求最后。

Request(Source -> Sink)

GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0/r/n
Date: Wed, 11 Dec 2019 08:31:54 +0000/r/n
Server: stagefright/1.2 (Linux;Android 8.1.0)/r/n
CSeq: 2/r/n
Content-type: text/parameters
Content-length: 83
/r/n
Line-based text data: text/parameters (4 lines)
    wfd_content_protection/r/n
    wfd_video_formats/r/n
    wfd_audio_codecs/r/n
    wfd_client_rtp_ports/r/n

Sink端回复M3指令,告诉Source端自身支持的属性及能力,比较重要的几个属性:RTP端口号wfd_client_rtp_ports(传输流媒体用)、所支持的audio及video编解码格式wfd_audio_codecswfd_video_formats等…

Response(Sink -> Source)

RTSP/1.0 200 OK/r/n
CSeq: 2/r/n
Content-type: text/parameters
Content-length: 848
/r/n
Line-based text data: text/parameters (7 lines)
    wfd_client_rtp_ports: RTP/AVP/UDP;unicast 20011 0 mode=play/r/n
    wfd_audio_codecs: LPCM 00000002 00, AAC 00000001 00/r/n
    wfd_video_formats: 78 00 01 01 00008400 00000000 00000000 00 0000 0000 00 none none/r/n
    wfd_connector_type: 07/r/n
    wfd_uibc_capability: none/r/n
    wfd_content_protection: none/r/n
    wfd_idr_request_capability: 1/r/n

RTSP M4 Messages

基于Sink端回复的M3指令,将由Source端发起SET_PARAMETER M4指令,以最终设置此次会话里的最佳参数集(收发双方都支持的编解码器类型等等)

Request(Source -> Sink)

SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0/r/n
Date: Wed, 11 Dec 2019 08:31:54 +0000/r/n
Server: stagefright/1.2 (Linux;Android 8.1.0)/r/n
CSeq: 3/r/n
Content-type: text/parameters
Content-length: 247
/r/n
Line-based text data: text/parameters (4 lines)
    wfd_video_formats: 00 00 01 01 00000400 00000000 00000000 00 0000 0000 00 none none/r/n
    wfd_audio_codecs: AAC 00000001 00/r/n
    wfd_presentation_URL: rtsp://192.168.49.5/wfd1.0/streamid=0 none/r/n
    wfd_client_rtp_ports: RTP/AVP/UDP;unicast 20011 0 mode=play/r/n

Response(Sink -> Source)

RTSP/1.0 200 OK/r/n
CSeq: 3/r/n
/r/n

wfd_video_formats格式解析

在官方WifiDisplaySource.cpp源码中,有对wfd_video_formats格式做了详细解释,各个字段的含义如下:

// wfd_video_formats:
// 1 byte "native"
// 1 byte "preferred-display-mode-supported" 0 or 1
// one or more avc codec structures
//   1 byte profile
//   1 byte level
//   4 byte CEA mask
//   4 byte VESA mask
//   4 byte HH mask
//   1 byte latency
//   2 byte min-slice-slice
//   2 byte slice-enc-params
//   1 byte framerate-control-support
//   max-hres (none or 2 byte)
//   max-vres (none or 2 byte)

其中比较重要的几个字段解释如下图所示:

Field Size (octets) Description
Native Resolutions/Refresh Rates bitmap 1 Bitmap defined in Table 37 detailing native display resolutions and refresh rates supported by the WFD Sink.
Profiles bitmap 1 Bitmap defined in Table 38 detailing the H.264 profile indicated by this instance of the WFD Video Formats subelement.
Levels bitmap 1 Bitmap defined in Table 39 detailing the H.264 level indicated by this instance of the WFD Video Formats subelement.
CEA Resolutions/Refresh Rates bitmap 4 Bitmap defined in Table 34 detailing CEA resolutions and refresh rates supported by the CODEC.
VESA Resolutions/Refresh Rates bitmap 4 Bitmap defined in Table 35 detailing VESA resolutions and refresh rates supported by the CODEC.
HH Resolutions/Refresh Rates bitmap 4 Bitmap defined in Table 36 detailing HH resolutions and refresh rates supported by the CODEC.

Native Resolutions/Refresh Rates Bitmap

该字段描述了Sink端设备当前的分辨率与刷新率,占1字节,其中低3位代表了分辨率模式选择位,高5位则代表当前分辨率与刷新率在表中的index。其中000代表选用CEA标准分辨率,而001则代表VESA标准分辨率,详见下表:

Bits Name Interpretation
2:0 Table Selection bits 0b000: Resolution/Refresh rate table selection: Index to CEA resolution/refresh rates (Table 34) 0b001: Resolution/Refresh rate table selection: Index VESA resolution/refresh rates (Table 35) 0b010: Resolution/Refresh rate table selection: Index HH resolutions/refresh rates (Table 36) 0b011~0b111: Reserved
7:3 Index bits Index into resolution/refresh rate table selected by [B2:B0]

CEA Resolutions/Refresh Rates Bitmap

该字段描述了当前Sink端设备所支持的分辨率与刷新率,占4个字节,总共32位,其中每一位都是一个flag,值为1代表支持该标志位对应的分辨率与刷新率。其中可以同时对多个标志位置1,代表同时支持这几种分辨率与刷新率。

Bits Index Interpretation
0 0 640×480 p60
1 1 720×480 p60
2 2 720×480 i60
3 3 720×576 p50
4 4 720×576 i50
5 5 1280×720 p30
6 6 1280×720 p60
7 7 1920×1080 p30
8 8 1920×1080 p60
9 9 1920×1080 i60
10 10 1280×720 p25
11 11 1280×720 p50
12 12 1920×1080 p25
13 13 1920×1080 p50
14 14 1920×1080 i50
15 15 1280×720 p24
16 16 1920×1080 p24
31:17 Reserved

Profiles Bitmap

该字段描述了当前Sink端设备所支持的H.264 profile配置,占1字节,低0位与低1位分别是CBP(Constrained Baseline Profile)与CHP(Constrained High Profile)标志位,置1时代表支持该配置,剩下的6位则为保留位。

Bits Name Interpretation
0 CBP bit 0b0: Constrained Baseline Profile (CBP) not supported 0b1: CBP supported
1 CHP bit 0b0: Constrained High Profile (CHP) not supported 0b1: CHP supported
7:2 Reserved Set to all zeros

Levels Bitmap

该字段描述了当前Sink端设备所支持的H.264 level限制。其中level是一组特定的约束,表示一个profile所需的解码性能。占1字节,低5位代表了各个level的flag位,置1时表示支持该level。关于H.264中profile与level的介绍不在这里详细展开,有兴趣的可以自行了解。

Bits Name Interpretation
0 H.264 Level 3.1 bit 0b0: H.264 Level 3.1 not supported 0b1: H.264 Level 3.1 supported
1 H.264 Level 3.2 bit 0b0: H.264 Level 3.2 not supported 0b1: H.264 Level 3.2 supported
2 H.264 Level 4 bit 0b0: H.264 Level 4 not supported 0b1: H.264 Level 4 supported
3 H.264 Level 4.1 bit 0b0: H.264 Level 4.1 not supported 0b1: H.264 Level 4.1 supported
4 H.264 Level 4.2 bit 0b0: H.264 Level 4.2 not supported 0b1: H.264 Level 4.2 supported
7:5 Reserved Set to all zeros

例子

我们这里拿几个官方的例子来帮助大家理解,如第一组数据30 00 02 02 00000040 …对应为720p/60帧,其中

  • Native 30二进制表示为0011 0000,低3位为0,代表CEA标准分辨率;高5位为分辨率index,00110换算为6,对应CEA分辨率表中的Index 61280x720 p60
  • Profile 02二进制表示为0000 0010,表示支持Constrained High Profile
  • Levels 02二进制表示为0000 0010,表示支持H.264 Level 3.2
  • CEA 00000040二进制0000 0000 0000 0000 0000 0000 0100 0000,也就是第6位flag置1,对应CEA分辨率表中的Index 61280x720 p60。此外,CEA字段可以同时对多个标志位置1,代表同时支持这几种分辨率与刷新率。

其他的几个例子大家可以按照上面的思路一一分析,这里不再展开。

// For 720p60:
//   use "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none/r/n"
// For 720p30:
//   use "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none/r/n"
// For 720p24:
//   use "78 00 02 02 00008000 00000000 00000000 00 0000 0000 00 none none/r/n"
// For 1080p30:
//   use "38 00 02 02 00000080 00000000 00000000 00 0000 0000 00 none none/r/n"

WFD会话建立(Session Establishment)

在Sink回复完M4指令后,能力协商的过程就结束了,下一步则是WFD会话建立过程,主要涉及到RTSP M5-M7指令。双方将按照以下顺序发送与处理消息。
image

RTSP M5 Messages

由Source端发起SET_PARAMETER M5请求,通过wfd_trigger_method参数触发Sink端向Source端进行SETUP、PLAY、PAUSE、TEARDOWN等请求。如下M5 Request中设置了SETUP触发请求。

Request(Source -> Sink)

SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0/r/n
Date: Wed, 11 Dec 2019 08:31:54 +0000/r/n
Server: stagefright/1.2 (Linux;Android 8.1.0)/r/n
CSeq: 4/r/n
Content-type: text/parameters
Content-length: 27
/r/n
Line-based text data: text/parameters (1 lines)
    wfd_trigger_method: SETUP/r/n

Sink端则正常回复,表示自己已经收到SETUP触发请求即可。

Response(Sink -> Source)

RTSP/1.0 200 OK/r/n
CSeq: 4/r/n
/r/n

RTSP M6 Messages

上面说到了M5 Request中设置了SETUP触发请求,则此时应该由Sink端主动发送SETUP M6请求:

Request(Sink -> Source)

SETUP rtsp://192.168.49.5/wfd1.0/streamid=0 RTSP/1.0/r/n
CSeq: 1/r/n
Transport: RTP/AVP/UDP;unicast;client_port=20011
/r/n

此时Source端将完成RTSP会话的创建,并返回Session ID:

Response(Source -> Sink)

TSP/1.0 200 OK/r/n
Date: Wed, 11 Dec 2019 08:31:55 +0000/r/n
Server: stagefright/1.2 (Linux;Android 8.1.0)/r/n
CSeq: 1/r/n
Session: 1804289383;timeout=30
Transport: RTP/AVP/UDP;unicast;client_port=20011;server_port=26466
/r/n

RTSP M7 Messages

经过M6指令交互后,RTSP会话已经完成创建。此时将由Sink端发送PLAY M7请求,告诉发送端可以开始发送流媒体数据了:

Request(Sink -> Source)

PLAY rtsp://192.168.49.5/wfd1.0/streamid=0 RTSP/1.0/r/n
CSeq: 2/r/n
Session: 1804289383;timeout=30
/r/n

Source端回复M7指令,并且状态是200 OK时,WFD Session成功建立。

Response(Source -> Sink)

RTSP/1.0 200 OK/r/n
Date: Wed, 11 Dec 2019 08:31:55 +0000/r/n
Server: stagefright/1.2 (Linux;Android 8.1.0)/r/n
CSeq: 2/r/n
Session: 1804289383;timeout=30
Range: npt=now-/r/n
/r/n

经过以上M1-M7的指令交互,且成功创建WFD会话后,Source与Sink端的协商及会话过程已完成。这个时候Source端会按照Sink指定的UDP端口发送RTP数据包,包含音视频数据。

总结M1-M7过程:

Message Method Direct 简述 重点
M1 OPTIONS Source -> Sink 打招呼
M2 OPTIONS Source <- Sink 打招呼
M3 GET_PARAMETER Source -> Sink 你支持什么音视频格式 wfd_video_formats/wfd_audio_codecs
M4 SET_PARAMETER Source -> Sink 我们使用这个格式吧
M5 SETUP Source -> Sink 建立连接吧
M6 SETUP Source <- Sink 建立连接吧 client_port/server_port/Session ID
M7 PLAY Source <- Sink 开始发送数据吧

关闭会话

RTSP M5 Messages这一节中,我们谈到会由Source端发起SET_PARAMETER M5请求,触发Sink端发送TEARDOWN请求。该请求可以使得Source与Sink端的RTSP及RTP连接断开。

RTSP M8 Messages

  1. 场景1:Source端主动关闭会话:
    首先会由Source发送M5请求,并且wfd_trigger_method的值为TEARDOWN,触发Sink端发送TEARDOWN M8指令:
  2. 场景2:Sink端主动关闭会话:
    Sink端直接发送TEARDOWN M8指令

Request(Sink -> Source)

TEARDOWN rtsp://192.168.49.5/wfd1.0/streamid=0 RTSP/1.0/r/n
CSeq: 3/r/n
Session: 1804289383
/r/n

Response(Source -> Sink)

RTSP/1.0 200 OK/r/n
CSeq: 3/r/n
Date: Tue, Dec 17 2019 07:20:28 GMT/r/n
/r/n

总结

针对Miracast RTSP协商、会话建立及流媒体传输,我们来进行一下总结。

  • 在Source和Sink端的TCP连接成功建立之后,会马上进入到RTSP能力协商的阶段,主要涉及到M1-M4指令
  • 能力协商的过程结束后,下一步则是WFD会话建立过程,主要涉及到M5-M7指令
  • WFD会话成功建立后,将由Source端通过UDP连接发送RTP音视频数据包
  • 通过PAUSE、PLAYTEARDOWN等指令控制音视频流暂停、播放、关闭
  • 通过M16指令来维持WFD长连接,确保会话处于正常的状态

我们可以使用下图来对整个WFD会话的生命周期进行总结:
Miracast技术详解(二):RTSP协议

参考:
WFD_RTSP交互包分析
Miracast技术详解(二):RTSP协议

原创文章,作者:dweifng,如若转载,请注明出处:https://blog.ytso.com/274085.html

(0)
上一篇 2022年7月13日
下一篇 2022年7月13日

相关推荐

发表回复

登录后才能评论