This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Adding to ONVIF GetServices in Appro IPNC SDK

Hardware is DM368, software is Appro IPNC SDK 4.x.


We are trying to get the blessed thing to pass ONVIF compliance test and include PTZ controls, it looks like we need to add to the list of services returned to Onvif "GetServices" request (in onvif.c) but I can't see the correct way to insert items on the Services / Capabilities list. The existing code is:


int  __tds__GetServices(struct soap* soap, struct _tds__GetServices *tds__GetServices, struct _tds__GetServicesResponse *tds__GetServicesResponse)
{

    char _IPAddr[URI_LENGTH];
    int i = 0;
    NET_IPV4 ip;
    ip.int32 = net_get_ifaddr(ETH_NAME);
    sprintf(_IPAddr, "http://%d.%d.%d.%d/onvif/services", ip.str[0], ip.str[1], ip.str[2], ip.str[3]);
    tds__GetServicesResponse->__sizeService = 1;
    
    
    if(!tds__GetServices->IncludeCapability)
    {
        tds__GetServicesResponse->Service = (struct tds__Service *)soap_malloc(soap, sizeof(struct tds__Service));
        
        tds__GetServicesResponse->__sizeService = 1; // There are <n> tds__Service structs in tds__GetServicesResponse->Service

        tds__GetServicesResponse->Service[0].XAddr = (char *)soap_malloc(soap, sizeof(char) * URI_LENGTH);
        tds__GetServicesResponse->Service[0].Namespace = (char *)soap_malloc(soap, sizeof(char) * URI_LENGTH);
        strcpy(tds__GetServicesResponse->Service[0].Namespace, "http://www.onvif.org/ver10/events/wsdl");
        strcpy(tds__GetServicesResponse->Service[0].XAddr, _IPAddr);
        tds__GetServicesResponse->Service[0].Capabilities = NULL;
        tds__GetServicesResponse->Service[0].Version = (struct ns2__OnvifVersion *)soap_malloc(soap, sizeof(struct ns2__OnvifVersion));
        tds__GetServicesResponse->Service[0].Version->Major = 0;
        tds__GetServicesResponse->Service[0].Version->Minor = 3;
        
        tds__GetServicesResponse->Service[0].__any = (char **)soap_malloc(soap, 2*sizeof(char *)); // Malloc Double the size of a pointer to char
        tds__GetServicesResponse->Service[0].__any[0] = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);
        strcpy(tds__GetServicesResponse->Service[0].__any[0],"Face Detection ");
        tds__GetServicesResponse->Service[0].__any[1] = (char *)soap_malloc(soap,sizeof(char) * INFO_LENGTH);
        strcpy(tds__GetServicesResponse->Service[0].__any[1],"Motion Detection ");
        tds__GetServicesResponse->Service[0].__size = NULL;
        tds__GetServicesResponse->Service[0].__anyAttribute = NULL;
        return SOAP_OK;
    }
    else
    {
        tds__GetServicesResponse->Service = (struct tds__Service *)soap_malloc(soap, sizeof(struct tds__Service));
        tds__GetServicesResponse->__sizeService = 1;
        tds__GetServicesResponse->Service[0].Namespace = NULL;
        tds__GetServicesResponse->Service[0].XAddr = (char *)soap_malloc(soap, sizeof(char) * URI_LENGTH);
        strcpy(tds__GetServicesResponse->Service[0].XAddr, _IPAddr);
        tds__GetServicesResponse->Service[0].Capabilities = NULL;
        tds__GetServicesResponse->Service[0].Version = (struct ns2__OnvifVersion *)soap_malloc(soap, sizeof(struct ns2__OnvifVersion));
        tds__GetServicesResponse->Service[0].Version->Major = 0;
        tds__GetServicesResponse->Service[0].Version->Minor = 3;
        tds__GetServicesResponse->Service[0].__size = NULL;
        tds__GetServicesResponse->Service[0].__any = NULL;
        tds__GetServicesResponse->Service[0].__anyAttribute = NULL;
        return SOAP_OK;    
    }
}

Now, I have spent a while reading through the code and thought this looked like a reasonable way to go about things, but it just SEGFAULTs as soon as it gets the request:

int  __tds__GetServices(struct soap* soap, struct _tds__GetServices *tds__GetServices, struct _tds__GetServicesResponse *tds__GetServicesResponse)
{

    char _IPAddr[URI_LENGTH];
    int i = 0;
    NET_IPV4 ip;
    ip.int32 = net_get_ifaddr(ETH_NAME);
    sprintf(_IPAddr, "http://%d.%d.%d.%d/onvif/services", ip.str[0], ip.str[1], ip.str[2], ip.str[3]);
    
    tds__GetServicesResponse->__sizeService = 2; // There are <n> tds__Service structs in tds__GetServicesResponse->Service
    tds__GetServicesResponse->Service = (struct tds__Service *)soap_malloc(soap, 2 * sizeof(struct tds__Service));
    
    tds__GetServicesResponse->Service[0].XAddr = (char *)soap_malloc(soap, sizeof(char) * URI_LENGTH);
    tds__GetServicesResponse->Service[0].Namespace = (char *)soap_malloc(soap, sizeof(char) * URI_LENGTH);
    strcpy(tds__GetServicesResponse->Service[0].Namespace, "http://www.onvif.org/ver10/events/wsdl");
    strcpy(tds__GetServicesResponse->Service[0].XAddr, _IPAddr);
    tds__GetServicesResponse->Service[0].Capabilities = NULL;
    tds__GetServicesResponse->Service[0].Version = (struct ns2__OnvifVersion *)soap_malloc(soap, sizeof(struct ns2__OnvifVersion));
    tds__GetServicesResponse->Service[0].Version->Major = 1;
    tds__GetServicesResponse->Service[0].Version->Minor = 0;
    
    tds__GetServicesResponse->Service[0].__size = NULL;
    tds__GetServicesResponse->Service[0].__any = NULL;
    tds__GetServicesResponse->Service[0].__anyAttribute = NULL;
    
    
    /// Now the 2nd service
    tds__GetServicesResponse->Service[1].XAddr = (char *)soap_malloc(soap, sizeof(char) * URI_LENGTH);
    tds__GetServicesResponse->Service[1].Namespace = (char *)soap_malloc(soap, sizeof(char) * URI_LENGTH);
    strcpy(tds__GetServicesResponse->Service[1].Namespace, "http://www.onvif.org/ver20/ptz/wsdl");
    strcpy(tds__GetServicesResponse->Service[1].XAddr, _IPAddr);
    
    
    tds__GetServicesResponse->Service[1].Capabilities = (char *)soap_malloc(soap, sizeof(char) * URI_LENGTH);
    strcpy(tds__GetServicesResponse->Service[1].Capabilities, "<tptz:Capabilities xmlns:tptz=\"http://www.onvif.org/ver20/ptz/wsdl\" EFlip=\"false\" Reverse=\"false\" />");
    tds__GetServicesResponse->Service[1].Version = (struct ns2__OnvifVersion *)soap_malloc(soap, sizeof(struct ns2__OnvifVersion));
    tds__GetServicesResponse->Service[1].Version->Major = 2;
    tds__GetServicesResponse->Service[1].Version->Minor = 20;
    
    tds__GetServicesResponse->Service[1].__size = NULL;
    tds__GetServicesResponse->Service[1].__any = NULL;
    tds__GetServicesResponse->Service[1].__anyAttribute = NULL;    
    return SOAP_OK;
}

The sort of response we are looking for has more than one entry, like this example from the Onvif Core Spec document:


<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:enc="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema">
<env:Header>
</env:Header>
<env:Body>
<tds:GetServicesResponse>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/device/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.0.10/onvif/device_service</tds:XAddr>
<tds:Capabilities>
<tds:Capabilities>
<tds:Network IPFilter="false" ZeroConfiguration="true" IPVersion6="false" DynDNS="false" Dot11Configuration="false" HostnameFromDHCP="false" NTP="0" />
<tds:Security TLS1.0="false" TLS1.1="false" TLS1.2="false" OnboardKeyGeneration="false" AccessPolicyConfig="false" DefaultAccessPolicy="false" Dot1X="false" RemoteUserHandling="false" X.509Token="false" SAMLToken="false" KerberosToken="false" UsernameToken="false" HttpDigest="false" RELToken="false" />
<tds:System DiscoveryResolve="true" DiscoveryBye="true" RemoteDiscovery="false" SystemBackup="false" SystemLogging="false" FirmwareUpgrade="true" HttpFirmwareUpgrade="false" HttpSystemBackup="false" HttpSystemLogging="false" HttpSupportInformation="false" />
<tds:MiscCapabilities AuxiliaryCommands="" />
</tds:Capabilities>
</tds:Capabilities>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/media/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.0.10/onvif</tds:XAddr>
<tds:Capabilities>
<trt:Capabilities xmlns:trt="http://www.onvif.org/ver10/media/wsdl" SnapshotUri="true" Rotation="false">
<trt:ProfileCapabilities MaximumNumberOfProfiles="10" />
<trt:StreamingCapabilities RTPMulticast="true" RTP_TCP="false" RTP_RTSP_TCP="true" NonAggregateControl="true" />
</trt:Capabilities>
</tds:Capabilities>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver20/ptz/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.0.10/onvif</tds:XAddr>
<tds:Capabilities>
<tptz:Capabilities xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" EFlip="false" Reverse="false" />
</tds:Capabilities>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/events/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.0.10/onvif</tds:XAddr>
<tds:Capabilities>
<tev:Capabilities xmlns:tev="http://www.onvif.org/ver10/events/wsdl" WSSubscriptionPolicySupport="false" WSPullPointSupport="false" WSPausableSubscription="false" />
</tds:Capabilities>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver20/imaging/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.0.10/onvif</tds:XAddr>
<tds:Capabilities>
<timg:Capabilities xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" ImageStabilization="false" />
</tds:Capabilities>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/deviceIO/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.0.10/onvif</tds:XAddr>
<tds:Capabilities>
<tmd:Capabilities xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" VideoSources="1" VideoOutputs="0" AudioSources="1" AudioOutputs="1" RelayOutputs="0" SerialPorts="0" DigitalInputs="0" />
</tds:Capabilities>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
</tds:GetServicesResponse>
</env:Body>
</env:Envelope>

