命令メッセージを送信し、レスポンスを取得します。
今回はメディアサーバのContentDirectoryサービスのSearchアクションを実行する命令を送信し、
取得したレスポンスを表示するプログラムを書きます。
実行結果
< u:SearchResponse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
< Result>< DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/">
< container id="Container:Video" parentID="0" restricted="1" searchable="1">
< dc:title>Video< /dc:title>
< upnp:class>object.container< /upnp:class>
< /container>
< container id="Container:Music" parentID="0" restricted="1" searchable="1">
< dc:title>Music< /dc:title>
< upnp:class>object.container< /upnp:class>
< /container>
< container id="Container:Pictures" parentID="0" restricted="1" searchable="1">
< dc:title>Photos< /dc:title>
< upnp:class>object.container< /upnp:class>
< /container>
~~~~~~~~~~~~~省略~~~~~~~~~~~~~~~
< container id="Container:AllMusic" parentID="Container:Music" restricted="1" searchable="1">
< dc:title>All Music< /dc:title>
< upnp:class>object.container.album.musicAlbum< /upnp:class>
< /container>
< container id="Container:VideoAlbum" parentID="Container:Video" restricted="1" searchable="1">
< dc:title>Album< /dc:title>
< upnp:class>object.container< /upnp:class>
< /container>
< /DIDL-Lite>
< /Result>
< NumberReturned>10< /NumberReturned>
< TotalMatches>30< /TotalMatches>
< UpdateID>1112< /UpdateID>
< /u:SearchResponse>
controlhw.c
#include "control.h"
#include "controlhw.h"
#include "DeviceType.h"
extern UpnpDevice_Handle g_handle;
/*
* ContentDirectoryサービスのSearchアクションを呼び出すXMLを生成する
*/
int search(char* soap, char* ContainerID, char* SearchCriteria, char* Filter,char* StartingIndex, char* RequestedCount, char* SortCriteria)
{
char message[2048]="";
sprintf(message, "< u:Search xmlns:u=\"urn:schemas-upnp-org:service:ContentDirectory:1\">"
"< containerid>%s< /containerid>"
"< searchcriteria>%s< /searchcriteria>"
"< filter>%s< /filter>"
"< startingindex>%s< /startingindex>"
"< requestedcount>%s< /requestedcount>"
"< sortcriteria>%s< /sortcriteria>"
"< /u:Search>", ContainerID, SearchCriteria, Filter, StartingIndex, RequestedCount, SortCriteria);
strcpy(soap, message);
return 0;
}
/*
* ddからserviceTypeに指定したserviceData型のポインタを検索し、sdにそのポインタを与える
*/
int getServicePointer(struct serviceData** sd, const struct deviceData* dd, const char* serviceType){
int i=0;
struct serviceData* tmp_sd = dd->SD;
for(i=0; i < dd->service_number; i++){
if(strcmp(tmp_sd->serviceType, serviceType)==0){
*sd = tmp_sd;
return 0;
}
tmp_sd++;
}
return -1;
}
int setDeviceData(struct deviceData* DeviceData, IXML_Document* DescDoc, char* location){
〜〜前回と同じなので省略〜〜
}
int upnp_callback(Upnp_EventType eventtype, void *event, void *cookie)
{
int num = 0;
int ret = 0;
printf("upnp_callback: start\n");
switch(eventtype){
case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
case UPNP_DISCOVERY_SEARCH_RESULT:
{
struct Upnp_Discovery *disc = (struct Upnp_Discovery *)event;
IXML_Document *Descdoc = NULL;
struct deviceData DeviceInfo;
int ret=0, i=0;
//check ErrCode
if(disc->ErrCode != UPNP_E_SUCCESS){
printf("Error: %d\n", disc->ErrCode);
}
//Download Device Description Document
if((ret = UpnpDownloadXmlDoc(disc->Location, &Descdoc)) != UPNP_E_SUCCESS){
//fault
}else{
//getDeviceInformation
setDeviceData(&DeviceInfo, Descdoc, disc->Location);
if(strcmp(DeviceInfo.deviceType, DEVICETYPE_MEDIASERVER)==0){
struct serviceData *sd = NULL;
ret = getServicePointer(&sd,&DeviceInfo,SERVICETYPE_CONTENTDIRECTORY);
if(ret == 0){
IXML_Document *action = NULL;
IXML_Document *Response = NULL;
char soapmessage[2048]="";
search(soapmessage, "0","*","*","0","10","");
action = ixmlParseBuffer(soapmessage);
ret = UpnpSendAction(g_handle,
sd->controlURL,
sd->serviceType,
NULL,
action,
&Response);
DOMString test = ixmlNodetoString(Response);
printf("ErrCode: %d\n", ret);
if(ret==0)printf("%s\n",test);
}
}
if(DeviceInfo.SD)free(DeviceInfo.SD);
}
break;
}
case UPNP_DISCOVERY_SEARCH_TIMEOUT:
{
printf("upnp_callback: search timeout\n");
break;
}
case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
{
struct Upnp_Discovery *disc = (struct Upnp_Discovery*)event;
printf("Device byebye at location: %s\n", disc->Location);
break;
}
case UPNP_CONTROL_ACTION_COMPLETE:
{
struct Upnp_Action_Complete *action = (struct Upnp_Action_Complete *)event;
DOMString result;
printf("Action Complete with return code: %d\n", action->ErrCode);
result = ixmlDocumenttoString(action->ActionResult);
printf("result: %s\n", result);
break;
}
default:
break;
}
printf("upnp_callback: end\n");
return UPNP_E_SUCCESS;
}
DeviceType.h
#ifndef DEVICETYPE_H_
#define DEVICETYPE_H_
#define DEVICETYPE_MEDIASERVER "urn:schemas-upnp-org:device:MediaServer:1"
#define SERVICETYPE_CONTENTDIRECTORY "urn:schemas-upnp-org:service:ContentDirectory:1"
#endif /* DEVICETYPE_H_ */
注意しなければならないのはレスポンスが長くなりすぎるとPortableSDKはエラーを返してしまう点である。
search(soapmessage, "0","*","*","0","10","");
この部分でSearchアクションのxmlを生成しているが、10と書いてあるパラメータはRequestedCountと呼ばれるパラメータで、コンテンツリストを10個だけ返すように要求するという意味になる。
すなわちこのパラメータを大きくしすぎると、大量のデータがレスポンスに含まれてしまい、その結果PortableSDK側でエラーを出してしまう。
対処方法は現在調査中です。