基于DLNA实现iOS,Android投屏:SSDP发现设备

SSDP能够在局域网能简单地发现设备提供的服务。SSDP有两种发现方式:主动通知和搜索响应方式。

寻址

UPnP 技术是架构在 IP 网络之上。因此拥有一个网络中唯一的 IP 地址是 UPnP 设备正常工作的基础。UPnP 设备首先查看网络中是否有 DHCP 服务器,如果有,那么使用 DHCP 分配的 IP 即可;如果没有,则需要使用LLA技术来为自己找适合的IP地址。


另外,在 UPnP 运行过程中,UPnP 设备都需要周期性检测网络中是否有 DHCP 服务器存在,一旦发现有 DHCP 服务器,就必须终止使用 LLA 技术获取的 IP 地址,改用 DHCP 分配的 IP 地址。


发现


SSDP

SSDP:Simple Sever Discovery Protocol,简单服务发现协议,此协议为网络客户提供一种无需任何配置、管理和维护网络设备服务的机制。此协议采用基于通知和发现路由的多播发现方式实现。协议客户端在保留的多播地址:239.255.255.250:1900(IPV4)发现服务,(IPv6 是:FF0x::C)同时每个设备服务也在此地址上上监听服务发现请求。如果服务监听到的发现请求与此服务相匹配,此服务会使用单播方式响应。

常见的协议请求消息有两种类型,第一种是服务通知,设备和服务使用此类通知消息声明自己存在;第二种是查询请求,协议客户端用此请求查询某种类型的设备和服务。

iOS中使用GCDAsyncUdpSocket发送和接受SSDP请求、响应及通知,安卓也需要用类此框架来完成

所以我们发现设备也有两种方法

  1. 主动通知方式:当设备加入到网络中,向网络上所有控制点通知它所提供的服务,通知消息采用多播方式。
  2. 搜索——响应方式:当一个控制点加入到网络中,在网络搜索它感兴趣的所有设备和服务,搜索消息采用多播方式发送,而设备针对搜索的响应则是使用单播方式发送。

SSDP 设备类型及服务类型


   
   
   
   
   
   
   
   
   
设备类型 表示文字
UPnP_RootDevice upnp:rootdevice
UPnP_InternetGatewayDevice1 urn:schemas-upnp-org:device:InternetGatewayDevice:1
UPnP_WANConnectionDevice1 urn:schemas-upnp-org:device:WANConnectionDevice:1
UPnP_WANDevice1 urn:schemas-upnp-org:device:WANConnectionDevice:1
UPnP_WANCommonInterfaceConfig1 urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
UPnP_WANIPConnection1 urn:schemas-upnp-org:device:WANConnectionDevice:1
UPnP_Layer3Forwarding1 urn:schemas-upnp-org:service:WANIPConnection:1
UPnP_WANConnectionDevice1 urn:schemas-upnp-org:service:Layer3Forwarding:1
服务类型 表示文字
UPnP_MediaServer1 urn:schemas-upnp-org:device:MediaServer:1
UPnP_MediaRenderer1 urn:schemas-upnp-org:device:MediaRenderer:1
UPnP_ContentDirectory1 urn:schemas-upnp-org:service:ContentDirectory:1
UPnP_RenderingControl1 urn:schemas-upnp-org:service:RenderingControl:1
UPnP_ConnectionManager1 urn:schemas-upnp-org:service:ConnectionManager:1
UPnP_AVTransport1 urn:schemas-upnp-org:service:AVTransport:1

主动通知方式

当设备添加到网络后,定期向(239.255.255.250:1900)发送SSDP通知消息宣告自己的设备和服务。

宣告消息分为 ssdp:alive(设备可用)ssdp:byebye(设备不可用)

ssdp:alive 消息

