投屏是指将某个终端的音视频或者其他内容通过有线或者无线的形式投射到其他终端上的一种协议。目前常见的投屏协议有DLNA
/Airplay
/Mirracast
/Chromecast
:
DLNA
(Digital Living Network Alliance
): DNLA是由英特尔、索尼、微软等消费电子巨头在2003年建立的一个文件共享协议,目前很多的电视都会支持DLNA
协议,用于手机与电视之间共享视频与图片等资源。Airplay
: Airplay是苹果公司开发的一个私有的投屏协议,实际包含了视频投屏与屏幕镜像等几个功能(音视频数据流包括交互控制协议都有是加密的),可以用于播放音频、视频,也可以把本地的图片投屏到电视上进行浏览。目前国内很多支持Airplay
的投屏协议都是基于秘钥破解进行开发的。Mirracast
: Mirracast是WIFI
联盟在2012年推出的一种基于WIFI
将某个终端设备的音视频投屏到其他终端(比如电视、平板)上的协议,通常也被称为HDMI over WIFI
。Android
最开始在AOSP 4.1
上实现了一个类似的Mirracast
协议,后来的版本则全部删除了,后来Google
就推出了闭源的一个投屏协议Chromecast
。Chromecast
:Google
在2013年基于Google Cast
协议开发的一个闭源的投屏协议,可以用于播放在线的音视频内容,用户可以通过支持Google Cast
协议的手机或PC上的浏览器来控制音视频内容的播放。同时,Google
提供了一个SDK给第三方应用开发投屏功能。
对一个投屏协议来说,要在两个终端之间建立一个投屏的连接,通常需要经历如下几个步骤:
- 被投屏的设备端以广播的形式向局域网的设备发布服务(该服务的信息通常会包含设备的名车,IP地址,以及通讯所用的端口地址等)
- 需要投屏的终端发现该服务后,会基于广播中的端口地址与另一端建立网络链接(控制与数据传输可能需要分开两个连接)
- 网络连接建立完成后,服务端需要告知对端设备的一些配置信息(比如设备的显示器的大小以及刷新率等)
- 投屏完成初始化配置后,最后一步就是投屏的终端向服务端发送需要投屏的内容(内容可能是音视频数据流,也可能是一个在线播放的
URL
)
从上面的流程,我们可以看到,不同的投屏协议在其他方面可能有很大差别,但都离不开服务发现协议(Service Discovery
)。在这篇文章,我们就来看看DLNA
/Airplay
/Mirracast
三种投屏协议中所使用到的服务发现协议具体是怎么个原理。
DLNA的服务发现
在DLNA
中,播放音视频的一方通常被称为Digital Media Renderer(DMR)
,而发送音视频数据的一方则称为Digital Media Server(DMS)
, 负责中转数据的设备节点则称为Control Point
(一般情况下,我们通常只有DMS/DMR
两个设备,因此下文都是基于这种两个设备通讯的情况下进行讨论的)。DLNA
使用UPnP(Universal Plug and Play)
协议来进行服务发现以及数据的传输;UPnP
可以在网络连接后通过UDP
端口1900
自动发布服务,DMS
在收到该服务的广播消息后,会发送一个消息确认DMR
的存在,这样整个服务发现过程就完成了。UPnP
使用的服务发现协议叫做SSDP(Simple Service Discovery Protocol)
。
DMR
服务启动后,会不断的通过组播地址239.255.255.250:1900
发送Advertisement
消息,广播系统当前的设备与服务状态(如果DMR
中有多个设备或者服务,则会同时发送多个组播消息),告知DMS
有相应的设备与服务可用; 需要投屏的设备(DMS
)收到该广播消息后,主动发送一个M-SEARCH(ssdp:discover)
的消息, DMR
收到该消息后需要发送一个UDP
消息给DMS
设备,该消息需要包含一个与广播Advertisement
中一样的UUID
。Advertisement
消息一般有三种类型:
NOTIFY ssdp:alive
: 当一个设备加入到网络中时需要发送alive
消息广播根设备(root device
)以及其他设备与服务的为可用状态,这样其他设备收到该消息后就可以发起连接NOTIFY ssdp:byebye
: 设备从网络中移除时需要发送一个byebyte
的消息告知其他节点设备即将变为不可用状态NOTIFY ssdp:update
: 这个消息主要用于多IP设备广播设备与服务状态
以alive
组播消息为例,可以看到对于SSDP
报文来说,最主要的字段主要有如下几个:
CACHE-CONTROL:max-age=1800
:Advertisement
消息最长生命周期LOCATION
: 根设备的URL
地址,一般是由IP地址与连接协议的监听端口号组成NT
: 通知类型,如果是根设备通常是upnp:rootdevice
, 其他设备对应的类型值是NT:uuid:<uuid>
;如果是服务,则一般以urn
开头,如:NT: urn:schemas-upnp-org:device:MediaRenderer
NT: urn:schemas-upnp-org:service:ConnectionManager
一旦完成服务发现,DMR
通过SOAP/XML
以及HTTP
协议发布服务能力以及支持的协议,比如是否可以播放视频,是否能浏览图片等,最后通过连接服务来发送控制指令,可以完成诸如播放、暂停、跳转等功能。更多有关UPnP/SSDP
协议相关的可以参考如下两个链接:
Airplay中的服务发现
苹果的Airplay
协议算是投屏协议里比较完全全面的,可以支持在线的音视频投屏、屏幕镜像以及图片浏览等功能,而且投屏过程中加入了私有秘钥验证机制,可以说是这几个投屏协议里安全性最好的。另外,Airplay
可以支持有线与无线两种投屏方式。
实际上Airplay
包含了两个服务,一个用于传输音频数据流的RAOP(Remote Audio Output Protocol)
; 一个是用于传输视频与图片数据流的Airplay
服务。Airplay
中的服务发现是基于DNS
的多播协议muticast DNS(mDNS)
(最开始由Apple
开源出来,也叫做Bonjour
)来实现的,服务的发布与发现类似与域名的DNS
解析过程:
- 服务端通过
mDNS
服务进程发布RAOP/Airplay
服务, 并监听UDP
端口5353
- 客户端连接上同一网络后,会发送
QUERY
到多播地址224.0.0.251
对应的5353
端口 - 服务端的
mDNS
收到请求后,把登记好的服务发送给对应的客户端
通过单播(
Unicast
)方式发送的QUERY
响应(RESPONSE
)的消息,称为QU
消息; 通过多播方式发送RESPONSE
的消息,称为QM
消息。这个标志位会在mDNS
消息中设置
下面两个图分别是mDNS
的QUERY/RESPONSE
的消息,可以看到mDNS
的消息结构与DNS
的完全一致: QUERY
中包含了需要查询的服务以及权威名称服务(Authoritative nameservers
, 实际是客户端网口的MAC
组成的一个名字而已); RESPONSE
消息(根据记录类型不同,一般有PTR
/TXT
两种)包含了服务的名称、协议类型,端口号以及协议所需要的其他字段(如设备的属性,设备的能力以及MAC
地址等)。
完成服务发现后,客户端就会根据查询到的服务的端口与服务端建立连接,一般数据传输都使用TCP
传输,其他的如时间同步协议则使用UDP
。
Android
中已经集成了mDNS
协议,代码可以参考mdnsresponder, 有关mDNS
的详细细节可以参考RFC6762。
Airplay
是苹果公司的私有投屏协议,网上有一些相关的协议逆向分析的文档,但是都不算很全面,这里是之前搜索到的资料可以参考:
已有实现的参考代码Github RPiPlay。
Mirrorcast中的服务发现
Mirrorcast
在Android也被称作Wifi Display(WFD)
,简单来说是一个通过WIFI
来传输音视频数据的协议, 可以用于设备的屏幕镜像,这个跟Airplay
的屏幕镜像功能是类似的。早在Android 4.1
的时候Google
开源过相关代码; 从实现来看, Mirrorcast
并不算复杂,其主要分为两个大的步骤:
- 通过
P2P
协议(也叫做WIFI
直连(Wifi Direct
))发现可用的WFD
设备 - 与对应的
P2P
设备建立RTP
连接,镜像的数据会通过RTP
发送到接收端
P2P
协议的发现分为两个流程,首先是设备的发现(Device Disconvery
): 设备发现大致需要经过扫描与发现两个阶段。一个P2P
设备要被发现需要处于LISTEN
状态,并在2.4GHZ中的几个固定的Socical
频段(1/6/11三个频段)选择一个频段进行监听,P2P
设备在监听状态时只会对Prope Request Frames
做出响应;设备在监听状态会等待固定的时间长度(0~100TU的随机时间)后,进入设备扫描阶段,扫描阶段,P2P
会扫描周围设备与网络的所支持的所有频段。发现阶段的作用是确保两个设备处于同一个通讯频段。
设备发现完成后,就会进行服务发现。P2P
的服务协议可以基于Airplay/DLNA
中的协议如mDNS/UPnP
进行扩展。搜索的一端主动发送Service Discovery
数据帧,服务端收到搜索请求后发送Response
给对端。Android S
中可以看到两种服务发现协议的封装WIFI P2P NSD。
有关WIFI P2P
的更多细节可以参考标准文档WIFI Direct Spec; 相关的代码实现可以参考AOSP
的源码: