ONVIF for Linux – Discovery
Completing the proxy generation
First I wanted to get rid of the errors “not implemented” and “deep recursion” that occurred during proxy generation.
I made local copies of all referenced XSDs and replaced references with xsd:anyType
or commented out the attributes referencing http://docs.oasis-open.org/wsn/b-2 . This XSD had the most errors and was only referenced by the Event service which I would not use to begin with.
Next I had a problem with namespaces: wsdl2perl
expects http://schemas.xmlsoap.org/wsdl/soap/ while ONVIF uses http://schemas.xmlsoap.org/wsdl/soap12/. Again I adjusted the ONVIF WSDLs.
Lastly I saw that the ONVIF WSDLs do not contain <service>
elements. Which makes sense since every ip camera will have its own IP address. Nevertheless I needed at least one <service>
and one <port>
to successfully complete generation. So I added these elements with a bogus address to be replaced later on.
I then re-generated the proxy classes for the three WSDLs:
wsdl2perl.pl -p ONVIF::Device:: -b proxy file:wsdl/devicemgmt.wsdl wsdl2perl.pl -p ONVIF::Media:: -b proxy file:wsdl/media.wsdl wsdl2perl.pl -p ONVIF::PTZ:: -b proxy file:wsdl/ptz.wsdl
Aside: Since all three WSDLs reference onvif.xsd
I now had all types from this file tripled – once in each service directory tree. A task for the future is to make a Common
directory and factor out all classes generated from onvif.xsd
.
Discovery!
I now had a nice API but who should I call? What was the URL of those web services?
To solve this problem the ONVIF specification mandates that ONVIF devices support WS-Discovery. This is a UDP-multicast based protocol with semantics like this:
Client: “I need a device with attributes X. Who’s there?”
Device 1: “I am here and I can do X and Y”.
Device 2: “I am here and I can do only X”.
Device 3: [ keeps quiet, cannot do X.]
So I put together a small WSDL file with binding and service for WS-Discovery and generated a proxy for it using the techniques outlined above.
Additionally I implemented a SOAP-over-UDP transport module in Perl and a small test script:
require WSDiscovery::Interfaces::WSDiscovery::WSDiscoveryPort; require WSDiscovery::Elements::Types; require WSDiscovery::Elements::Scopes; require WSDiscovery::TransportUDP; sub discover { my $svc_discover = WSDiscovery::Interfaces::WSDiscovery::WSDiscoveryPort->new(); my $result = $svc_discover->ProbeOp( { # WSDiscovery::Types::ProbeType Types => { 'dn:NetworkVideoTransmitter', 'tds:Device' }, # QNameListType Scopes => { value => '' }, },, ); die $result if not $result; print $result; } discover();
This test script got the following answer from my camera.
<?xml version="1.0" encoding="UTF-8"?> <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:soapenc="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tst="http://www.onvif.org/ver10/storage/wsdl" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:dn="http://www.onvif.org/ver10/network/wsdl" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl" xmlns:wsoap12="http://schemas.xmlsoap.org/wsdl/soap12" xmlns:http="http://schemas.xmlsoap.org/wsdl/http" xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:wsadis="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2" xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2" xmlns:trc="http://www.onvif.org/ver10/recording/wsdl" xmlns:tse="http://www.onvif.org/ver10/search/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tnsn="http://www.eventextension.com/2011/event/topics"> <env:Header><wsadis:MessageID>urn:uuid:af34024f-1dd1-11b2-81f8-d8eb97cd1a05</wsadis:MessageID> <wsadis:RelatesTo></wsadis:RelatesTo> <wsadis:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsadis:To> <wsadis:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches</wsadis:Action> <d:AppSequence InstanceId="1404277082" MessageNumber="5"/> </env:Header> <env:Body><d:ProbeMatches><d:ProbeMatch><wsadis:EndpointReference><wsadis:Address>urn:uuid:af34024f-1dd1-11b2-81f8-d8eb97cd1a05</wsadis:Address> </wsadis:EndpointReference> <d:Types>dn:NetworkVideoTransmitter tds:Device</d:Types> <d:Scopes>onvif://www.onvif.org/type/video_encoder onvif://www.onvif.org/Profile/Streaming onvif://www.onvif.org/hardware/TV-IP311PI onvif://www.onvif.org/name/TV-IP311PI onvif://www.onvif.org/location/ </d:Scopes> <d:XAddrs>http://192.168.0.20/onvif/device_service </d:XAddrs> <d:MetadataVersion>10</d:MetadataVersion> </d:ProbeMatch> </d:ProbeMatches> </env:Body> </env:Envelope>
As you can see, the response neatly describes the device (TV-IP311PI), its capabilities (type/video_encoder
, Profile/Streaming
) and — most importantly — gives an address for the Device
web service:
http://192.168.0.20/onvif/device_service
The next steps will be to call the web service at this address and query it for more capabilities. Also I want to integrate this into ZoneMinder.
I will keep you posted.
Nice work! Congratulations!!!
Keep waching your work. I’m interested in zoneminder integration!!!