Can anyone help with the correct way to add multiple services into that code?

  • Never mind, I got it sorted, so easy to miss bits in this code!

  • Hi Bob:

    I am doing ptz  service on ONVIF too.  and happen to an error on testing ONVIF device test tool PTZ-1-1-1 PTZ NODES. The error is show as in red below 

    The element 'Service' in namespace 'http://www.onvif.org/ver10/device/wsdl' cannot contain text. List of possible elements expected: any element in namespace '##any'.

    I learn from your case and add a ptz service  at  __tds__GetServices like below, I don't got it why test tool told me

    in namespace 'http://www.onvif.org/ver10/device/wsdl'  cannot contain text, but actually I assigned "http://www.onvif.org/ver20/ptz/wsdl" ?

    tds__GetServicesResponse->Service[1].XAddr = _IPAddr;
    tds__GetServicesResponse->Service[1].Namespace = "http://www.onvif.org/ver20/ptz/wsdl";
    tds__GetServicesResponse->Service[1].Capabilities = NULL;
    tds__GetServicesResponse->Service[1].Version = (struct tt__OnvifVersion *)soap_malloc(soap, sizeof(struct tt__OnvifVersion));
    tds__GetServicesResponse->Service[1].Version->Major = 2;
    tds__GetServicesResponse->Service[1].Version->Minor = 20;
    tds__GetServicesResponse->Service[1].__size = 0;
    tds__GetServicesResponse->Service[1].__any = NULL;
    tds__GetServicesResponse->Service[1].__anyAttribute = NULL;

  • Hey, I was wondering what success you folks had adding PTZ to the reference design. I am looking into trying to do this, and was wondering if you had any further success/failure stories?
  • Timothy,

    All I can say is yes we did it, but it's a long and painful road. The entire IPNC codebase is riddled with bugs, and the ONVIF standards have moved on so even the standard original code would not pass ONVIF conformance now - and yes you MUST pass the current spec or ONVIF will not accept your product.

    If memory serves we had to run gSoap against the PTZ WSDL and then to avoid ruining the entire existing ONVIF code, sort of weave it into the existing code.

    See http://www.cs.fsu.edu/~engelen/soapfaq.html "How do I use gSOAP for the ONVIF specifications?

    cd /IPNC/gsoap-2.8/gsoap/bin/linux386/
    ./wsdl2h -c -o onvifptz.h www.onvif.org/.../ptz.wsdl www.w3.org/.../ws-addr.xsd
    soapcpp2 -c onvifptz.h

    Well, that's the easy bit anyway. TBH explaining the whole thing in any useful detail is like trying to explain the space programme on the back of a napkin, there's just too much of it.

    On the plus side, we've done it and it works and you can hire us to sort yours out if that sounds more appealing ;)

  • Bob-

    Thanks for the response, and right now I am just doing initial investigation into this. I am trying to go through and familiarize myself with their code that is there. I am not sure that submitting this to ONVIF for us is a necessity. I saw that you had been working on this, and saw that you had a lot of frustrations trying to get this working. So I thought I would reach out for some words of wisdom. I would not expect you to give the nuts and bolts in a forum post.  

    Thanks


    Tim