1
2
3
4
5
6
7
8
9
10
11
NOTIFY * HTTP/1.1           // 消息头
NT:                         // 在此消息中,NT头必须为服务的服务类型。(如:upnp:rootdevice)
HOST:                       // 设置为协议保留多播地址和端口,必须是:239.255.255.250:1900(IPv4)或FF0x::C(IPv6
NTS:                        // 表示通知消息的子类型,必须为ssdp:alive
LOCATION:                   // 包含根设备描述得URL地址  device 的webservice路径(如:http://127.0.0.1:2351/1.xml) 
CACHE-CONTROL:              // max-age指定通知消息存活时间,如果超过此时间间隔,控制点可以认为设备不存在 (如:max-age=1800)
SERVER:                     // 包含操作系统名,版本,产品名和产品版本信息( 如:Windows NT/5.0, UPnP/1.0)
USN:                        // 表示不同服务的统一服务名,它提供了一种标识出相同类型服务的能力。如:
                            // 根/启动设备 uuid:f7001351-cf4f-4edd-b3df-4b04792d0e8a::upnp:rootdevice
                            // 连接管理器  uuid:f7001351-cf4f-4edd-b3df-4b04792d0e8a::urn:schemas-upnp-org:service:ConnectionManager:1
                            // 内容管理器 uuid:f7001351-cf4f-4edd-b3df-4b04792d0e8a::urn:schemas-upnp-org:service:ContentDirectory:1

ssdp:byebye 消息

当设备即将从网络中退出时,设备需要对每一个未超期的 ssdp:alive 消息多播形式发送ssdp:byebye 消息,其格式如下:

1
2
3
4
NOTIFY * HTTP/1.1       // 消息头
HOST:                   // 设置为协议保留多播地址和端口,必须是:239.255.255.250:1900(IPv4)或FF0x::C(IPv6
NTS:                    // 表示通知消息的子类型,必须为ssdp:byebye
USN:                    // 同上

搜索——响应方式

当控制点,如手机客户端,加入到网络中,可以通过多播搜索消息来寻找网络上感兴趣的设备。我写DLNA模块时候也用主动搜索方式来发现设备。主动搜索可以使用多播方式在整个网络上搜索设备和服务,也可以使用单播方式搜索特定主机上的设备和服务。

多播搜索消息

一般情况我们使用多播搜索消息来搜索所有设备即可。多播搜索消息如下:

1
2
3
4
5
6
7
8
9
10
M-SEARCH * HTTP/1.1             // 请求头 不可改变
MAN: "ssdp:discover"            // 设置协议查询的类型,必须是:ssdp:discover
MX: 5                           // 设置设备响应最长等待时间,设备响应在0和这个值之间随机选择响应延迟的值。这样可以为控制点响应平衡网络负载。
HOST: 239.255.255.250:1900      // 设置为协议保留多播地址和端口,必须是:239.255.255.250:1900(IPv4)或FF0x::C(IPv6
ST: upnp:rootdevice             // 设置服务查询的目标,它必须是下面的类型:
                                // 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组织定义。

如果需要实现投屏,则设备类型 STurn:schemas-upnp-org:service:AVTransport:1

多播搜索响应

多播搜索 M-SEARCH 响应与通知消息很类此,只是将NT字段作为ST字段。响应必须以一下格式发送:

1
2
3
4
5
6
7
8
9
10
HTTP/1.1 200 OK             // * 消息头
LOCATION:                   // * 包含根设备描述得URL地址  device 的webservice路径(如:http://127.0.0.1:2351/1.xml) 
CACHE-CONTROL:              // * max-age指定通知消息存活时间,如果超过此时间间隔,控制点可以认为设备不存在 (如:max-age=1800)
SERVER:                     // 包含操作系统名,版本,产品名和产品版本信息( 如:Windows NT/5.0, UPnP/1.0)
EXT:                        // 为了符合HTTP协议要求,并未使用。
BOOTID.UPNP.ORG:            // 可以不存在,初始值为时间戳,每当设备重启并加入到网络时+1,用于判断设备是否重启。也可以用于区分多宿主设备。
CONFIGID.UPNP.ORG:          // 可以不存在,由两部分组成的非负十六进制整数,由两部分组成,第一部分代表跟设备和其上的嵌入式设备,第二部分代表这些设备上的服务。
USN:                        // * 表示不同服务的统一服务名
ST:                         // * 服务的服务类型
DATE:                       // 响应生成时间

