最近开始着手研究DLNA较底层的实现,目标是实现一个部分实现DLNA协议的类库,开发语言用Java,也许会涉及其它开发语言。
DLNA(Digital Living Network Alliance),数字生活网络联盟,这其实是一个组织,具体信息见其官网:http://www.dlna.org/home。国内很少见,但是在国外已经开始有普及的趋势。现在市面上已经有很多DLNA认证的设备和软件,最长见的有Sony BrandView电视、Windows Media Player 12、PS3、一部分手机软件(三星的All share,索尼爱立信的一些软件)等等。一些个人软件也有实现了DLNA部分协议,但是没有通过DLNA认证(认证程序是CTT,有一系列的case需要测试通过)的,例如Android平台上的2player和ps3mediaserver等。
DLNA是一个应用协议栈,它根据功能的不同把设备分成多个角色,如DMR,DMC,DMS等等。DM就是Digital Media的意思,R、C、S分别代表Renderer、Controller和Server。每个角色都有各自明确的分工,不同设备通过通过DLNA进行通信之后,也扮演着不同的角色。具体内容以官方white paper为准。
其实,跑去DLNA上层应用协议栈,它的核心协议实际上是UPNP(Universal Plug and Play),就是通用即插即用。这也是一个应用级的协议。它也是一系列协议的堆栈。
upnp协议堆栈图
我这里所指的应用级协议是应用层的协议,或者商用协议,开放协议一般都是RFC XX之类的东西,听同事说是由IEEE之类的组织负责发表这些协议。
看过UPNP一些基本文档之后,我发现,对于Java实现者而言,实现难度没有那么复杂。操作系统一般都是已经集成UPNP服务,我们只需要调用这个服务就可以。例如在windows下,有一个upnp.dll专门提供这样的服务,如果你的win os的这个服务出现问题,那么对硬件的发现和使用可能会出现一些问题(这点不是很准确,需要考证)。
下面列出我自己学习过程中自提的几个问题和自答:
1.每个UPNP设备可能都有一个描述文件?
我的Galaxy S(2.2系统)下,有一个系统服务就是DMS。当你用手机连接上局域网之后,这个服务可能就启动了,然后可以按照一下格式访问DMS的描述文件:http://手机ip:33003/description.xml。例如我的手机获取到的ip是192.168.1.188,那么当我访问http://192.168.1.188:33003/description.xml时,会看到一下内容:
<root>
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<dlna:X_DLNADOC>DMS-1.50</dlna:X_DLNADOC>
<dlna:X_DLNADOC>M-DMS-1.50</dlna:X_DLNADOC>
<dlna:X_DLNACAP>av-upload,image-upload,audio-upload</dlna:X_DLNACAP>
<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>
<friendlyName>Galaxy S</friendlyName>
<manufacturer>SAMSUNG Electronics</manufacturer>
<manufacturerURL>http://www.sec.co.kr</manufacturerURL>
<modelDescription>
Provides content through UPnP ContentDirectory service
</modelDescription>
<modelName>SAMSUNG Media Server</modelName>
<modelNumber>1.0</modelNumber>
<modelURL>http://www.sec.co.kr</modelURL>
<UDN>uuid:ed86b8f4-4077-31e1-949b-a3214a16e3e1</UDN>
<iconList>
<icon>
<mimetype>image/jpeg</mimetype>
<height>48</height>
<width>48</width>
<depth>24</depth>
<url>/icon/icon.jpeg</url>
</icon>
<icon>
<mimetype>image/jpeg</mimetype>
<height>120</height>
<width>120</width>
<depth>24</depth>
<url>/icon/icon2.jpeg</url>
</icon>
<icon>
<mimetype>image/png</mimetype>
<height>48</height>
<width>48</width>
<depth>24</depth>
<url>/icon/icon.png</url>
</icon>
<icon>
<mimetype>image/png</mimetype>
<height>120</height>
<width>120</width>
<depth>24</depth>
<url>/icon/icon2.png</url>
</icon>
</iconList>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:ContentDirectory:1</serviceType>
<serviceId>urn:upnp-org:serviceId:ContentDirectory</serviceId>
<SCPDURL>cds.xml</SCPDURL>
<controlURL>ContentDirectory_control</controlURL>
<eventSubURL>ContentDirectory_event</eventSubURL>
</service>
<service>
<serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType>
<serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>
<SCPDURL>cms.xml</SCPDURL>
<controlURL>ConnectionManager_control</controlURL>
<eventSubURL>ConnectionManager_event</eventSubURL>
</service>
</serviceList>
</device>
</root>
这个配置文件基本描述了当前这个DLNA软件支持什么的协议版本(specVersion)和设备信息(device)。device节点描述了更多信息,什么deviceType啊、friendlyName啊等。关键看几个点,dlna:X_DLNACAP,它竟然是av-upload,image-upload,audio-upload,它意思就是说它支持视频、图片、音频上传。serviceList节点的值表明它目前支持2个服务,CMS(Content Manager Service,内容管理服务)和CDS(Content Directory Service,内容目录服务)。
SCPDURL是这两个服务的描述文件。可以分别通过/cms.xml和/cds.xml来访问。
2.什么是cds,如何实现?
CDS就像是一个文件服务器,它把你本地的文件可以通过HTTP的方式发布到网络上去。
我所知道的可用的组件有:在嵌入式设备上,可以用开源的(好像是GPL协议)的NanoHTTPD来做一个HTTP服务器;在桌面应用上,选择就太多了,什么netty、httpd之类应该都可以用。ps3mediaserver用的就是netty实现该功能。
3.什么是cms,如何实现?
//追查ing
4.什么是组播?Java中如何实现?
组播就是Multicast,具体概念见wiki。java就有组播的实现类:java.net.MulticastSocket.
5.UPNP如何实现?
我目前看到的比较明显的方式是组播(upnp只应用与局域网)。upnp协议定义了一些基本组件,例如device、service、av transmission等,基于upnp的其它协议都是扩展这些组件就可以了。DLNA其实就是扩展了upnp device、service等之后的应用协议。upnp有默认的组播地址,我看psm的实现写的是239.255.255.250,不知道是不是这个。另外upnp默认端口好像是1900,如果建立一个组播socket,然后读取这个端口的数据,就会发现有很多数据,什么M-SEARCH、NOTIFY之类的,并会发现一些挺有意思的事情(前提是你所在的局域网够大)。
6.netty和NanoHTTPD实现的区别?
a>对比一下获取还n文件的URL就知道了:
netty:http://192.168.1.100:5001/description/fetch
NanoHTTPD: http://192.168.1.100:5001/description.xml
7.哪里去找upnp和dlna的资料?
不用问,对于这种标准的东西,直接上官方查spec,如果涉及RFC的部分,可以去这个网站:www.faqs.org。
8.描述DLNA的一个场景的工作过程。
场景:用户将手机A中的媒体内容播放到电视B上。(DMC+DMR)
在这个场景中,前提是,A和B必须连接到同一个局域网中。假定电视B先接入局域网,手机A后接入局域网,然后再进行播放操作,那么该场景大概是这样的:
B接入局域网以后,B需要建立多播socket,然后加入DLNA这个多播组(譬如说是239.255.255.250,数据端口是1900),同时不断监听1900端口发送过来的报文数据。
如果报文以M-SEARCH开头,那么就说明,局域网内有设备正在进行查找。B现在扮演DMR的角色,那么它就应该处理所有Renderer的M-SEARCH报文,接收到相应报文之后,需要给查询方发送一个回复报文,回复报文中包含了当前DMR的基本信息。
A现在加入局域网,它也建立多播socket,也加入到多播组中,然后根据A上用户选择进行DMR搜索之后,A发出M-SEARCH报文,局域网多播机制会将该报文发送给DLNA多播组中所有监听者,于是B也收到了该报文。B开始解析报文,它知道对方搜索的正式DMR,于是它立刻给多播组内发一条回复报文,告诉搜索方自己就是DMR。于是A又收到了该回复报文,A解析了该回复,得到了DMR的基本信息,它接着把这些基本信息装载到UI上,于是用户看到了该DMR的信息。
如果用户已经选择了某个媒体资源,那么就可以直接进行具体的流媒体push操作了。
关于push操作,其实是这样的。无论对于DMR+DMC的push场景,或者DMS+DMR的pull场景,媒体提供方其实也要提供一个服务就是流媒体服务器(就是NanoHTTPD或者netty等去实现的)。所以在A和B这个场景中,A是DMC,所以它提供了一个媒体服务器。当报文发出并得到回复之后,事实上这一步只是确定了DMR有谁,接着用户选择了某个DMR,这就确定了要与之通信的DMR是谁,然后,A和B其实就已经建立了一种端对端的关系,A会先发起一个HTTP请求,告诉B,我要播放什么格式的内容,它的URL地址是什么,然后B接收到请求之后,解析到要播放的地址文件格式及其地址等信息之后,先会判断它支持不支持这个媒体内容,如果不知吃,那么就需要返回一个400或者什么错误码给A(错误码,DLNA spec里都有详细介绍),如果它支持,那么就开始建立与该流媒体的连接,通过HTTP去拿数据,然后根据媒体类型再在本地进行解码,然后进行播放。
在刚才的过程中,如果媒体文件是视频或者音频,那就更复杂一些,一是B要进行实时解码播放,二是还需要把播放的进度不断返回给A,因为对于A来讲,它需要把播放进度条展示给用户去看。同时A一般还会提供一些更具体的视频、音频操作,例如暂停、恢复、跳转等。这些都是协议里面规定的,具体如何去通信,还要仔细的阅读spec。
DMR搜索报文 写道
M-SEARCH * HTTP/1.1
USER-AGENT: SEC_HHP_Galaxy S/1.0
ST: urn:schemas-upnp-org:device:MediaRenderer:1
MX: 3
MAN: "ssdp:discover"
HOST: 239.255.255.250:1900
目前还没找到回复报文,因为回复报文都是需要截取DMR的数据包,可是我手头还没有DMR设备,唯一能用的WMP12,只能在win7下用,只好等以后有空把win7的开发环境配置好,才能抓取。
补充:为什么默认组播地址和端口用的是239.255.255.250:1900,是因为这是SSDP协议所用的地址。
引用
SSDP is a text-based protocol based on HTTPU. It uses the User Datagram Protocol (UDP) as underlying transport protocol. Services are announced by the hosting system with multicast addressing to a specifically designated IP multicast address at port number 1900. In IPv4, the multicast address is 239.255.255.250[1] and SSDP over IPv6 uses the address set FF0X::C for all scope ranges indicated by X.[2]
9.基于DLNA的应用有什么特点吗?
除了即插即用之外,我暂时还注意到另外一个特点。
我们知道,对于web应用来说,服务器端大多是被动的,即便某些服务可能会主动推送数据,但是那也要提前注册了才行。
而UPNP应用中,由于基于组播,DLNA media server一旦建立,就需要自己每隔一个时间段往组播组中发送心跳数据报,以保证同组中关注DMS的设备更新它的DMS列表。(这点可能不是很对,不过目前看起来确实很想这样,以后花时间再具体考证)。
//