UPnP协议分析

简介

UPNP的全称是 Universal plug-and-play( 通用即插即用),是针对智能加点、无线设备以及各种外观尺寸的个人电脑的普遍P2P(peer-to-peer)网络连接而设计的一种架构。旨在为家庭、企业、公共场所中或连接到互联网的移动自组网(Ad Hoc:移动自组网是一种随建即连的网络,是一群移动节点的集合, 在没有任何预先部署的固定基础设施的情况下,也能够形成网络,节点是随时都在移动,可以随时加入网络或者离开网络,网络中的节点既可以当做通信的主机,又可以代表路由器,为其他主机中继数据包)或未管理网络提供易于使用、灵活其基于标准的连接。

术语表

术语名称 术语解释
DLNA 数字生活网络联盟,由intel牵头、开发和推广的一套在认证标准主持下的多媒体设备中的数字媒体共享的互操作性的准则;
UPnP 通用即插即用,是一套网络协议,该协议的目的是使家庭网络或者公司网络中的各种设备能够相互无线连接,并简化相关网络的实现;
DMS DLNA 定义的一套用于家庭网络环境的设备, 用于向家庭的网络设备提供内容分发的服务;
DMC DLNA 定义的一套用于家庭网络环境的设备, 被用于发现环境中的 DMS 和 DMR, 并让 DMS 和 DMR 建立连接;
DMR DLNA 定义的一套用于家庭网络环境的设备, 用于连接和展示由 DMC 配置内容;
SSDP 简单服务发现协议,UPnP 中使用的设备发现协议;
SOAP 简单对象访问协议,基于XML的消息传递协议,用于通过网络交换服务请求和响应;
CENA 一般事件通知协议,UPnP 中使用的一般事件通知协议;
AV 泛指任何同时携带声音和图片的媒体内容;
AVT AVTransport服务是UPnP服务,它为常见的传输操作提供基于网络的控制;
CP UPnP Control Point;
DIDL 一个 XML 规范文档,用于描述数字内容(文档)的元数据(metadata)的格式;
DIDL-Lite 一个 XML 规范文档,用于在 UPnP 传输中描述数字内容(文档)的元数据(metadata)的格式。 是 DIDL 的子集和 UPnP 自定义的一些属性集合的并集;
UDN 唯一的设备名称,设备的通用唯一标识符;
HTTPMU 基于UDP的HTTP多播
HTTPU 基于UDP的HTTP单播

UPnP结构规范

UPnP基本单元

组成UPnP的基本单元主要有3个模块:

设备(Device):UPnP规范中device是最基本单元。设备代表了一个物理设备或包含多个物理设备的逻辑设备,它是UPnP服务或嵌入设备的载体,不同类型的设备对应一组不同的服务和嵌入设备。

服务(Services):UPnP规范中最小控制单元。服务是设备所能向外提供的功能,定义了设备的功能调用接口以及描述设备状态的变量。服务由一个状态表、一个控制服务器和一个事件服务器构成。

控制点(Control Point):UPnP规范中控制点是UPnP网络中的控制者,能发现和控制网络中的其他UPnP设备。

UPnP协议架构

UPnP是一个多层协议构成的框架体系,每一层都以相邻的下层为基础,同时又是相邻上层的基础。

  • 第一、第二层为TCP/IP和UDP,负责设备的IP地址;
  • 第三层是HTTP、HTTPU、HTTPMU,这一层属于传送协议层,传送的内容都是经过封装后的内容,存放在特定的XML文件中。对应的SSDP、SOAP、GENA指的是保存在XML文件中的数据格式。这一层,已经解决了UPnP设备的IP地址和传送信息问题;
  • 第四层是UPnP设备体系定义,仅仅是一个抽象的、公用的设备模型。任何UPnP设备都必须使用这一层;
  • 第五层是UPnP论坛的各个专业委员会的设备定义层,在这个论坛中,不同电器设备由不同的专业委员会定义,例如:电视委员会只负责定义网络电视设备部分,空调器委员会只负责定义网络空调设备部分,依此类推。所有的不同类型的设备都被定义成一个专门的架构或者模板,供建立设备的时候使用。可以推知,进入这一层,设备已经被指定了明确用途。当然,这些都必须遵守标准化的规范。从目前看,UPnP已经可以支持大部分的设备:从电脑、电脑外设,移动设备和家用消费类电子设备等等,无所不包,随着这个体系的普及,将可能有更多的厂家承认这一标准,最终,可能演化为公认的行业标准;
  • 第六层,也就是应用层,由UPnP设备制造厂商定义的部分。这一层的信息是由设备制造厂商来"填充" 的,这部分一般有设备厂商提供的、对设备控制和操作的底层代码,然后,就是名称序列号呀,厂商信息之类的东西;

UPnP工作流程及协议分析

大致分为6个步骤:

寻址(Addressing) :UPnP协议的基础是TCP/IP,这就决定了了每一个UPnP必须分配一个IP地址。

发现(Discoverity) :这个是第一阶段,控制点搜索设备和服务,同时设备(devices IGD) 广播他能提供的服务通告。

描述(Description) :一旦控制节点发现了他感兴趣的设备或服务,他将向该设备也就是(IGD)请求该设备能够提供的完整的服务描述。

控制(Control) :本阶段允许控制点通过改变设备(devices IDG)的状态来控制设备上提供的一个或多个服务。

事件(Eventing) :本阶段允许控制点与其感兴趣的服务状态保持同步,控制点向事件服务器订阅一个特定的服务,但该服务状态改变时,接收事件通告。