其中主要关注带有 * 的部分即可。这里还有一个大坑,有些设备返回来的字段名称可能包含有小写,如LOCATION和Location,需要做处理。
此外还需根据LOCATION保存设备的IP和端口地址。
响应例子如下:

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Cache-control: max-age=1800
Usn: uuid:88024158-a0e8-2dd5-ffff-ffffc7831a22::urn:schemas-upnp-org:service:AVTransport:1
Location: http://192.168.1.243:46201/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/desc.xml
Server: Linux/3.10.33 UPnP/1.0 Teleal-Cling/1.0
Date: Tue, 01 Mar 2016 08:47:42 GMT+00:00
Ext: 
St: urn:schemas-upnp-org:service:AVTransport:1

描述

控制点发现设备之后仍然对设备知之甚少,仅能知道UPnP类型,UUID和设备描述URL。为了进一步了解设备和服务,需要获取并解析XML描述文件。
描述文件有两种类型:
设备描述文档(DDD)服务描述文档(SDD)

设备描述文档

设备描述文档是对设备的基本信息描述,包括厂商制造商信息、设备信息、设备所包含服务基本信息等。

设备描述采用XML格式,可以通过HTTP GET请求获取。其链接为设备发现消息中的Location。如上述设备的描述文件获取请求为

1
2
GET http://192.168.1.243:46201/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/desc.xml HTTP/1.1
HOST: 192.168.1.243:46201

设备响应如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
HTTP/1.1 200 OK
Content-Length    : 3612
Content-type      : text/xml
Date              : Tue, 01 Mar 2016 10:00:36 GMT+00:00


<root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:qq="http://www.tencent.com">
    <specVersion>
        <major>1major>
        <minor>0minor>
    specVersion>
    <device>
        <deviceType>urn:schemas-upnp-org:device:MediaRenderer:1deviceType>
        <UDN>uuid:88024158-a0e8-2dd5-ffff-ffffc7831a22UDN>
        <friendlyName>客厅的小米盒子friendlyName>
        <qq:X_QPlay_SoftwareCapability>QPlay:1qq:X_QPlay_SoftwareCapability>
        <manufacturer>Xiaomimanufacturer>
        <manufacturerURL>http://www.xiaomi.com/manufacturerURL>
        <modelDescription>Xiaomi MediaRenderermodelDescription>
        <modelName>Xiaomi MediaRenderermodelName>
        <modelNumber>1modelNumber>
        <modelURL>http://www.xiaomi.com/hezimodelURL>
        <serialNumber>11262/180303452serialNumber>
        <presentationURL>device_presentation_page.htmlpresentationURL>
        <UPC>123456789012UPC>
        <dlna:X_DLNADOC xmlns:dlna="urn:schemas-dlna-org:device-1-0">DMR-1.50dlna:X_DLNADOC>
        <dlna:X_DLNACAP xmlns:dlna="urn:schemas-dlna-org:device-1-0">,dlna:X_DLNACAP>
        <iconList>
            <icon>
                <mimetype>image/pngmimetype>
                <width>128width>
                <height>128height>
                <depth>8depth>
                <url>icon/icon128x128.pngurl>
            icon>
        iconList>
        <serviceList>
            <service>
                <serviceType>urn:schemas-upnp-org:service:AVTransport:1serviceType>
                <serviceId>urn:upnp-org:serviceId:AVTransportserviceId>
                <controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/actioncontrolURL>
                <eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/eventeventSubURL>
                <SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/desc.xmlSCPDURL>
            service>
            <service>
                <serviceType>urn:schemas-upnp-org:service:RenderingControl:1serviceType>
                <serviceId>urn:upnp-org:serviceId:RenderingControlserviceId>
                <controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RenderingControl/actioncontrolURL>
                <eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RenderingControl/eventeventSubURL>
                <SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RenderingControl/desc.xmlSCPDURL>
            service>
            <service>
                <serviceType>urn:schemas-upnp-org:service:ConnectionManager:1serviceType>
                <serviceId>urn:upnp-org:serviceId:ConnectionManagerserviceId>
                <controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/ConnectionManager/actioncontrolURL>
                <eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/ConnectionManager/eventeventSubURL>
                <SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/ConnectionManager/desc.xmlSCPDURL>
            service>
            <service>
                <serviceType>urn:mi-com:service:RController:1serviceType>
                <serviceId>urn:upnp-org:serviceId:RControllerserviceId>
                <controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RController/actioncontrolURL>
                <eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RController/eventeventSubURL>
                <SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RController/desc.xmlSCPDURL>
            service>
        serviceList>
        <av:X_RController_DeviceInfo xmlns:av="urn:mi-com:av">
            <av:X_RController_Version>1.0av:X_RController_Version>
            <av:X_RController_ServiceList>
                <av:X_RController_Service>
                    <av:X_RController_ServiceType>controllerav:X_RController_ServiceType>
                    <av:X_RController_ActionList_URL>http://192.168.1.243:6095/av:X_RController_ActionList_URL>
                av:X_RController_Service>
                <av:X_RController_Service>
                    <av:X_RController_ServiceType>dataav:X_RController_ServiceType>
                    <av:X_RController_ActionList_URL>http://api.tv.duokanbox.com/bolt/3party/av:X_RController_ActionList_URL>
                av:X_RController_Service>
            av:X_RController_ServiceList>
        av:X_RController_DeviceInfo>
    device>
root>

其中响应消息体为XML格式的设备描述内容。信息结构比较明确,就不一一介绍了。解析该XML,保存设备的一些基本信息如deviceTypefriendlyNameiconList 等。之后我们关注该设备提供的服务列表,投屏最关注的服务为urn:schemas-upnp-org:service:AVTransport:1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

<root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:qq="http://www.tencent.com">
    <device>
        <serviceList>
            <service>
                <serviceType>urn:schemas-upnp-org:service:AVTransport:1serviceType>
                <serviceId>urn:upnp-org:serviceId:AVTransportserviceId>
                <controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/actioncontrolURL>
                <eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/eventeventSubURL>
                <SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/desc.xmlSCPDURL>
            service>
        serviceList>
    device>
root>

  • serviceId : 必有字段。服务表示符,是服务实例的唯一标识。
  • serviceType : 必有字段。UPnP服务类型。格式定义与deviceType类此。详看文章开头表格。
  • SCPDURL : 必有字段。Service Control Protocol Description URL,获取设备描述文档URL。
  • controlURL : 必有字段。向服务发出控制消息的URL,详见 基于DLNA实现iOS,Android投屏:SOAP控制设备
  • eventSubURL : 必有字段。订阅该服务时间的URL,详见 基于DLNA实现iOS,Android投屏:SOAP控制设备

如只需要实现简单的投屏,则保存urn:schemas-upnp-org:service:AVTransport:1服务的上述信息即可。如需要进一步了解该服务,则需要获取并解析服务描述文档。

坑点1:有些设备 SCPDURLcontrolURLeventSubURL 开头包含/ ,有些设备不包含,拼接URL时需要注意。

服务描述文档

为了实现简单的投屏和控制(播放、暂停、停止、快进)操作并不需要解析服务描述文件。所有动作均为UPnP规范动作,具体动作请求参见基于DLNA实现iOS,Android投屏:SOAP控制设备

服务描述文档是对服务功能的基本说明,包括服务上的动作及参数,还有状态变量和其数据类型、取值范围等。

和设备描述文档一致,服务描述文档也是采用XML语法,并遵守标准UPnP服务schema文件格式要求。获取上述服务SDD语法如下:

1
2
GET http://192.168.1.243:46201/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/desc.xml
HOST: 192.168.1.243:46201

