描述
通过SSDP协议获取到的设备信息少之甚少,因此我们还需要进行描述文档的下载和解析,来获得更多的数据。
描述文件有两种类型:设备描述文档(DDD)和服务描述文档(SDD)
设备描述文档(DDD)
设备描述文档是对设备的基本信息描述,包括厂商制造商信息、设备信息、设备所包含服务基本信息等。
设备描述采用XML格式,可以通过HTTP GET请求获取。其链接为设备发现消息中的Location。因为涉及到XML文件的解析,我们需要使用框架GDataXMLNode
XML文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:qq="http://www.tencent.com">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>
<UDN>uuid:88024158-a0e8-2dd5-ffff-ffffc7831a22</UDN>
<friendlyName>客厅的小米盒子</friendlyName>
<qq:X_QPlay_SoftwareCapability>QPlay:1</qq:X_QPlay_SoftwareCapability>
<manufacturer>Xiaomi</manufacturer>
<manufacturerURL>http://www.xiaomi.com/</manufacturerURL>
<modelDescription>Xiaomi MediaRenderer</modelDescription>
<modelName>Xiaomi MediaRenderer</modelName>
<modelNumber>1</modelNumber>
<modelURL>http://www.xiaomi.com/hezi</modelURL>
<serialNumber>11262/180303452</serialNumber>
<presentationURL>device_presentation_page.html</presentationURL>
<UPC>123456789012</UPC>
<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">,</dlna:X_DLNACAP>
<iconList>
<icon>
<mimetype>image/png</mimetype>
<width>128</width>
<height>128</height>
<depth>8</depth>
<url>icon/icon128x128.png</url>
</icon>
</iconList>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
<serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
<controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/action</controlURL>
<eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/event</eventSubURL>
<SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/desc.xml</SCPDURL>
</service>
<service>
<serviceType>urn:schemas-upnp-org:service:RenderingControl:1</serviceType>
<serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId>
<controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RenderingControl/action</controlURL>
<eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RenderingControl/event</eventSubURL>
<SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RenderingControl/desc.xml</SCPDURL>
</service>
<service>
<serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType>
<serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>
<controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/ConnectionManager/action</controlURL>
<eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/ConnectionManager/event</eventSubURL>
<SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/ConnectionManager/desc.xml</SCPDURL>
</service>
<service>
<serviceType>urn:mi-com:service:RController:1</serviceType>
<serviceId>urn:upnp-org:serviceId:RController</serviceId>
<controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RController/action</controlURL>
<eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RController/event</eventSubURL>
<SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RController/desc.xml</SCPDURL>
</service>
</serviceList>
<av:X_RController_DeviceInfo xmlns:av="urn:mi-com:av">
<av:X_RController_Version>1.0</av:X_RController_Version>
<av:X_RController_ServiceList>
<av:X_RController_Service>
<av:X_RController_ServiceType>controller</av: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>data</av: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>
通过<device></device>标签对可以获取到设备deviceType、friendlyName等信息,通过<serviceList></serviceList>标签对可以获取到设备的服务列表urn:schemas-upnp-org:service:AVTransport:1等。
例如投屏服务
<service>
<serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
<serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
<controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/action</controlURL>
<eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/event</eventSubURL>
<SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/desc.xml</SCPDURL>
</service>
serviceId: 必有字段。服务表示符,是服务实例的唯一标识。serviceType: 必有字段。UPnP服务类型。SCPDURL: 必有字段。Service Control Protocol Description URL,获取服务描述文档URL。controlURL: 必有字段。向服务发出控制消息的URL。eventSubURL: 必有字段。订阅该服务事件的URL。 核心代码如下
/// 通过设备描述的URL地址,去获取设备描述文档(DDD)(XML格式),并映射对应model
- (CLUPnPDevice *)getDeviceWithLocation:(NSString *)location withUSN:(NSString *)usn{
dispatch_semaphore_t seamphore = dispatch_semaphore_create(0);
__block CLUPnPDevice *device = nil;
NSURL *URL = [NSURL URLWithString:location];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
request.HTTPMethod = @"GET";
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
[self onError:error];
}else{
if (response != nil && data != nil) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ([httpResponse statusCode] == 200) {
device = [[CLUPnPDevice alloc] init];
device.loaction = URL;
device.uuid = usn;
GDataXMLDocument *xmlDoc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
GDataXMLElement *xmlEle = [xmlDoc rootElement];
NSArray *xmlArray = [xmlEle children];
for (int i = 0; i < [xmlArray count]; i++) {
GDataXMLElement *element = [xmlArray objectAtIndex:i];
if ([[element name] isEqualToString:@"device"]) {
[device setArray:[element children]];
continue;
}
}
}
}
}
dispatch_semaphore_signal(seamphore);
}] resume];
dispatch_semaphore_wait(seamphore, DISPATCH_TIME_FOREVER);
return device;
}
服务描述文档(SDD)
服务描述文档是对服务功能的基本说明,包括服务上的动作及参数,还有状态变量和其数据类型、取值范围等。
获取方式和设备描述文档一样,只需要把SCPDURL替换Location后部分路径即可。
XML文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<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>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>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>
...
</actionList>
<serviceStateTable>
<stateVariable sendEvents="no">
<name>CurrentTrackURI</name>
<dataType>string</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>CurrentMediaDuration</name>
<dataType>string</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>AbsoluteCounterPosition</name>
<dataType>i4</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>RelativeCounterPosition</name>
<dataType>i4</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>A_ARG_TYPE_InstanceID</name>
<dataType>ui4</dataType>
</stateVariable>
...
</serviceStateTable>
</scpd>
actionList目前服务上所包含的动作列表。argumentList目前服务上所包含的状态变量。
实现简单的投屏和控制(播放、暂停、停止、快进)操作并不需要解析服务描述文件。所有动作均为UPnP规范动作。
有些设备SCPDURL、controlURL、eventSubURL开头包含/有些设备不包含,拼接URL时需要注意。