在使用 gSoap 框架生成代码之后, 得到文件:
soapC.c
soapClient.c
stdsoap2.c stdsoap2.h
duration.c
wsdd.h
我们利用现有的soapClient, 调用API构建Onvif请求(包括XML, HTTP Client). 开发前需要了解一下Onvif官网文档指导: Onvif 2.0 Service Operation Index;该文档列举了ONVIF的各个模块下的各种方法. 再回到gSoap框架, 同样, 它的文档说明也比较详细.
gSoap 框架API
- 创建初始化Soap对象
在stdsoap2.h文件中,有如下定义
//创建各种soap
#define soap_new() soap_new1(SOAP_IO_DEFAULT)
#define soap_new1(mode) soap_new2(mode, mode)
#define soap_new2(imode, omode) soap_versioning(soap_new)(imode, omode)
//初始化各种soap
#define soap_init(soap) soap_init1(soap, SOAP_IO_DEFAULT)
#define soap_init1(soap, mode) soap_init2(soap, mode, mode)
#define soap_init2(soap, imode, omode) soap_versioning(soap_init)(soap, imode, omode)
- 申请内存模块打Soap中
//该函数soap_done函数调用的时候释放, 无需调用free函数
soap_malloc(struct soap *soap, size_t n)
- 结束释放Soap
//释放临时Cache
soap_end(struct soap *soap)
//释放所以内存模块和关闭socket
soap_done(struct soap *soap)
//销毁soap对象
#define soap_destroy(soap) soap_delete((soap), NULL)
另外,调试程序接口信息可以打开LOG Level, 如Cmake下
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb -DDEBUG")
使用宏DEBUG
打开并输出调试信息到 recv.log, send.log, test.log .
设备发现
从官方文档上列举的这些方法,我们按照正常操作ONVIF设备客户端开始,那么第一步就必然是找到ONVIF在线的设备.
设备搜索步骤:
(1) 初始化客户端
初始化客户端, 包括uuid地址, 超时设置,头部信息等.
struct saop* onvif_init_soap(struct SOAP_ENV__Header *header,
const char *wsa_To,
const char *wsa_Action,
int timeout,
UserInfo_S *pUser){
struct soap *soap = NULL;
unsigned char macaddr[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; //设置MAC值
char _HwId[1024];
unsigned int Flagrand;
soap = soap_new();
if (soap == NULL) {
//LOGE("soap is NULL\n");
return NULL;
}
//设置命名空间
soap_set_namespaces(soap, namespaces);
if (timeout > 0){
soap->recv_timeout = timeout;
soap->send_timeout = timeout;
soap->connect_timeout = timeout;
}else{
//设置超时默认值 10s
soap->recv_timeout = 10;
soap->send_timeout = 10;
soap->connect_timeout = 10;
}
soap_default_SOAP_ENV__Header(soap, header);
srand((int)time(0));
Flagrand = rand() % 9000 + 1000; //取4位数
sprintf(_HwId, "urn:uuid:%ud68a-1dd2-11b2-a1025-%02X%02X%02X%02X%02X%02X",
Flagrand, macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
header->wsa__MessageID = (char *)soap_malloc(soap, 100);
memset(header->wsa__MessageID, 0, 100);
strncpy(header->wsa__MessageID, _HwId, strlen(_HwId));
if (pUser != NULL){
//TODO
}
if (wsa_Action != NULL){
//was_Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
header->wsa__Action = (char *)malloc(1024);
memset(header->wsa__Action, '\0', 1024);
strncpy(header->wsa__Action, wsa_Action, 1024);
}
if (wsa_To != NULL){
//wsa_To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
header->wsa__To = (char *)malloc(1024);
memset(header->wsa__To, '\0', 1024);
strncpy(header->wsa__To, wsa_To, 1024);
}
soap->header = header;
return soap;
}
(2) 设置Probe搜索参数
wsdd__ProbeType req;
struct __wsdd__ProbeMatches resp;
wsdd__ScopesType sScope;
struct SOAP_ENV__Header header;
struct soap *soap = NULL;
const char *wsa_To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
const char *wsa_Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
const char *soap_endpoint = "soap.udp://239.255.255.250:3702/";
soap = onvif_init_soap(&header, wsa_To, wsa_Action, 5, NULL);
soap_default_SOAP_ENV__Header(soap, &header);
soap->header = &header;
soap_default_wsdd__ScopesType(soap, &sScope);
sScope.__item = "";
soap_default_wsdd__ProbeType(soap, &req);
req.Scopes = &sScope;
req.Types = "";
(3) 发送Probe Action
retval = soap_send___wsdd__Probe(soap, soap_endpoint, NULL, &req);
(4) 接收ProbeMatches
while(retval == SOAP_OK){
retval = soap_recv___wsdd__ProbeMatches(soap, &resp);
if (retval == SOAP_OK){
if (soap->error){
//LOGE("recv soap error:%s(%d)\n", *soap_faultstring(soap), *soap_faultcode(soap));
retval = soap->error;
}else{
if (resp.wsdd__ProbeMatches != NULL &&
resp.wsdd__ProbeMatches->ProbeMatch != NULL &&
resp.wsdd__ProbeMatches->ProbeMatch->XAddrs != NULL){
HasDev ++;
if (on_device_found(resp)){// 非0表示退出
break;
}
sleep(1);
}
}//else
}else if (soap->error){
if (HasDev == 0){
retval = soap->error;
}else{
retval = 0;
}
break;
}//else if
}//while
(5) 释放资源
soap_destroy(soap);
soap_end(soap);
soap_free(soap);