设备响应如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
HTTP/1.1 200 OK
Content-Length    : 3612
Content-type      : text/xml
Date              : Tue, 01 Mar 2016 10:00:36 GMT+00:00


<scpd xmlns="urn:schemas-upnp-org:service-1-0">
    <specVersion>
        <major>1major>
        <minor>0minor>
    specVersion>
    <actionList>
        <action>
            <name>Pausename>
            <argumentList>
                <argument>
                    <name>InstanceIDname>
                    <direction>indirection>
                    <relatedStateVariable>A_ARG_TYPE_InstanceIDrelatedStateVariable>
                argument>
            argumentList>
        action>
        <action>
            <name>Playname>
            <argumentList>
                <argument>
                    <name>InstanceIDname>
                    <direction>indirection>
                    <relatedStateVariable>A_ARG_TYPE_InstanceIDrelatedStateVariable>
                argument>
                <argument>
                    <name>Speedname>
                    <direction>indirection>
                    <relatedStateVariable>TransportPlaySpeedrelatedStateVariable>
                argument>
            argumentList>
        action>
        <action>
            <name>Previousname>
            <argumentList>
                <argument>
                    <name>InstanceIDname>
                    <direction>indirection>
                    <relatedStateVariable>A_ARG_TYPE_InstanceIDrelatedStateVariable>
                argument>
            argumentList>
        action>
        <action>
            <name>SetAVTransportURIname>
            <argumentList>
                <argument>
                    <name>InstanceIDname>
                    <direction>indirection>
                    <relatedStateVariable>A_ARG_TYPE_InstanceIDrelatedStateVariable>
                argument>
                <argument>
                    <name>CurrentURIname>
                    <direction>indirection>
                    <relatedStateVariable>AVTransportURIrelatedStateVariable>
                argument>
                <argument>
                    <name>CurrentURIMetaDataname>
                    <direction>indirection>
                    <relatedStateVariable>AVTransportURIMetaDatarelatedStateVariable>
                argument>
            argumentList>
        action>
        ...
    actionList>
    <serviceStateTable>
        <stateVariable sendEvents="no">
            <name>CurrentTrackURIname>
            <dataType>stringdataType>
        stateVariable>
        <stateVariable sendEvents="no">
            <name>CurrentMediaDurationname>
            <dataType>stringdataType>
        stateVariable>
        <stateVariable sendEvents="no">
            <name>AbsoluteCounterPositionname>
            <dataType>i4dataType>
        stateVariable>
        <stateVariable sendEvents="no">
            <name>RelativeCounterPositionname>
            <dataType>i4dataType>
        stateVariable>
        <stateVariable sendEvents="no">
            <name>A_ARG_TYPE_InstanceIDname>
            <dataType>ui4dataType>
        stateVariable>
        ...
    serviceStateTable>
scpd>

  • actionList 目前服务上所包含的动作列表。
  • actionList 目前服务上所包含的状态变量。

以Pause动作为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

<scpd xmlns="urn:schemas-upnp-org:service-1-0">
    <actionList>
        <action>
            
            <name>Pausename>
            
            <argumentList>
                <argument>
                    
                    <name>InstanceIDname>
                    
                    <direction>indirection>
                    
                    <relatedStateVariable>A_ARG_TYPE_InstanceIDrelatedStateVariable>
                argument>
            argumentList>
        action>
        ...
    actionList>
    <serviceStateTable>
    
        <stateVariable>
            
            <stateVariable sendEvents="no">
            
            <name>A_ARG_TYPE_InstanceIDname>
            
            <dataType>ui4dataType>
        stateVariable>
        ...
    serviceStateTable>
scpd>

为了实现简单的投屏和控制(播放、暂停、停止、快进)操作并不需要解析服务描述文件。所有动作均为UPnP规范动作,具体动作请求参见基于DLNA实现iOS,Android投屏:SOAP控制设备


你可能感兴趣的:(Android开发)