Pelco Developer Network (PDN)

Developing an ONVIF C++ Client Application

This article discusses the creation of an ONVIF C++ client application that communicates with a Sarix camera. ONVIF complements the Pelco API in Sarix cameras by providing additional functionality in the form of web service calls. One specific call in the Pelco API, GetDeviceInformation, is an ONVIF web service that fetches information about a device. GetDeviceInformation does not require credentials, and provides a simple introduction to the ONVIF calling sequence.

Although the concept of web services and SOAP-based communication is easy to grasp, the details can be difficult to manage. Many developers prefer to use classes that wrap SOAP calls instead of reading and writing raw XML strings. These classes hide the strings and the communication between client and server. There are several ways to create wrappers around the SOAP calls necessary for a client to communicate with a camera or other ONVIF device. The sample provided in this article uses C++ proxy classes generated by the gSOAP toolkit, as discussed in Generating ONVIF Proxy Classes using gSOAP.

Complete Application Source Code

Here is the complete application source code in one listing. Snippets will be discussed in detail throughout the article. Projects for Visual Studio and Xcode are available on the Sample Code page.

#include <iostream>
#include <cstring>

#include "soapDeviceBindingProxy.h"
#include "DeviceBinding.nsmap"


int main(int argc, const char * argv[])
{
    struct soap soap;

    soap_init( &soap );

    DeviceBindingProxy proxy( soap );    

    _tds__GetDeviceInformation tds__GetDeviceInformation;
    _tds__GetDeviceInformationResponse tds__GetDeviceInformationResponse;

    std::string endpoint = "http://192.168.0.99/onvif/services";

    int result = SOAP_ERR;    

    result = proxy.GetDeviceInformation( endpoint.c_str(), NULL, 
      &tds__GetDeviceInformation, &tds__GetDeviceInformationResponse );

    if ( result == SOAP_OK )
    {
        std::cout << "Mfr: " << tds__GetDeviceInformationResponse.Manufacturer << std::endl;
        std::cout << "Model: " << tds__GetDeviceInformationResponse.Model << std::endl;
        std::cout << "F/W version: " << tds__GetDeviceInformationResponse.FirmwareVersion << std::endl;
    }

    return 0;
}

Header Files

This application uses C++ STL (Standard Template Library) iostream and string classes. The other #include files are gSOAP-related.

#include <iostream>
#include <cstring>

#include "soapDeviceBindingProxy.h"
#include "DeviceBinding.nsmap"

The soapDeviceBindingProxy.h and DeviceBinding.nsmap files are created by gSOAP during the class generation process. The .nsmap file maps individual namespaces to their definitions on the ONVIF site and other locations.

There is a chain of #include files starting at the top of soapDeviceBindingProxy.h. Those files are not listed explicitly in main.cpp but can either reside in the project header paths or in the project directory itself.

No manipulation of these header files is needed.

main()

The main() function is very simple but some of the data types may be unfamiliar. The soap structure is a gSOAP data structure that maintains state information, settings, function hooks, and much more. Look in stdsoap2.h for details.

    struct soap soap;

    soap_init( &soap );

After initializing the structure, allocate a DeviceBindingProxy object, and request and response objects (_tds__GetDeviceInformation[Response]). Automatic variables work great here.

    DeviceBindingProxy proxy( soap );    

    _tds__GetDeviceInformation tds__GetDeviceInformation;
    _tds__GetDeviceInformationResponse tds__GetDeviceInformationResponse;

The SOAP endpoint is the URI to which to connect.

    std::string endpoint = "http://192.168.0.99/onvif/services";

The GetDeviceInformation method call requires only the endpoint, and addresses of the request and response objects. The call is made synchronously. Behind the scenes the method maps to a web service call.

    int result = SOAP_ERR;    

    result = proxy.GetDeviceInformation( endpoint.c_str(), NULL, 
      &tds__GetDeviceInformation, &tds__GetDeviceInformationResponse );

Output is routed to the console. The response object contains enough interesting information to print.

    if ( result == SOAP_OK )
    {
        std::cout << "Mfr: " << tds__GetDeviceInformationResponse.Manufacturer << std::endl;
        std::cout << "Model: " << tds__GetDeviceInformationResponse.Model << std::endl;
        std::cout << "F/W version: " << tds__GetDeviceInformationResponse.FirmwareVersion << std::endl;
    }

GetDeviceInformation Output

The call to GetDeviceInformation returns the following camera information as well as a couple of fields that are not shown:

Mfr: Pelco
Model: D5118
F/W version: 1.9.2.19-20140318-1.9310-A1.10443

Project Settings

Development environments differ in how you specify settings but these general concepts apply to a simple project:

  • Add source code files
  • Set compiler flags

The next two sections include examples of applying these steps.

Source code files

Figure 1 lists the source files included in this project. Most of these are gSOAP files and not all are C++ files. The gSOAP documentation, including the README.txt and INSTALL.txt files included in the archive, contain a lot of information regarding what needs to be included in a project.

Figure 1. Source file list.

Compiler settings

Figure 2 highlights one particular setting that Xcode users might need to use: "Compile Sources As". The default is to let the compiler choose how to compile each file based on the file extension. For some files this does not work quite right, leading to compiler errors such as not recognizing #include <vector>; in this case the resulting error is "'vector' file not found". In a simple project it is possible to force the compilation to one particular file type to eliminate that particular error. Note that C files compile fine with this flag set to C++.

Figure 2. Force compilation file type.

Other development environments may have their own quirks.

Using the techniques demonstrated in this article you can create an ONVIF C++ client application. If you are not already familiar with gSOAP, read the article Generating ONVIF Proxy Classes using gSOAP. Proxy classes save a lot of development effort and allow you to focus on application functionality.

For More Information…

The links below provide additional information regarding the tools referenced in this article.