展示(Presentation) :表示阶段允许设备保持一份文档,该文档采用标准的HTML语言进行编写,他可以是该用户的一个用户界面。

本次分析过程中会涉及到3个常用的IP地址:

设备名 IP 说明
UPnP设备 10.53.133.69 (Server)UPnP Device的IP地址,不固定的,为DHCP分配的IP地址
控制点 10.53.132.90 (Client)UPnP Control Point的IP地址,不固定的,为DHCP分配的IP地址
组播地址 239.255.255.250 239.255.255.250是SSDP(简单服务发现协议),这是路由器的UPNP服务使用的协议,是固定的。

寻址(Addressing)

UPnP协议的基础是TCP/IP,这就决定了了每一个UPnP必须分配一个IP地址。当一个UPnP设备或控制点接入网络时,他能通过DHCP从网络上获取一个IP地址。当网络中不存在DHCP服务器时,他能通过auto-ip自动分配一个IP地址;

寻址是UPnP协议的前提(第一步),这部分由IP协议完成;

发现(Discovery)

当UPnP设备或控制点获得IP地址以后,UPnP设备可以通过网络向控制点提供自己的相关信息,CP可以从网络上获取自己感兴趣的设备的信息。这一切都是通过SSDP协议实现的;

在发现阶段,UPnP设备和CP采用SSDP协议宣告和发现设备和服务,SSDP采用了HTTP的一种变体(HTTPMU)以UDP多播的方式来进行广播,并采用另一种HTTP变体(HTTPU)通过UDP单薄来进行应答或宣告;

UPnP设备宣告存在(定时发送)

upnp:rootdevice

yaml 复制代码
Simple Service Discovery Protocol
    NOTIFY * HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): NOTIFY * HTTP/1.1\r\n]
            [NOTIFY * HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: NOTIFY
        Request URI: *
        Request Version: HTTP/1.1
    CACHE-CONTROL: max-age=1800\r\n
    LOCATION: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc\r\n
    NT: upnp:rootdevice\r\n
    HOST: 239.255.255.250:1900\r\n
    NTS: ssdp:alive\r\n
    USN: uuid:598706bc-9126-eb4e-0000-00005cbb7380::upnp:rootdevice\r\n
    SERVER: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    \r\n
    [Full request URI: http://239.255.255.250:1900*]

通过上述的数据包分析可知,server端启动之后,10.53.133.69会向239.255.255.250发送一个NOTIFY命令,宣告UPnP设备的可用性。

  • NOTIFY * HTTP/1.1:请求头,不可改变;

  • CACHE-CONTROL:必选,该字段值是用于标识广播有效的时间。在这个时间的时候,就表示该服务不可用,但只要收到根设备或其嵌入式设备中的任何一个服务的任何广播,那么便认为这个设备的所有服务都可用。时间应大于1800秒;

  • LOCATION:设备描述文件的URL;

  • NT:Notification Type,这里的值为upnp:rootdevice,表明这是一个"根设备",每个设备可以有自己的子设备;

  • HOST:设置为协议保留多播地址和端口,这个必须使用IANA(InternetAssigned Numbers Authority)为SSDP预留的组播地址:239.255.255.250:1900;

  • NTS:Notification Sub Type,表示通知消息的子类型,标准规定必须是ssdp:alive;

  • USN:Unique Service Name,是一个设备实例的标识符,表示不同服务的统一服务名,它提供了一种标识出相同类型服务的能力;

    • 根/启动设备:uuid:598706bc-9126-eb4e-0000-00005cbb7380::upnp:rootdevice
    • 内容管理器:uuid:598706bc-9126-eb4e-0000-00005cbb7380::urn:schemas-upnp-org:service:ContentDirectory:1
    • ???:uuid:598706bc-9126-eb4e-0000-00005cbb7380
    • 媒体渲染管理器:uuid:598706bc-9126-eb4e-0000-00005cbb7380::urn:schemas-upnp-org:device:MediaRenderer:1
    • 渲染控制管理器:uuid:598706bc-9126-eb4e-0000-00005cbb7380::urn:schemas-upnp-org:service:RenderingControl:1
    • AV传输管理器:uuid:598706bc-9126-eb4e-0000-00005cbb7380::urn:schemas-upnp-org:service:AVTransport:1
    • 连接管理器:uuid:598706bc-9126-eb4e-0000-00005cbb7380::urn:schemas-upnp-org:service:ConnectionManager:1
  • SERVER:包含操作系统名,版本,产品名和产品版本信息;

上述的NOTIFY命令中的NT为upnp:rootdevice,其实UPnP设备会向239.255.255.250发送多个NOTIFY命令,将自身具备的能力全部告知组播地址,即自身还有多个子设备需要告知组播地址;

uuid:598706bc-9126-eb4e-0000-00005cbb7380

yaml 复制代码
Simple Service Discovery Protocol
    NOTIFY * HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): NOTIFY * HTTP/1.1\r\n]
            [NOTIFY * HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: NOTIFY
        Request URI: *
        Request Version: HTTP/1.1
    CACHE-CONTROL: max-age=1800\r\n
    LOCATION: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc\r\n
    NT: uuid:598706bc-9126-eb4e-0000-00005cbb7380\r\n
    HOST: 239.255.255.250:1900\r\n
    NTS: ssdp:alive\r\n
    USN: uuid:598706bc-9126-eb4e-0000-00005cbb7380\r\n
    SERVER: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    \r\n
    [Full request URI: http://239.255.255.250:1900*]

urn:schemas-upnp-org:device:MediaRenderer:1

yaml 复制代码
Simple Service Discovery Protocol
    NOTIFY * HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): NOTIFY * HTTP/1.1\r\n]
            [NOTIFY * HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: NOTIFY
        Request URI: *
        Request Version: HTTP/1.1
    CACHE-CONTROL: max-age=1800\r\n
    LOCATION: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc\r\n
    NT: urn:schemas-upnp-org:device:MediaRenderer:1\r\n
    HOST: 239.255.255.250:1900\r\n
    NTS: ssdp:alive\r\n
    USN: uuid:598706bc-9126-eb4e-0000-00005cbb7380::urn:schemas-upnp-org:device:MediaRenderer:1\r\n
    SERVER: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    \r\n
    [Full request URI: http://239.255.255.250:1900*]

这个就是server(车机端)作为DMR,向组播地址发送的通知信息,类型为device;

urn:schemas-upnp-org:service:RenderingControl:1

yaml 复制代码
Simple Service Discovery Protocol
    NOTIFY * HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): NOTIFY * HTTP/1.1\r\n]
            [NOTIFY * HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: NOTIFY
        Request URI: *
        Request Version: HTTP/1.1
    CACHE-CONTROL: max-age=1800\r\n
    LOCATION: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc\r\n
    NT: urn:schemas-upnp-org:service:RenderingControl:1\r\n
    HOST: 239.255.255.250:1900\r\n
    NTS: ssdp:alive\r\n
    USN: uuid:598706bc-9126-eb4e-0000-00005cbb7380::urn:schemas-upnp-org:service:RenderingControl:1\r\n
    SERVER: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    \r\n
    [Full request URI: http://239.255.255.250:1900*]

RenderingControl Service,支持CP发现设备所支持的状态变量表,获取任何状态变量当前值,可以改变任何可修改的状态变量,初始化设置。

用于控制rendering的特性,例如音量、背光等;

urn:schemas-upnp-org:service:AVTransport:1

yaml 复制代码
Simple Service Discovery Protocol
    NOTIFY * HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): NOTIFY * HTTP/1.1\r\n]
            [NOTIFY * HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: NOTIFY
        Request URI: *
        Request Version: HTTP/1.1
    CACHE-CONTROL: max-age=1800\r\n
    LOCATION: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc\r\n
    NT: urn:schemas-upnp-org:service:AVTransport:1\r\n
    HOST: 239.255.255.250:1900\r\n
    NTS: ssdp:alive\r\n
    USN: uuid:598706bc-9126-eb4e-0000-00005cbb7380::urn:schemas-upnp-org:service:AVTransport:1\r\n
    SERVER: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    \r\n
    [Full request URI: http://239.255.255.250:1900*]

AVTransport Service,支持音视频流的传输控制。

用于控制活动和位置,比如播放、暂定、快进、快退等;

urn:schemas-upnp-org:service:ConnectionManager:1

yaml 复制代码
Simple Service Discovery Protocol
    NOTIFY * HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): NOTIFY * HTTP/1.1\r\n]
            [NOTIFY * HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: NOTIFY
        Request URI: *
        Request Version: HTTP/1.1
    CACHE-CONTROL: max-age=1800\r\n
    LOCATION: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc\r\n
    NT: urn:schemas-upnp-org:service:ConnectionManager:1\r\n
    HOST: 239.255.255.250:1900\r\n
    NTS: ssdp:alive\r\n
    USN: uuid:598706bc-9126-eb4e-0000-00005cbb7380::urn:schemas-upnp-org:service:ConnectionManager:1\r\n
    SERVER: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    \r\n
    [Full request URI: http://239.255.255.250:1900*]

ConnectionManager Service,用于列举支持的传输协议和媒体格式,进行CP和DMR之间的能力匹配和连接管理;

综上,UPnP设备所有涉及到的模块就都告知了组播地址(239.255.255.250);

控制点发现可用UPnP设备
yaml 复制代码
Simple Service Discovery Protocol
    M-SEARCH * HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): M-SEARCH * HTTP/1.1\r\n]
            [M-SEARCH * HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: M-SEARCH
        Request URI: *
        Request Version: HTTP/1.1
    HOST: 239.255.255.250:1900\r\n
    MAN: "ssdp:discover"\r\n
    MX: 5\r\n
    ST: urn:schemas-upnp-org:device:MediaRenderer:1\r\n
    \r\n
    [Full request URI: http://239.255.255.250:1900*]
    [HTTP request 7/15]
    [Prev request in frame: 153]
    [Next request in frame: 194]

CP使用UDP多播包向组播地址发送HTTP的M-SEARCH命令,任何网络上服务控制点搜索条件的设备发回一个UDP单播进行应答,该应答中包含了指向其描述文档的 URL 地址。

  • M-SEARCH * HTTP/1.1:请求头,不可改变;

  • HOST:这个必须使用IANA(InternetAssigned Numbers Authority)为SSDP预留的组播地址:239.255.255.250:1900;

  • MAN:必须是"ssdp:discover";

  • MX:1~5之间的一个值,表示最大的等待应答的秒数;

  • ST:Seatch Target,表示服务查询的目标;

    常见类型:

    • ssdp:all:搜索所有设备和服务
    • upnp:rootdevice:仅搜索网络中的根设备
    • uuid:device-UUID:查询UUID标识的设备
    • urn:schemas-upnp-org:device:device-Type:version:查询device-Type字段指定的设备类型,设备类型和版本由UPNP组织定义
    • urn:schemas-upnp-org:service:service-Type:version:查询service-Type字段指定的服务类型,服务类型和版本由UPNP组织定义

扫描(Description)

当控制点发现一个可用设备后,需要获取更加详细的信息,因而会向UPnP设备请求设备描述文档。描述文档是一个XML文档,用来描述一个设备,包括:

  • 制造商信息、版本、其他
  • 可被设备采用的图标的URL地址
  • 嵌入式设备列表
  • 设备提供的服务列表
  • ............

和发现阶段不同,改进段已经进入了CP和DMR请求和响应的阶段,不是直接向组播地址发送消息,控制点采用基于TCP的HTTP来请求描述文档,控制点执行标准的HTTP GET命令。

控制点请求设备描述
sql 复制代码
Hypertext Transfer Protocol
    GET /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): GET /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc HTTP/1.1\r\n]
            [GET /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: GET
        Request URI: /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc
        Request Version: HTTP/1.1
    HOST: 10.53.133.69:42097\r\n
    DATE: Thu, 06 Jan 2022 05:28:12 GMT\r\n
    CONNECTION: close\r\n
    USER-AGENT: Linux/4.14.116, UPnP/1.0, Portable SDK for UPnP devices/1.6.25\r\n
    \r\n
    [Full request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc]
    [HTTP request 1/1]
    [Response in frame: 171]

CP向UPnP设备请求设备描述文档。

HOST代表了请求的IP地址,CONNECTION代表当前CP和DMR的连接状态;

UPnP设备响应控制点请求
javascript 复制代码
Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
        [Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
            [HTTP/1.1 200 OK\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Response Version: HTTP/1.1
        Status Code: 200
        [Status Code Description: OK]
        Response Phrase: OK
    Server: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    Content-type: text/xml\r\n
    Date: Thu, 06 Jan 2022 05:32:21 GMT\r\n
    Content-Length: 2235\r\n
        [Content length: 2235]
    Connection: close\r\n
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.016851000 seconds]
    [Request in frame: 167]
    [Request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/desc]
    File Data: 2235 bytes
eXtensible Markup Language
    <?xml
    <root
        xmlns="urn:schemas-upnp-org:device-1-0">
        <specVersion>
            <major>
                1
                </major>
            <minor>
                0
                </minor>
            </specVersion>
        <device>
            <deviceType>  //设备类型
                urn:schemas-upnp-org:device:MediaRenderer:1
                </deviceType>
            <friendlyName>  //设备别名
                dupzDevice
                </friendlyName>
            <manufacturer>  //制造商
                Cling
                </manufacturer>
            <manufacturerURL>
                Google
                </manufacturerURL>
            <modelDescription>  
                Cling MediaRenderer
                </modelDescription>
            <modelName>  //型号
                Cling MediaRenderer
                </modelName>
            <modelNumber>
                1
                </modelNumber>
            <modelURL>
                http://4thline.org/projects/cling/mediarenderer/
                </modelURL>
            <UDN>
                uuid:598706bc-9126-eb4e-0000-00005cbb7380
                </UDN>
            <dlna:X_DLNADOC
                xmlns:dlna="urn:schemas-dlna-org:device-1-0">
                DMR-1.50
                </dlna:X_DLNADOC>
            <dlna:X_DLNACAP
                xmlns:dlna="urn:schemas-dlna-org:device-1-0">
                av-upload,image-upload,audio-upload
                </dlna:X_DLNACAP>
            <serviceList>  //服务列表
                <service>
                    <serviceType>  //服务类型
                        urn:schemas-upnp-org:service:AVTransport:1
                        </serviceType>
                    <serviceId> //服务ID,通常于serviceType对应
                        urn:upnp-org:serviceId:AVTransport
                        </serviceId>
                    <SCPDURL>  //服务描述的URL
                        /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/desc
                        </SCPDURL>
                    <controlURL>  //用于控制的URL
                        /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action
                        </controlURL>
                    <eventSubURL>  //用于订阅事件的URL
                        /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/event
                        </eventSubURL>
                    </service>
                <service>
                    <serviceType>
                        urn:schemas-upnp-org:service:RenderingControl:1
                        </serviceType>
                    <serviceId>
                        urn:upnp-org:serviceId:RenderingControl
                        </serviceId>
                    <SCPDURL>
                        /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/RenderingControl/desc
                        </SCPDURL>
                    <controlURL>
                        /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/RenderingControl/action
                        </controlURL>
                    <eventSubURL>
                        /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/RenderingControl/event
                        </eventSubURL>
                    </service>
                <service>
                    <serviceType>
                        urn:schemas-upnp-org:service:ConnectionManager:1
                        </serviceType>
                    <serviceId>
                        urn:upnp-org:serviceId:ConnectionManager
                        </serviceId>
                    <SCPDURL>
                        /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/ConnectionManager/desc
                        </SCPDURL>
                    <controlURL>
                        /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/ConnectionManager/action
                        </controlURL>
                    <eventSubURL>
                        /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/ConnectionManager/event
                        </eventSubURL>
                    </service>
                </serviceList>
            </device>
        </root>

UPnP设备响应CP请求,返回了对应的XML设备描述文档。

标签说明:

  • device:DMR设备的描述,包含了friendlyName、manufacturer、manufacturerURL、modelDescription、UDN、dlna:X_DLNACAP以及核心的serviceList;

  • serviceList:包含了DMR支持的所有的services的集合;

  • service:服务详解,包括serviceType、serviceId、SCPDURL、controlURL、eventSubURL5个标签

    • serviceType:service类型,其中DMR支持3种类型的service,AVTransport、RenderingControl以及ConnectionManager
    • serviceId:服务ID,通常与serviceType对应
    • SCPDURL:服务描述URL
    • controlURL:服务控制URL
    • eventSubURL:服务订阅事件URL
控制点请求服务描述 / UPnP设备响应

控制点请求设备描述之后,还需要请求各个service的描述,对应上面的SCPDURL标签中的URL。

我们以AVTransport Service为例;

bash 复制代码
Hypertext Transfer Protocol
    GET /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/desc HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): GET /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/desc HTTP/1.1\r\n]
            [GET /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/desc HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: GET
        Request URI: /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/desc
        Request Version: HTTP/1.1
    HOST: 10.53.133.69:42097\r\n
    DATE: Thu, 06 Jan 2022 05:28:13 GMT\r\n
    CONNECTION: close\r\n
    USER-AGENT: Linux/4.14.116, UPnP/1.0, Portable SDK for UPnP devices/1.6.25\r\n
    \r\n
    [Full request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/desc]
    [HTTP request 1/1]
    [Response in frame: 198]

Request URI表明了请求的内容为AVTransport Service的description;

javascript 复制代码
Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
        [Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
            [HTTP/1.1 200 OK\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Response Version: HTTP/1.1
        Status Code: 200
        [Status Code Description: OK]
        Response Phrase: OK
    Server: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    Content-type: text/xml\r\n
    Date: Thu, 06 Jan 2022 05:32:21 GMT\r\n
    Content-Length: 16419\r\n
        [Content length: 16419]
    Connection: close\r\n
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.119654000 seconds]
    [Request in frame: 185]
    [Request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/desc]
    File Data: 16419 bytes
eXtensible Markup Language
    <?xml
    <scpd
        xmlns="urn:schemas-upnp-org:service-1-0">
        <specVersion>
            <major>
                1
                </major>
            <minor>
                0
                </minor>
            </specVersion>
        <actionList>
            <action>
                <name>
                    Pause
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    </argumentList>
                </action>
            ........................
            <action>
                <name>
                    Stop
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    </argumentList>
                </action>
            <action>
                <name>
                    GetPositionInfo
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            Track
                            </name>
                        <direction>
                            out
                            </direction>
                        <relatedStateVariable>
                            CurrentTrack
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            TrackDuration
                            </name>
                        <direction>
                            out
                            </direction>
                        <relatedStateVariable>
                            CurrentTrackDuration
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            TrackMetaData
                            </name>
                        <direction>
                            out
                            </direction>
                        <relatedStateVariable>
                            CurrentTrackMetaData
                            </relatedStateVariable>
                        </argument>
                    ........................
                    </argumentList>
                </action>
            ........................
            <action>
                <name>
                    SetNextAVTransportURI
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            NextURI
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            AVTransportURI
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            NextURIMetaData
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            AVTransportURIMetaData
                            </relatedStateVariable>
                        </argument>
                    </argumentList>
                </action>
            <action>
                <name>
                    Play
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            Speed
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            TransportPlaySpeed
                            </relatedStateVariable>
                        </argument>
                    </argumentList>
                </action>
            ........................
            <action>
                <name>
                    GetMediaInfo
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            NrTracks
                            </name>
                        <direction>
                            out
                            </direction>
                        <relatedStateVariable>
                            NumberOfTracks
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            MediaDuration
                            </name>
                        <direction>
                            out
                            </direction>
                        <relatedStateVariable>
                            CurrentMediaDuration
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            CurrentURI
                            </name>
                        <direction>
                            out
                            </direction>
                        <relatedStateVariable>
                            AVTransportURI
                            </relatedStateVariable>
                        </argument>
                    ........................
                    </argumentList>
                </action>
            <action>
                <name>
                    Next
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    </argumentList>
                </action>
            ..............................
            <action>
                <name>
                    Previous
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    </argumentList>
                </action>
            ........................
            <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>
            ..............................
            <action>
                <name>
                    GetCurrentTransportActions
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            Actions
                            </name>
                        <direction>
                            out
                            </direction>
                        <relatedStateVariable>
                            CurrentTransportActions
                            </relatedStateVariable>
                        </argument>
                    </argumentList>
                </action>
            <action>
                <name>
                    Seek
                    </name>
                <argumentList>
                    <argument>
                        <name>
                            InstanceID
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_InstanceID
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            Unit
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_SeekMode
                            </relatedStateVariable>
                        </argument>
                    <argument>
                        <name>
                            Target
                            </name>
                        <direction>
                            in
                            </direction>
                        <relatedStateVariable>
                            A_ARG_TYPE_SeekTarget
                            </relatedStateVariable>
                        </argument>
                    </argumentList>
                </action>
            </actionList>
        <serviceStateTable>
            <stateVariable
                sendEvents="no">
                <name>
                    AbsoluteTimePosition
                    </name>
                <dataType>
                    string
                    </dataType>
                </stateVariable>
            <stateVariable
                sendEvents="no">
                <name>
                    CurrentTrackURI
                    </name>
                <dataType>
                    string
                    </dataType>
                </stateVariable>
            <stateVariable
                sendEvents="no">
                <name>
                    CurrentTrackMetaData
                    </name>
                <dataType>
                    string
                    </dataType>
                <defaultValue>
                    NOT_IMPLEMENTED
                    </defaultValue>
                </stateVariable>
            <stateVariable
                sendEvents="no">
                <name>
                    RelativeCounterPosition
                    </name>
                <dataType>
                    i4
                    </dataType>
                <defaultValue>
                    2147483647
                    </defaultValue>
                </stateVariable>
            ........................
            <stateVariable
                sendEvents="yes">
                <name>
                    LastChange
                    </name>
                <dataType>
                    string
                    </dataType>
                </stateVariable>
            </serviceStateTable>
        </scpd>

在该服务描述文档中,包含了service支持的action指令,例如play、stop、setAVTransportURI、next以及previous等常见的一些指令,以及对应事件响应的定义,主要包括状态变量的变化情况;

至此,CP获取到了对应UPnP设备的设备描述文档和所有的服务描述文档。

控制(Control)

在这个阶段中,使用的就是SOAP协议(简单对象访问协议),这SOAP基于TCP/IP协议传输HTTP的POST和M-POST命令,SOAP使用XML来说明采取的活动。

首先执行GetProtocolInfo来获取协议信息,用于将CP和UPnP设备建立通道;

bash 复制代码
Hypertext Transfer Protocol
    POST /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/ConnectionManager/action HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): POST /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/ConnectionManager/action HTTP/1.1\r\n]
            [POST /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/ConnectionManager/action HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: POST
        Request URI: /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/ConnectionManager/action
        Request Version: HTTP/1.1
    HOST: 10.53.133.69:42097\r\n
    CONTENT-LENGTH: 262\r\n
    Accept-Ranges: bytes\r\n
    CONTENT-TYPE: text/xml; charset="utf-8"\r\n
    SOAPACTION: "urn:schemas-upnp-org:service:ConnectionManager:1#GetProtocolInfo"\r\n
    USER-AGENT: Linux/4.14.116, UPnP/1.0, Portable SDK for UPnP devices/1.6.25\r\n
    \r\n
    [Full request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/ConnectionManager/action]
    [HTTP request 1/1]
    [Response in frame: 273]
    File Data: 262 bytes
eXtensible Markup Language
    <s:Envelope
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
        s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
        <s:Body>
            <u:GetProtocolInfo
                xmlns:u="urn:schemas-upnp-org:service:ConnectionManager:1">
                </u:GetProtocolInfo>
            </s:Body>
        </s:Envelope>

通过Request URI可知,该request为action,即控制指令,指令为GetProtocolInfo;

UPnP设备响应请求:

ruby 复制代码
Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
        [Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
            [HTTP/1.1 200 OK\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Response Version: HTTP/1.1
        Status Code: 200
        [Status Code Description: OK]
        Response Phrase: OK
    Ext: \r\n
    Server: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    Content-type: text/xml;charset="utf-8"\r\n
    Date: Thu, 06 Jan 2022 05:32:21 GMT\r\n
    Content-Length: 801\r\n
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.031402000 seconds]
    [Request in frame: 266]
    [Request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/ConnectionManager/action]
    File Data: 801 bytes
eXtensible Markup Language
    <?xml
    <s:Envelope
        s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
        <s:Body>
            <u:GetProtocolInfoResponse
                xmlns:u="urn:schemas-upnp-org:service:ConnectionManager:1">
                <Source>
                    </Source>
                <Sink>
                     [truncated]http-get:*:image/jpeg:*,http-get:*:image/png:*,http-get:*:image/gif:*,http-get:*:image/bmp:*,http-get:*:image/pjpeg:*,http-get:*:image/tiff:*,http-get:*:audio/aac:*,http-get:*:audio/3gpp:*,http-get:*:audio/amr:*,http-get:*:aud
                    </Sink>
                </u:GetProtocolInfoResponse>
            </s:Body>
        </s:Envelope>

UPnP设备响应请求,在XML response中,Sink标签中加载了支持的MimeType,包括image、audio和video。这一部分逻辑在ConnectionManagerService的构造方法执行;

在ConnectionManager::GetProtocolInfo请求完成之后,在数据包的流程中,首先是进行了订阅事件的请求和响应,这一部分逻辑在后续过程中描述;

我们跳过订阅事件逻辑,直接看之后的控制逻辑。

我们以AVTransport Service为例,分析推送媒体内容逻辑。

bash 复制代码
Hypertext Transfer Protocol
    POST /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): POST /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action HTTP/1.1\r\n]
            [POST /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: POST
        Request URI: /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action
        Request Version: HTTP/1.1
    HOST: 10.53.133.69:42097\r\n
    CONTENT-LENGTH: 1140\r\n
    Accept-Ranges: bytes\r\n
    CONTENT-TYPE: text/xml; charset="utf-8"\r\n
    SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"\r\n
    USER-AGENT: Linux/4.14.116, UPnP/1.0, Portable SDK for UPnP devices/1.6.25\r\n
    \r\n
    [Full request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action]
    [HTTP request 1/1]
    [Response in frame: 644]
    File Data: 1140 bytes
eXtensible Markup Language
    <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>
                    http://10.53.132.90:49152/upnp/service/local/622471592/0/0.mp4
                    </CurrentURI>
                <CurrentURIMetaData>
                     [truncated]&lt;DIDL-Lite xmlns=&quot;urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:upnp=&quot;urn:schemas-upnp-org:metadata-1-0/upnp/&quot; xmlns:dlna=&quot;urn:schemas-dln
                    </CurrentURIMetaData>
                </u:SetAVTransportURI>
            </s:Body>
        </s:Envelope>

CP POST推送DMS上的媒体内容,CurrentURI为http://10.53.132.90:49152/upnp/service/local/622471592/0/0.mp4,为视频文件;

UPnP设备响应CP:

yaml 复制代码
Hypertext Transfer Protocol
    HEAD /upnp/service/local/622471592/0/0.mp4 HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): HEAD /upnp/service/local/622471592/0/0.mp4 HTTP/1.1\r\n]
            [HEAD /upnp/service/local/622471592/0/0.mp4 HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: HEAD
        Request URI: /upnp/service/local/622471592/0/0.mp4
        Request Version: HTTP/1.1
    User-Agent: Dalvik/2.1.0 (Linux; U; Android 9; AOSP on crosshatch Build/PQ3A.190801.002)\r\n
    Host: 10.53.132.90:49152\r\n
    Connection: Keep-Alive\r\n
    Accept-Encoding: gzip\r\n
    \r\n
    [Full request URI: http://10.53.132.90:49152/upnp/service/local/622471592/0/0.mp4]
    [HTTP request 1/1]
    [Response in frame: 638]

UPnP设备获取到了CP端推送过来的Request URI,响应CP端,确认已接收到了媒体内容;

yaml 复制代码
Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
        [Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
            [HTTP/1.1 200 OK\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Response Version: HTTP/1.1
        Status Code: 200
        [Status Code Description: OK]
        Response Phrase: OK
    CONTENT-LENGTH: 80798619\r\n
        [Content length: 80798619]
    Accept-Ranges: bytes\r\n
    CONTENT-TYPE: video/mp4\r\n
    DATE: Thu, 06 Jan 2022 05:28:30 GMT\r\n
    LAST-MODIFIED: Thu, 10 Jun 2021 07:04:41 GMT\r\n
    SERVER: Linux/4.14.116, UPnP/1.0, Portable SDK for UPnP devices/1.6.25\r\n
    X-User-Agent: redsonic\r\n
    CONNECTION: close\r\n
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.024056000 seconds]
    [Request in frame: 636]
    [Request URI: http://10.53.132.90:49152/upnp/service/local/622471592/0/0.mp4]

CP接收到UPnP设备的响应,同时也给UPnP响应了HTTP/1.1 200 OK;

ini 复制代码
Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
        [Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
            [HTTP/1.1 200 OK\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Response Version: HTTP/1.1
        Status Code: 200
        [Status Code Description: OK]
        Response Phrase: OK
    Ext: \r\n
    Server: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    Content-type: text/xml;charset="utf-8"\r\n
    Date: Thu, 06 Jan 2022 05:32:38 GMT\r\n
    Content-Length: 292\r\n
        [Content length: 292]
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.063340000 seconds]
    [Request in frame: 629]
    [Request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action]
    File Data: 292 bytes
eXtensible Markup Language
    <?xml
    <s:Envelope
        s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
        <s:Body>
            <u:SetAVTransportURIResponse
                xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"/>
            </s:Body>
        </s:Envelope>

UPnP设备响应CP端的SetAVTransportURI的action;

至此,SetAVTransportURI action流程请求和响应就结束了;

媒体内容推送到UPnP设备之后,等待CP端的指令,正常逻辑下,CP端开始执行play指令。

bash 复制代码
Hypertext Transfer Protocol
    POST /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): POST /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action HTTP/1.1\r\n]
            [POST /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: POST
        Request URI: /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action
        Request Version: HTTP/1.1
    HOST: 10.53.133.69:42097\r\n
    CONTENT-LENGTH: 282\r\n
        [Content length: 282]
    Accept-Ranges: bytes\r\n
    CONTENT-TYPE: text/xml; charset="utf-8"\r\n
    SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Play"\r\n
    USER-AGENT: Linux/4.14.116, UPnP/1.0, Portable SDK for UPnP devices/1.6.25\r\n
    \r\n
    [Full request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action]
    [HTTP request 1/1]
    [Response in frame: 658]
    File Data: 282 bytes
eXtensible Markup Language
    <s:Envelope
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
        s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
        <s:Body>
            <u:Play
                xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
                <InstanceID>
                    0
                    </InstanceID>
                <Speed>
                    1
                    </Speed>
                </u:Play>
            </s:Body>
        </s:Envelope>

CP推送play action。

ini 复制代码
Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
        [Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
            [HTTP/1.1 200 OK\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Response Version: HTTP/1.1
        Status Code: 200
        [Status Code Description: OK]
        Response Phrase: OK
    Ext: \r\n
    Server: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    Content-type: text/xml;charset="utf-8"\r\n
    Date: Thu, 06 Jan 2022 05:32:38 GMT\r\n
    Content-Length: 279\r\n
        [Content length: 279]
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.003809000 seconds]
    [Request in frame: 655]
    [Request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/action]
    File Data: 279 bytes
eXtensible Markup Language
    <?xml
    <s:Envelope
        s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
        <s:Body>
            <u:PlayResponse
                xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"/>
            </s:Body>
        </s:Envelope>

UPnP设备响应CP端推送的play action。

这个就是play action指令的请求和响应,之后的很多action逻辑和上述的play类似,都是request / response 一一对应出现。

control阶段是持续性的,不是瞬时的,在该阶段可能会执行play、stop、next、previous等action。

事件(Eventing)

接着上一阶段(控制阶段)的分析,在扫描阶段结束之后,就已经获取到了服务描述文档,其中包含了该服务支持的所有的指令action以及对应的event;然后始进入控制阶段的时候,首先是执行了CP和DMR的连接交互(ConnectionManager),连接成功之后,其实紧接着就是AVTransport Service和RenderingControl Service中Eventing的订阅逻辑交互。

在服务进行的整个时间段内,只要变量值发生了变化或者是模式的状态发生了改变,就产生了一个事件,系统将修改上述提到的事件列表的内容。随之事件服务器把事件向整个局域网进行广播。另一方面,控制点也可以事件向实践服务器预约事件信息,保证将该控制点感兴趣的时间及时准确地传送过来。

订阅和退订请求使用HTTP/TCP连接到事件URL,该URL包含在服务的描述文档中。事件服务器是一个类HTTP服务器,实现GENA协议的服务器。一个设备可能根据设备提供的服务的组合情况必须运行多于一个的事件服务器。

控制点向UPnP设备订阅事件

我们以AVTransport Service的事件订阅为例,RenderingControl Service与之类同。

CP向UPnP设备请求事件订阅消息:

bash 复制代码
Hypertext Transfer Protocol
    SUBSCRIBE /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/event HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): SUBSCRIBE /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/event HTTP/1.1\r\n]
            [SUBSCRIBE /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/event HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: SUBSCRIBE
        Request URI: /upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/event
        Request Version: HTTP/1.1
    HOST: 10.53.133.69:42097\r\n
    CALLBACK: <http://10.53.132.90:49152/>\r\n
    NT: upnp:event\r\n
    TIMEOUT: Second-300\r\n
    \r\n
    [Full request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/event]

Request Method: SUBSCRIBE:表示该请求为订阅请求;

NT: upnp:event:表示订阅事件;

CALLBACK: http://10.53.132.90:49152/:代表的是回调的URL;

TIMEOUT:订阅事件的超时时长;

UPnP设备响应控制点

与之对应的事件订阅的应答:

yaml 复制代码
Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
        [Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
            [HTTP/1.1 200 OK\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Response Version: HTTP/1.1
        Status Code: 200
        [Status Code Description: OK]
        Response Phrase: OK
    Server: Linux/4.9.148-g695fa5606dab-ab5636409 UPnP/1.0 Cling/2.0\r\n
    Timeout: Second-300\r\n
    Sid: uuid:3587d867-0e45-40b3-b042-a9548e81eaf3\r\n
    Date: Thu, 06 Jan 2022 05:32:21 GMT\r\n
    Content-Length: 0\r\n
        [Content length: 0]
    \r\n
    [HTTP response 1/1]
    [Request URI: http://10.53.133.69:42097/upnp/dev/598706bc-9126-eb4e-0000-00005cbb7380/svc/upnp-org/AVTransport/event]

Sid:表示本订阅的标识符,通常使用UUID;

TIMEOUT:表示本订阅的有效期,这意味着在超时前,必须续订;

这样CP和UPnP设备之间的事件订阅就成功了。

紧接着下来就是UPnP设备在发生状态变化的时候,向局域网中发送事件广播,推送给订阅该事件监听的CP,CP根据回调回来的事件进行CP状态或者是其他的调整和更新;

UPnP设备向控制点推送事件消息

我们以UPnP设备暂停媒体内容播放为例,分析PAUSE的数据包;

xml 复制代码
Hypertext Transfer Protocol
    NOTIFY / HTTP/1.1\r\n
    User-Agent: Android/9 UPnP/1.0 Cling/2.0\r\n
    Nt: upnp:event\r\n
    Nts: upnp:propchange\r\n
    Sid: uuid:8d931940-3d4e-4d48-9bb2-3418c70c5ea2\r\n
    Seq: 2\r\n
    Content-Type: text/xml\r\n
    Host: 10.53.132.90:49152\r\n
    Content-Length: 414\r\n
    \r\n
    [Full request URI: http://10.53.132.90:49152/]
    File Data: 414 bytes
eXtensible Markup Language
    <?xml
        version="1.0"
        encoding="utf-8"
        standalone="yes"
        ?>
    <e:propertyset
        xmlns:e="urn:schemas-upnp-org:event-1-0">
        <e:property>
            <LastChange>
                &lt;Event xmlns="urn:schemas-upnp-org:metadata-1-0/RCS/"&gt;&lt;InstanceID val="0"&gt;&lt;TransportState val="PAUSED_PLAYBACK"/&gt;&lt;CurrentTransportActions val="Stop,Play,Pause,Seek,Next,Previous"/&gt;&lt;/InstanceID&gt;&lt;/Event&gt;
                </LastChange>
            </e:property>
        </e:propertyset>

Seq:是消息的顺序号,从0开始;

每个产生事件的状态变数对应一个e:property标识,LastChange是状态最新信息;

展示(Presentation)

由于设备需要或支持用户交互,在表示阶段一个控制点能下载一个为设备描述用户界面的HTML文档。这是一个能提供一种控制或状态显示的标准HTML文档。如检索描述文档一样,检索表示文档的协议也是基于TCP的HTTP协议。控制点使用描述文档中包含的表示URL来请求表示文档。不是所有设备都拥有表示文档也不是所有控制点能够显示包含复杂HTML对象如框架,嵌入式Java applets等的表示文档。

该模块因为在开发过程中没有使用到,所以不过多描述;

相关推荐
言之。24 分钟前
【面试题】构建高并发、高可用服务架构:技术选型与设计
架构
小马爱打代码4 小时前
Tomcat整体架构分析
java·架构·tomcat
time_silence5 小时前
微服务——不熟与运维
运维·微服务·架构
-指短琴长-5 小时前
Docker之技术架构【八大架构演进之路】
docker·容器·架构
武子康5 小时前
大数据-259 离线数仓 - Griffin架构 修改配置 pom.xml sparkProperties 编译启动
xml·java·大数据·hive·hadoop·架构
2401_857617626 小时前
“无缝购物体验”:跨平台网上购物商城的设计与实现
java·开发语言·前端·安全·架构·php
思忖小下6 小时前
梳理你的思路(从OOP到架构设计)_介绍GoF设计模式
设计模式·架构·eit
秀儿y7 小时前
单机服务和微服务
java·开发语言·微服务·云原生·架构
向上的车轮11 小时前
云边端架构的优势是什么?面临哪些挑战?
架构·云边端