1. DLNA简介
DLNA(Digital Living Network Alliance),即数字家庭网络联盟。
DLNA不是技术,而是一种解决方案,它是多种技术的整合,并致力于构建家庭媒体共享。
DLNA包含多种网络协议,如http、https、upnp等,其中upnp是其重要组成部分。
DLNA主要包含以下四种产品:
DMS,即Digital Media Server(数字媒体服务器)的缩写,其主要作用是作为媒体内容的提供者,为DMP/DMR提供内容播放,DMS可控制提供哪些媒体内容。
DMP,即Digital Media Player(数字媒体播放器)的缩写,可搜索并播放DMS的内容,其作用相当于DMR+DMC。
DMC,即Digital Media Controller(数字媒体控制器)的缩写,可搜索并控制DMR播放DMS提供的内容,即控制DMR与DMS的交互。
DMR,即Digital Media Renderer(数字媒体渲染器)的缩写,可播放DMS提供的内容。
2.Upnp设备架构(Upnp Device Architecture)
Upnp DA将家庭网络中的角色分为三种:控制点、设备和服务。它们之间主要通过HTTP技术实现通信。设备和相关服务的规格信息使用XML方式向其他节点公布。
Upnp DA中各角色的关系如下图:
各个角色的基本概念如下:
- 根设备/设备,即硬件设备,如电脑、电视盒子等。一个设备可提供多个服务。但是家用电器内部一般都包含了多个功能不同的设备,这样由多个设备集合而成的设备集合体,被称为根设备。
- 设备所能提供的功能服务。分为控制服务、事件服务、展示服务。服务是Upnp系统中最小的可控制单元(动作与状态)。
- 控制点。即控制设备,可发现并控制其他设备。如控制其他设备的视频播放、暂停等。
在DLNA投屏的过程中,Android设备充当的角色是控制点
,它初始化并配置好DMS和DMR设备之间的连接,并不直接参与真正的内容传输,内容传输由DMS和DMR完成。
3.DLNA网络传输流程
DLNA的网络传输由设备发现开始。首先,一个新的控制点(Control Point)加入局域网,那么这个Control Point就会开始搜索局域网内可用的设备了。当控制点开始搜索时,它会从UDP端口发送如下格式的搜索请求消息:
M-SEARCH * HTTP/1.1
MX: 1 //最大时间间隔数
ST: upnp:rootdevice //搜索的设备类型
MAN: "ssdp:discover"
User-Agent: iOS 10.2.1 product/version
Connection: close
Host: 239.255.255.250 //多播地址
如果发现可用设备,则会从UDP端口收到如下响应消息:
HTTP/1.1 200 OK
Cache-control: max-age=1800
Date: Thu, 16 Feb 2017 09:09:45 GMT
EXT:
LOCATION: http://10.2.9.152:49152/TxMediaRenderer_desc.xml //URL for UPnP description for device
Server: search target
USN: uuid:3c970e3c0c0d0000_MR::upnp:rootdevice //composite identifier for the advertisment
BOOTID.UPNP.ORG: 1487062102 //number increased each time device sends an initial announce or an update message
CONFIGID.UPNP.ORG: 499354 //number used for caching description information
SEARCHPORT.UPNP.ORG: number identifies port on which device responds to unicast M-SEARCH
ST: upnp:rootdevice //device type
可以看到,在响应消息中,LOCATION
这个字段是一个url:
LOCATION: http://10.2.9.152:49152/TxMediaRenderer_desc.xml //URL for UPnP description for device
这个url指向的是设备服务和信息描述文档
,一般为xml格式。我们可以直接通过浏览器访问该链接查看该设备的相关信息:
<root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:dlna="urn:schemas-dlna-org:device-1-0" configId="499354">
<specVersion>
<major>1</major>
<minor>1</minor>
</specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>
<friendlyName>卧室的创维盒子Q+</friendlyName>
<manufacturer>Plutinosoft LLC</manufacturer>
<manufacturerURL>http://www.plutinosoft.com</manufacturerURL>
<modelDescription>Plutinosoft AV Media Renderer Device</modelDescription>
<modelName>AV Renderer Device</modelName>
<modelURL>http://www.plutinosoft.com/platinum</modelURL>
<UDN>uuid:9c443d47158b-dmr</UDN>
<dlna:X_DLNADOC xmlns:dlna="urn:schemas-dlna-org:device-1-0">DMR-1.50</dlna:X_DLNADOC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
<serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
<SCPDURL>/AVTransport/9c443d47158b-dmr/scpd.xml</SCPDURL>
<controlURL>/AVTransport/9c443d47158b-dmr/control.xml</controlURL>
<eventSubURL>/AVTransport/9c443d47158b-dmr/event.xml</eventSubURL>
</service>
...
</serviceList>
</device>
</root>
在设备信息描述文档中,有一个名为<serviceList>
的节点,该节点是设备可提供服务的描述。有多个<service>
节点,
在<serviceList>
节点中,包含了多个在<service>
节点,每一个<service>
节点代表着一个服务
。
<service>
节点中主要包含着以下节点:
-
<serviceType>
service的类型 -
<serviceId>
service的ID值 -
<SCPDURL>
该节点的url指向服务的动作描述文档(SDD)
,可以直接通过浏览器访问 -
<controlURL>
该节点为服务请求url,在发送动作请求消息时,需要将动作参数以规定格式发送给该url以获取响应消息
可以看出,<SCPDURL>
节点的url并没有标出域名和端口号,因为其域名和端口号与响应消息中LOCATION
字段的域名和端口号一致。如上述代码中的<SCPDURL>
的完整url应为:
http://10.2.9.152:49152/AVTransport/9c443d47158b-dmr/scpd.xml
通过浏览器访问url,可获取如下格式的内容:
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<actionList>
<action>
<name>SetAVTransportURI</name>
<argumentList>
<argument>
<name>InstanceID</name>
<direction>in</direction>
<relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
</argument>
<argument>
<name>CurrentURI</name>
<direction>in</direction>
<relatedStateVariable>AVTransportURI</relatedStateVariable>
</argument>
<argument>
<name>CurrentURIMetaData</name>
<direction>in</direction>
<relatedStateVariable>AVTransportURIMetaData</relatedStateVariable>
</argument>
</argumentList>
</action>
...
<serviceStateTable>
<stateVariable sendEvents="no">
<name>AVTransportURI</name>
<dataType>string</dataType>
</stateVariable>
...
</serviceStateTable>
</scpd>
可以看到,文档中包含一个名为<actionList>
的节点,该节点为服务的动作描述。
<actionList>
中包含了多个<action>
节点,每个节点对应着一个动作
。
每个<action>
节点中都包含着如下节点:
-
<name>
动作名 -
<argumentList>
参数列表。每个<argumentList>
节点中包含了多个<argument>
节点,每个<argument>
节点代表着一个动作参数。一个<argument>
节点包含着如下节点:-
<name>
参数名 -
<direction>
该节点参数取值为in/out
, 当<direction>
的值为in
时,表明这个参数的值是传入值,当为out
时,表明这个参数的值是返回值,则该值会随着订阅事件一起返回给订阅者。 -
<relatedStateVariable>
该节点的值是一个<stateVariable>
节点的映射,映射的内容可在下方<serviceStateTable>
节点中找到,<stateVariable>
节点包含值的类型及取值范围等信息。
-
简单的来说,可以把一个action
当成一个API接口,而action
中的argument
则可表示为API接口的参数,而service
即是多个相关接口的集合。
通过上面的信息,就可以请求服务动作,实现设备控制了。开发者可根据文档中规定的请求参数,发送如下格式的请求消息:
POST /AVTransport/9c443d47158b-dmr/control.xml HTTP/1.1
HOST: 10.2.9.152
Content-Type: text/xml; charset="utf-8"
SOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID>
<CurrentURI>yourAVURI</CurrentURI>
</u:SetAVTransportURI>
</s:Body>
</s:Envelope>
POST
字段后面跟的是<controlURL>
节点的url,HOST
对应的LOCATION
字段的IP。
SOAPAction
的格式:"<serviceType>节点的值#请求的action的名称"
<s:Body>
节点的内容是请求体,请求体的格式为:
<u:请求的action的名称 xmlns:u="<serviceType>节点的值">
<参数1>参数值</参数1>
<参数2>参数值</参数2>
...
</u:请求的action的名称>
如果请求成功,会获取如下格式的响应消息:
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Date: Thu, 16 Feb 2017 09:09:45 GMT
Server: OS/version UPnP/1.1 product/version
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<u:SetAVTransportURIResponse>
<_xmlns:u>"urn:schemas-upnp-org:service:AVTransport:1"</_xmlns:u>
</u:SetAVTransportURIResponse>
</u:SetAVTransportURI>
</s:Body>
</s:Envelope>
这样,整个传输流程就完成了。同一种类型的设备提供的服务大部分相同,但也可能有所差异,因此,在请求设备服务之前,最好先浏览其设备描述文档
,查看设备支持哪些服务。
在介绍完DLNA投屏基本原理之后,在下一篇博客《Android DLNA投屏-基于CyberGarage开发投屏功能》,我将介绍如何使用CyberGarage开发Android投屏功能。
参考博客: