首页 UPNP编程

UPNP编程

举报
开通vip

UPNP编程UPNP编程 分类: UPNP 2012-11-22 15:17669人阅读评论(3)收藏 HYPERLINK "http://blog.csdn.net/crazyman2010/article/details/8212513#report"举报 零、SDK的安装 upnp的概念就不理会了,网上很多,这里偏向于具体编程。 SDK使用upnp1.6.17版本,这是一个linux下的开源版本,目前仍然在维护,下载地址: http://pupnp.sourceforge.net/ 安装SDK相对比较简单,参考阅读S...

UPNP编程
UPNP编程 分类: UPNP 2012-11-22 15:17669人阅读评论(3)收藏 HYPERLINK "http://blog.csdn.net/crazyman2010/article/details/8212513#report"举报 零、SDK的安装 upnp的概念就不理会了,网上很多,这里偏向于具体编程。 SDK使用upnp1.6.17版本,这是一个linux下的开源版本,目前仍然在维护,下载地址: http://pupnp.sourceforge.net/ 安装SDK相对比较简单,参考阅读SDK目录下的README 我使用命令如下: tar jxvf libupnp-1.6.17.tar.bz2 cd libupnp-1.6.17/ ./configure --prefix=/home/momo/DLNA --enable-sample make make install 这样在/home/momo/DLNA目录下就可以找到include和lib两个目录了,里面就是头文件和库,在upnp/sample目录下是示例程序。 交叉编译目前没有去理会,先学习下X86下面UPNP的编程。 另外可以在网上下载intel upnp tools来对自己编写的设备进行测试。 一、名词解释和XML文档 UDN:uuid,设备唯一名 SID:订阅标识,唯一 ServiceId:服务ID号,唯一 URI:Universal Resource Identifier UPNP编程分为设备端和客户端(控制点),设备端采用XML来提供自己的信息,主要包括自身描述XML文档和动作状态文档。 自身描述XML文档格式: 见文档。 动作状态XML文档格式: 见文档。 这些XML的编写,除了自己按照格式填之外,还可以使用Intel upnp tools中的DeviceBuild和ServiceAuthor生成。我测试DeviceBuild好像有点问题,无法保存。 其中自身描述XML文档有个节点presentationURL,这个主要用来表现设备的界面,是一个网址,网页是自己编写的。 二、XML的操作 编写设备或控制点都需要操作XML。 下面是一个普通的XML: urn:schemas-upnp-org:service:service_0001:1 urn:upnp-org:serviceId:0001 /upnp/control/service_0001 /upnp/event/service_0001 /service_0001SCPD.xml 节点是XML中一个很重要的概念,对于理解后面操作XML有帮助,下面这些都是节点: xxxxxx urn:schemas-upnp-org:service:service_0001:1 urn:schemas-upnp-org:service:service_0001:1 其中有<>的节点是Element节点,节点分类比较多,详情自己百度下。 1.API int UpnpDownloadXmlDoc(const char *url, IXML_Document **xmlDoc) 下载url指向的XML文档,保存在*xmlDoc中。 IXML_NodeList *ixmlDocument_getElementsByTagName( IXML_Document *doc, const DOMString tagName) 从一个XML文档中读取所有标签名是tagName的节点,并把它们编制成一个单向链表。 IXML_Node *ixmlNodeList_item( IXML_NodeList *nList, unsigned long index) 从链表中取出其中一个节点。 ixmlNode getChildNodes (IXML Node* nodeptr ) 取出nodeptr的子节点,组成一个节点链表,调用ixmlNodeList_item(child_node_list,1),可以得到: IXML_Node *ixmlNode_getFirstChild(IXML_Node *nodeptr) 取出一个节点的第一个子节点。 const DOMString ixmlNode_getNodeValue(IXML_Node *nodeptr) 取出一个节点的值。 void ixmlNodeList_free(IXML_NodeList *nList) 释放节点列表空间。 void ixmlDocument_free(IXML_Document *doc) 释放DOC空间 2.举例 对于之前那个XML,如何读取其中的ServiceId值呢?(假设XML为”./web/device_desc.xml”) IXML_Document *doc_desc; UpnpDownloadXmlDoc(”./web/device_desc.xml”,&doc_desc); IXML_NodeList *node_list=ixmlDocument_getElementsByTagName(doc_desc,”ServiceId”); IXML_Node *node= ixmlNodeList_item(node_list,0); node= ixmlNode_getFirstChild(node); char *service_id=strdup(ixmlNode_getNodeValue(node)); ixmlNodeList_free (node_list); ixmlDocument_free(doc_desc); …. free(service_id); 三、upnp设备的编写 一、设备的初始化 1.初始化SDK UpnpInit( ip_address, port ); 2.注册虚拟目录: char* web_dir_path="./web"; UpnpSetWebServerRootDir( web_dir_path ); 3.注册根设备 UpnpRegisterRootDevice( desc_doc_path, MyDeviceCallbackEventHandler, &device_handle, &device_handle ); 4.初始化服务和状态(这部分自己完成,非SDK里面的 关于工期滞后的函关于工程严重滞后的函关于工程进度滞后的回复函关于征求同志党风廉政意见的函关于征求廉洁自律情况的复函 数): SetupServiceAndVarible(desc_doc_path); 5.广播设备上线消息: unsigned int default_advr_expire=100; UpnpSendAdvertisement( device_handle, default_advr_expire); 6.阻塞主线程,等待设备退出信号,如果退出,调用: UpnpFinish(); 二、处理设备请求 设备广播之后就可以处理其他设备发送过来的请求了,请求是异步和并发的,所以要加锁。一个请求到来就会调用UpnpRegisterRootDevice中注册的回调函数(上面的MyDeviceCallbackEventHandler),定义如下: int MyDeviceCallbackEventHandler(Upnp_EventType EventType, void *Event, void *Cookie) EventType表示请求的类型,作为一个设备而言,它只需要处理三种请求: UPNP_EVENT_SUBSCRIPTION_REQUEST:订阅请求 UPNP_CONTROL_GET_VAR_REQUEST: 变量请求 UPNP_CONTROL_ACTION_REQUEST: 动作请求 Event保存请求信息的结构体 设备处理订阅请求: 1.将Event转换为订阅请求类型: (struct Upnp_Subscription_Request *)Event 2.从请求结构体中获取udn,service_id,sid const char *l_serviceId = NULL; const char *l_udn = NULL; const char *l_sid = NULL; l_serviceId = sr_event->ServiceId; l_udn = sr_event->UDN; l_sid = sr_event->Sid; 3.跟据service_id和udn查找设备提供的服务列表,如果有匹配项,那么接受订阅: UpnpAcceptSubscription(device_handle,l_udn,l_serviceId, (const char**)g_dev_service_list[i].VariableName, (const char**)g_dev_service_list[i].VariableStrVal, g_dev_service_list[i].VariableCount,l_sid); 处理动作请求: 1.将Event转换为动作请求类型: (struct Upnp_Action_Request *)Event 2.从请求结构体中获取udn,service_id,action_name: const char *dev_udn = NULL; const char *service_id = NULL; const char *action_name = NULL; dev_udn = ca_event->DevUDN; service_id = ca_event->ServiceID; action_name = ca_event->ActionName; 3.跟据udn、service_id和action_name查找对应的action函数,如果找到了就调用这个action函数,action函数定义如下: typedef int (*upnp_action) (IXML_Document *request, IXML_Document **out, char **errorString); IXML_Document action_result; char *error_string; ret_code=g_dev_service_list[i].actions[j]( ca_event->ActionResult, &ca_event->ActionResult, &error_string, (void*)&g_dev_service_list[i] ); if(ret_code == UPNP_E_SUCCESS) ca_event->ErrCode=UPNP_E_SUCCESS; 如果没有发现匹配的action,那么返回401的错误代码: ca_event->ActionResult=NULL; strcpy(ca_event->ErrStr, "Invalid Action" ); ca_event->ErrCode=401; 在action函数中,通常可能改变了服务状态变量的值,这时候要调用通知函数UpnpNotify: UpnpNotify( device_handle, pservice->UDN, pservice->ServiceId, ( const char ** )&pservice->VariableName[VAR_INDEX_POWER], ( const char ** )&pservice->VariableStrVal[VAR_INDEX_POWER], 1); action函数中处理完和设备的相关数据后,调用UpnpAddToActionResponse设置返回结果: if( UpnpAddToActionResponse( out,pservice->ActionNames[ACT_INDEX_POWERON], pservice->ServiceType, pservice->VariableName[VAR_INDEX_POWER], pservice->VariableStrVal[VAR_INDEX_POWER]) != UPNP_E_SUCCESS ) { *out= NULL; *errorString = "Internal Error"; return UPNP_E_INTERNAL_ERROR; } 处理变量请求: 1. 将Event转换为变量请求类型: (struct Upnp_State_Var_Request *)Event 2.获取udn,service_id和var_name: dev_udn=cgv_event->DevUDN; service_id=cgv_event->ServiceID; var_name=cgv_event->StateVarName; 3.在服务列表中查找匹配项,如果找到就将变量值设置到Event中: for(i=0;iCurrentVal = ixmlCloneDOMString( g_dev_service_list[i].VariableStrVal[j]); break; } } break; } } 4.设置好Event中的返回值: if(i==DEV_SERVICE_COUNT && j==g_dev_service_list[i].VariableCount){ cgv_event->ErrCode=404; strcpy(cgv_event->ErrStr, "Invalid Variable" ); }else{ cgv_event->ErrCode=UPNP_E_SUCCESS; } 四、编写UPNP控制点 一、控制点的流程: 1.初始化SDK库: int UpnpInit(const char *HostIP, unsigned short DestPort) 2.注册控制点: int UpnpRegisterClient( Upnp_FunPtr Fun, const void *Cookie, UpnpClient_Handle *Hnd) 3.发出搜索: int UpnpSearchAsync( UpnpClient_Handle Hnd, int Mx, const char *Target_const, const void *Cookie_const ) 4.处理各种事件 5.退出: UpnpUnRegisterClient(g_ctrl_handle); UpnpFinish(); 二、控制点处理的事件: 1. UPNP_DISCOVERY_SEARCH_RESULT和UPNP_DISCOVERY_ADVERTISEMENT_ALIVE 在调用UpnpSearchAsync发出搜索请求后,设备端收到请求会返回UPNP_DISCOVERY_SEARCH_RESULT,如果超时会得到UPNP_DISCOVERY_SEARCH_TIMEOUT。 设备端上线后会广播一次,这时控制点会收到UPNP_DISCOVERY_ADVERTISEMENT_ALIVE的消息。 收到这两个事件时,需要跟据事件中的URL将设备的XML文档下载过来,然后将设备添加到控制点维护的设备链表中,以供后期使用。 location = event->Location; err_code = UpnpDownloadXmlDoc(location, &desc_doc); if (err_code != UPNP_E_SUCCESS) { dprinterr("Error obtaining device description from %s -- error = %d", location, err_code); } else { add_device_to_list(desc_doc, location, event->Expires); } if( desc_doc ) { ixmlDocument_free(desc_doc); } 2. UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE 当设备下线时会广播此消息,控制点收到后,需要把设备从链表中移除。 int err_code = event->ErrCode; if (err_code != UPNP_E_SUCCESS) { dprinterr("Error in Discovery ByeBye Callback -- %d", err_code); } const char *udn = event->DeviceId; remove_device(udn); 3. UPNP_CONTROL_ACTION_COMPLETE 当控制点发送了ACTION后,会收到这个消息,它是用来返回ACTION执行的结果,控制点也可以通过这个判断ACTION是否执行成功,是否需要再次发送ACTION。 4. UPNP_CONTROL_GET_VAR_COMPLETE 当控制点发送获取设备状态后,会收到此消息,可以从消息中读取到状态。 5. UPNP_EVENT_RECEIVED 当控制点发送订阅服务,并订阅成功后,如果设备调用Notify,就会收到此消息,主要用于设备通知控制点状态发生变化。 三、控制点发出的请求 1.搜索请求 int UpnpSearchAsync( UpnpClient_Handle Hnd, int Mx,//超时时间,单位秒 const char *TTarget_constarget_const,//搜索匹配条件 const void *Cookie_const); 搜索匹配条件可以是以下: ssdp:all 搜索所有的设备和服务 upnp:rootdevice 只搜索根设备 uuid:device-UUID 搜索特定的设备 urn:schemas-upnp-org:device:deviceType:ver 搜索某一类型的设备 urn:schemas-upnp-org:service:serviceType:ver 搜索某一类型的服务 urn:domain-name:device:deviceType:ver urn:domain-name:service:serviceType:ver 发出搜索请求后,如果此设备在网络上,就会返回UPNP_DISCOVERY_SEARCH_RESULT,如果不能及时返回,应用程序就会收到UPNP_DISCOVERY_SEARCH_TIMEOUT。 2.动作请求 找到设备以后,可以请求设备执行某项动作,这些动作可以是控制设备开关,也可以是返回设备状态(据说UPNP论坛推荐这样做,而不是使用请求状态变量来获取设备状态)。 在发送动作请求之前,需要创建一个动作: IXML_Document *UpnpMakeAction( const char *ActionName, const char *ServType, int NumArg, const char *Arg,...); int UpnpAddToAction( IXML_Document **ActionDoc, const char *ActionName, const char *ServType, const char *ArgName, const char *ArgVal); 创建好动作以后,就可以开始发送动作了: int UpnpSendActionAsync( UpnpClient_Handle Hnd, const char *ActionURL, const char *ServiceType, const char *DevUDN, IXML_Document *Action, Upnp_FunPtr Fun, const void *Cookie); typedef int (*Upnp_FunPtr)(Upnp_EventType EventType,void *Event, void *Cookie); 其中Upnp_FunPtr是回调函数,里面可以得到动作执行的结果。 示例: if( 0 == param_count ) { action_node =UpnpMakeAction(actionname,service_type, 0,NULL ); } else { for( param = 0; param < param_count; param++ ){ if( UpnpAddToAction(&action_node,actionname,service_type,param_name[param], param_val[param]) != UPNP_E_SUCCESS ) { dprinterr("ERROR:Trying to add action param"); ithread_mutex_unlock( &g_ctrl_mutex ); return -1; } } } ret_code = UpnpSendActionAsync(client_handle,ctrl_url, service_type,NULL,action_node, upnp_ctrl_event_handler,NULL); 3.设备状态请求 有两种方法可以获取到当前设备的状态,一种是使用动作请求,一种是设备状态请求,其中后面一种不推荐使用了。 int UpnpGetServiceVarStatus( UpnpClient_Handle Hnd, const char *ActionURL, const char *VarName, DOMString *StVarVal); int UpnpGetServiceVarStatusAsync( UpnpClient_Handle Hnd, const char *ActionURL, const char *VarName, Upnp_FunPtr Fun, const void *Cookie); 4.订阅请求 设备状态发生变化时,也可以主动调用Notify函数通知已订阅此状态的控制点。 控制点调用下面这个函数订阅服务的状态: int UpnpSubscribeAsync( UpnpClient_Handle Hnd, const char *PublisherUrl,//event_url int TimeOut, Upnp_FunPtr Fun, const void *Cookie); 取消订阅: int UpnpUnSubscribe( UpnpClient_Handle Hnd, const Upnp_SID SubsId); 五、数据的传输 可以使用HTTP进行数据传输: 1.从服务器获取数据: UpnpOpenHttpGet UpnpReadHttpGet UpnpCloseHttpGet 2.提交文件到服务器: UpnpOpenHttpPost UpnpWriteHttpPost UpnpCloseHttpPost 六、UPNP的 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 服务 主要包括下面四个标准服务: 1. Content Directory Service: Enumerates the available content. 2. Connection Manager Service: Determines how the content can be transferred from the UPnP AV MediaServer to the UPnP AV MediaRenderer devices. 3. AV Transport Service: Controls the flow of the content. 4. Rendering Control Service: Controls how the content is played.
本文档为【UPNP编程】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_758875
暂无简介~
格式:doc
大小:59KB
软件:Word
页数:9
分类:互联网
上传时间:2013-06-01
浏览量:36