基于DLNA的移动端网络视频投屏技术初探

我们有一个QQ群 341872661,以及我的个人wx: borishaka,可以拉进微信群讨论相关DLNA难点技术。

个人开源的基本DLNA控制库:DLNAKit

本文从DLNA核心协议层进行原理解释,因此具有平台通用性。(适用iOS/Android/Web等)

DLNADigital Living Network Alliance的缩写。从英文全称可以看出,这个东西不是一种协议,而是一个实现数字生活网络解决方案做了一个标准的联盟。目前主流的智能网络设备通信解决方案主要是DLNA Airplay和新出的Miracast,最早索尼、微软、三星、苹果等大牛都加入了DLNA。到后来苹果退出自立门户做了Airplay,所以我想Airplay多少是基于DLNA标准的吧。

DLNA不是一种协议,但包括了实现相关标准所需要的一系列协议栈。如HTTP SSDP XML SOAP UPnP UDP TCP/IP等等。DLNA不仅可用于WIFI,还支持Bluetooth等多种通信协议。这里只讨论在局域网LAN下使用WIFI连接的智能设备与客户端之间的协议编程。

首先简单介绍一下客户端和智能设备在DLNA标准定义下的角色。当手机端仅实现将网络视频投射至电视时,手机端扮演的是控制点Control Point,而电视或者机顶盒则扮演的是渲染设备播放设备

要实现从移动端将网络视频投放至智能电视或机顶盒,首先要保证这些设备在同一个局域网的相同网段下,即共享同一个网关Internet Gateway。这样所有设备都能够拥有独立的IP,从而具备相互通信的基础了。

试想这样一个场景:所有设备都比作人,整个局域网就好比是一个政府大院。当有人要进入政府大院时,警卫会先让这个新人登记,把他的一些基本信息,如姓名,手机号等记录下来。同时,这个新人可能想知道政府大院里都有什么人,每个人的姓名和联系方式是什么。在这里假设警卫和这个新人都拥有足够的权限告知和获取,那么警卫可能会打印一份名单交给这个新人。名单上列有今天已经进入政府大院的人的基本信息;当有人从大院里出来,这个人会告诉警卫自己的姓名,然后警卫会把他的条目从名单里划掉。

发现设备

这个简单的场景就是支持DLNA的智能设备加入组网并进行搜索其他设备时的基本流程了。这个过程称为设备发现。当一个新的CP (Control Point)加入一个局域网时,为了获取当前网段里都有哪些智能设备,CP需要遵循SSDP向默认多播IP和端口发送获取信息的请求。对于CP,可以使用DLNA定义的搜索-响应方式来发现设备,这会用到http的扩展协议M-SEARCH

搜索请求消息的格式如下:

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端口发送的请求,如果请求成功,则会收到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

上面的响应消息即DLNA的控制点设备在做发现时得到的某个设备返回的消息。由于这个过程的消息通信是基于UDP这种不可靠,无连接的协议,所以建议在设备搜索过程多做几次发现请求,以免丢包带来的遗漏。

现在控制点即你的手机端可以获得的信息是:有一台设备,它的IP和端口号、设备描述文档在什么位置(LOCATION)、UUID是什么(USN)。但它能提供什么服务,是否允许手机端将网络视频投放至它的渲染设备,支不支持移动端进行播放控制等等,我们都还不清楚。因此这一步仅仅是发现了设备,下一步我们需要获取更详细的设备信息,即请求该设备的设备描述文档 (DDD, Device Description Document)

请求DDD

DDD以及后面要说到的服务描述文档 (SDD, Service Description Document)都是以XML格式返回给请求端的,这一步的通信则是基于TCP HTTP进行可靠传输的。我们向Location字段的内容即:

http://10.2.9.152:49152/TxMediaRenderer_desc.xml

发出一个GET请求,成功后会返回如下响应消息:


  
    1
    1
  
  
    urn:schemas-upnp-org:device:MediaRenderer:1
    卧室的创维盒子Q+
    Plutinosoft LLC
    http://www.plutinosoft.com
    Plutinosoft AV Media Renderer Device
    AV Renderer Device
    http://www.plutinosoft.com/platinum
    uuid:9c443d47158b-dmr
    DMR-1.50
    
      
        urn:schemas-upnp-org:service:AVTransport:1
        urn:upnp-org:serviceId:AVTransport
        /AVTransport/9c443d47158b-dmr/scpd.xml
        /AVTransport/9c443d47158b-dmr/control.xml
        /AVTransport/9c443d47158b-dmr/event.xml
      
      ...
    
  

这个格式很清晰地描述了设备的详细信息,我们可以知道,此设备的自定义名字是卧室的创维盒子Q+、设备类型是媒体渲染播放器、制造商相关信息、UUID、以及它提供的服务列表;每个服务都有serviceType, serviceId, SCPDURL, controlURLeventSubURL。这几个字段都是很关键的信息,比如在以上设备服务列表的第一个服务中,可以看到serviceType字段内容是urn:schemas-upnp-org:service:AVTransport:1,这表示这个服务提供的是音视频传输服务,版本号是1。

请求SDD

那么我们如何使用这个服务呢,使用这个服务需要控制端提供什么参数呢。想要得到这些信息,则需要去参考该服务的SDD了。注意到SCPDURL这个字段的内容就是请求SDD的路径地址,我们将其与之前在SSDP发现设备阶段获取到的响应消息中的Location字段内容中设备的IP和端口号拿过来,拼接成完整URL字符串:

http://10.2.9.152:49152/AVTransport/9c443d47158b-dmr/scpd.xml

做一个GET请求,则可以获取该服务的描述文档SDD了:

This XML file does not appear to have any style information associated with it. The document tree is shown below.

  
    1
    0
  
  
    
      SetAVTransportURI
      
        
          InstanceID
          in
          A_ARG_TYPE_InstanceID
        
        
          CurrentURI
          in
          AVTransportURI
        
        
          CurrentURIMetaData
          in
          AVTransportURIMetaData
        
      
    
    ...
  
    
      AVTransportURI
      string
    
    ...
  

这里做了省略,只展示了该服务的部分内容。可以看出该服务提供了一个actionList动作列表,一个服务会包含一个或多个功能请求动作。如actionList下这个SetAVTransportURI,顾名思义,这个请求的功能是将一个音视频资源的URI发送给渲染端。一个动作(Action)就好比一个API请求,你还需要传递一些要求的参数,这时就会用到该Action后面argumentList里规定的一些Argument。比如根据第一个参数CurrentURI,表示的就是你想发送的URI;同时in表示的是这是一个传入参数,如果为out则表示该Action会返回给你这个参数的值。

服务动作请求

那么我们现在有了发送网络视频URI所需要的全部信息,这时就可以按照DLNA规定的方式发给设备请求服务了。DLNA规定请求Action消息格式如下:

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"

  
  
    
      0
      yourAVURI
    
  

IPSSDP发现设备得到的IP
内容是SDDserviceTypeAction名字拼接而成;
也是由serviceTypeAction名字组合而成;

0
yourAVURI

是由actionList中的参数组合而成。

如果消息发送没问题,设备会发送请求成功的响应消息:

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

  
    
      
        
          <_xmlns:u>"urn:schemas-upnp-org:service:AVTransport:1"
        
      
    
  

响应信息一目了然,不必多说。

至此,我们就可以初步实现从手机端入网、发现机顶盒设备、获取设备详细信息、获取设备服务、传输URI给播放设备的一个简单通路。

使用DLNA进行智能电视或普通电视连接智能机顶盒设备投射的开发过程颇为曲折,有大量的坑点,都是泪,等有时间再写一篇文章总结一下。

你可能感兴趣的:(基于DLNA的移动端网络视频投屏技术初探)