Skip to content

OnvifClient Plugin

Description

OnvifClient is a network camera integration plugin that provides ONVIF (Open Network Video Interface Forum) protocol support for CVEDIA-RT. It enables discovery, configuration, and control of ONVIF-compliant IP cameras and network video devices.

This plugin implements the complete ONVIF specification for professional camera integration, providing automatic device discovery, secure authentication, camera control, stream management, and event handling for enterprise-grade surveillance and video management systems.

Key Features

  • ONVIF Protocol Compliance: Full implementation of ONVIF specification for standardized camera integration
  • Automatic Device Discovery: WS-Discovery protocol for automatic detection of ONVIF devices on the network
  • Camera Control: Pan, tilt, zoom (PTZ) and other camera control operations
  • Stream Management: Video stream configuration, profile management, and URI generation
  • Secure Authentication: WS-Security authentication with digest and basic authentication support
  • Profile Management: Camera profile configuration, switching, and media stream setup
  • Event Handling: ONVIF event subscription, notification processing, and real-time event streams
  • REST API Integration: RESTful API interface for external ONVIF operations and management
  • Device Information: Comprehensive device information retrieval and management
  • Capabilities Discovery: Automatic discovery and reporting of device capabilities
  • Network Configuration: Network interface configuration and management
  • Time Synchronization: NTP and manual time synchronization with ONVIF devices

Requirements

Hardware Requirements

  • Network Interface: Ethernet or Wi-Fi network connectivity
  • ONVIF Devices: ONVIF-compliant IP cameras and network video devices
  • Network Infrastructure: Proper network configuration with multicast support for discovery
  • Bandwidth: Sufficient network bandwidth for video streams (varies by resolution/bitrate)

Software Dependencies

  • GSOAP: SOAP protocol implementation library for ONVIF communication
  • OpenSSL: Cryptographic library for secure communication and authentication
  • libxml2: XML parsing library for SOAP message processing
  • Network Libraries: TCP/UDP networking support and socket operations
  • JSON Library: JSON processing for REST API and configuration
  • UUID Library: UUID generation for device identification
  • Threading Library: Multi-threading support for concurrent operations

Network Requirements

  • Multicast Support: UDP multicast for WS-Discovery (239.255.255.250:3702)
  • Port Access: Access to ONVIF device HTTP/HTTPS ports (typically 80, 443, 8080)
  • Firewall Configuration: Proper firewall rules for ONVIF communication
  • DNS Resolution: DNS resolution for device hostname lookup

Configuration

Basic Configuration

{
  "onvif": {
    "discovery": {
      "enabled": true,
      "timeout": 5000,
      "multicast_address": "239.255.255.250",
      "multicast_port": 3702
    },
    "authentication": {
      "username": "admin",
      "password": "password",
      "auth_method": "digest"
    },
    "connection": {
      "timeout": 30000,
      "retry_attempts": 3,
      "keep_alive": true
    }
  }
}

Advanced Configuration

{
  "onvif": {
    "discovery": {
      "enabled": true,
      "timeout": 10000,
      "multicast_address": "239.255.255.250",
      "multicast_port": 3702,
      "probe_interval": 60000,
      "device_filters": ["NetworkVideoTransmitter"],
      "scope_filters": ["onvif://www.onvif.org/Profile/Streaming"]
    },
    "authentication": {
      "username": "admin",
      "password": "secure_password",
      "auth_method": "digest",
      "token_lifetime": 3600,
      "nonce_generation": true
    },
    "connection": {
      "timeout": 30000,
      "retry_attempts": 5,
      "retry_delay": 1000,
      "keep_alive": true,
      "ssl_verify": false,
      "user_agent": "CVEDIA-RT ONVIF Client"
    },
    "capabilities": {
      "ptz_support": true,
      "imaging_support": true,
      "events_support": true,
      "media_support": true
    },
    "streaming": {
      "preferred_transport": "RTP-Unicast",
      "stream_setup_timeout": 10000,
      "profile_selection": "auto"
    }
  }
}

Configuration Schema

Parameter Type Default Description
discovery.enabled bool true Enable automatic device discovery
discovery.timeout int 5000 Discovery timeout in milliseconds
discovery.multicast_address string "239.255.255.250" WS-Discovery multicast address
discovery.multicast_port int 3702 WS-Discovery multicast port
discovery.probe_interval int 60000 Periodic discovery probe interval
discovery.device_filters array [] Device type filters for discovery
discovery.scope_filters array [] Scope filters for device matching
authentication.username string "admin" ONVIF device username
authentication.password string "" ONVIF device password
authentication.auth_method string "digest" Authentication method ("basic", "digest")
authentication.token_lifetime int 3600 Authentication token lifetime (seconds)
connection.timeout int 30000 Connection timeout in milliseconds
connection.retry_attempts int 3 Number of retry attempts for failed operations
connection.retry_delay int 1000 Delay between retry attempts (ms)
connection.keep_alive bool true Enable HTTP keep-alive connections
connection.ssl_verify bool false Enable SSL certificate verification
streaming.preferred_transport string "RTP-Unicast" Preferred transport protocol
streaming.stream_setup_timeout int 10000 Stream setup timeout (ms)
streaming.profile_selection string "auto" Profile selection mode

API Reference

C++ API (OnvifDeviceImpl)

Device Information and Properties

class OnvifDeviceImpl : public iface::OnvifDevice {
public:
    // Device identification
    std::string const& getName() const override;
    std::string const& getXaddr() const override;
    std::string const& getManufacturer() const override;
    std::string const& getModel() const override;
    std::string const& getFirmwareVersion() const override;
    std::string const& getSerialNumber() const override;
    std::string const& getHardwareId() const override;

    // Network and scope information
    std::string const& getScopes() const override;
    std::string const& getTypes() const override;
    std::string const& getMetadataVersion() const override;

    // UUID and identification
    Uuid getUuid() const override;

    // Device state
    iface::OnvifDeviceState getState() const override;
};

enum class OnvifDeviceState {
    Unknown,
    Discovered,
    Connected,
    Authenticated,
    Configured,
    Error
};

Authentication and Security

class OnvifDeviceImpl {
public:
    // Credential management
    std::string const& getUsername() const override;
    std::string const& getPassword() const override;
    void setUsername(std::string const& username) override;
    void setPassword(std::string const& password) override;

    // Device population and initialization
    expected<void> populate() override;
    expected<void> authenticate();
    expected<void> updateCapabilities();
};

Stream Management

struct OnvifStream {
    std::string token;           // Profile token
    std::string name;            // Profile name
    std::string uri;             // Stream URI
    std::string transport;       // Transport protocol
    int width;                   // Video width
    int height;                  // Video height
    float framerate;             // Frame rate
    std::string encoding;        // Video encoding
    int bitrate;                 // Bitrate (bps)
};

class OnvifDeviceImpl {
public:
    // Stream access
    std::map<std::string, iface::OnvifStream> const& getStreams() const override;
    expected<std::string> getStreamUri(const std::string& profileToken);
    expected<void> configureStream(const std::string& profileToken, const StreamConfig& config);
};

Device Control

class OnvifDeviceImpl {
public:
    // PTZ control
    expected<void> moveAbsolute(float pan, float tilt, float zoom);
    expected<void> moveRelative(float pan, float tilt, float zoom);
    expected<void> moveContinuous(float panVelocity, float tiltVelocity, float zoomVelocity);
    expected<void> stopMovement();

    // Preset management
    expected<void> setPreset(const std::string& name);
    expected<void> gotoPreset(const std::string& token);
    expected<std::vector<PresetInfo>> getPresets();

    // Imaging control
    expected<void> setImagingSettings(const ImagingSettings& settings);
    expected<ImagingSettings> getImagingSettings();
};

struct ImagingSettings {
    float brightness = 50.0f;
    float contrast = 50.0f;
    float saturation = 50.0f;
    float sharpness = 50.0f;
    bool auto_focus = true;
    float focus_value = 0.0f;
};

REST API Interface

Device Discovery and Management

class ONVIFApi {
public:
    // Device discovery
    expected<std::vector<OnvifDevice>> discoverDevices();
    expected<OnvifDevice> getDevice(const std::string& deviceId);

    // Camera management
    expected<std::vector<OnvifCamera>> getCameras();
    expected<OnvifCamera> getCamera(const std::string& cameraId);
    expected<void> setCredentials(const std::string& cameraId, 
                                 const CredentialRequest& credentials);

    // Stream management
    expected<std::vector<OnvifStream>> getStreams(const std::string& cameraId);
    expected<std::string> getStreamUri(const std::string& cameraId, 
                                      const std::string& profileToken);
};

struct OnvifCamera {
    std::string id;
    std::string name;
    std::string manufacturer;
    std::string model;
    std::string ipAddress;
    std::string macAddress;
    OnvifDeviceState state;
    std::vector<std::string> capabilities;
};

Lua API

Device Discovery

-- Create ONVIF client
local onvif = api.factory.onvif.create(instance, "onvif_client")

-- Discover ONVIF devices
local devices = onvif:discoverDevices({
    timeout = 10000,
    device_types = {"NetworkVideoTransmitter"},
    scope_match = "onvif://www.onvif.org/Profile/Streaming"
})

for _, device in ipairs(devices) do
    print("Discovered device:")
    print("  Name:", device.name)
    print("  Manufacturer:", device.manufacturer)
    print("  Model:", device.model)
    print("  IP Address:", device.ip_address)
    print("  Capabilities:", table.concat(device.capabilities, ", "))
end

Device Connection and Authentication

-- Connect to specific device
local deviceId = "uuid:12345678-1234-1234-1234-123456789012"
local device = onvif:getDevice(deviceId)

if device then
    -- Set credentials
    device:setCredentials("admin", "password")

    -- Populate device information
    local success = device:populate()
    if success then
        print("Device connected successfully")
        print("Firmware:", device:getFirmwareVersion())
        print("Serial:", device:getSerialNumber())
    else
        print("Failed to connect to device")
    end
end

Stream Management

-- Get available streams
local streams = device:getStreams()

for profileToken, stream in pairs(streams) do
    print("Stream Profile:", stream.name)
    print("  Token:", stream.token)
    print("  Resolution:", stream.width .. "x" .. stream.height)
    print("  Frame Rate:", stream.framerate .. " fps")
    print("  Encoding:", stream.encoding)
    print("  URI:", stream.uri)
end

-- Select and configure stream
local mainStream = streams["Profile_1"]
if mainStream then
    local streamUri = device:getStreamUri(mainStream.token)
    print("Stream URI:", streamUri)
end

Examples

Basic ONVIF Device Discovery and Connection

#include "onvif_device_impl.h"
#include "ws_discovery_impl.h"

// ONVIF client for device discovery and management
class ONVIFClientManager {
public:
    void discoverAndConnect() {
        // Initialize WS-Discovery for device discovery
        wsDiscovery_ = std::make_unique<WSDiscoveryImpl>();

        // Configure discovery parameters
        DiscoveryConfig config;
        config.timeout = 10000;  // 10 second timeout
        config.multicastAddress = "239.255.255.250";
        config.multicastPort = 3702;

        // Discover ONVIF devices
        auto devices = wsDiscovery_->discoverDevices(config);
        if (!devices) {
            LOGE << "Device discovery failed: " << devices.error().message();
            return;
        }

        LOGI << "Discovered " << devices->size() << " ONVIF devices";

        // Connect to discovered devices
        for (const auto& deviceInfo : devices.value()) {
            connectToDevice(deviceInfo);
        }
    }

    void connectToDevice(const WsDiscoveryDevice& deviceInfo) {
        // Create ONVIF device instance
        auto device = std::make_unique<OnvifDeviceImpl>(deviceInfo);

        // Set authentication credentials
        device->setUsername("admin");
        device->setPassword("password");

        // Populate device information and capabilities
        auto populateResult = device->populate();
        if (!populateResult) {
            LOGE << "Failed to populate device " << device->getName() 
                 << ": " << populateResult.error().message();
            return;
        }

        // Log device information
        LOGI << "Connected to device: " << device->getName();
        LOGI << "  Manufacturer: " << device->getManufacturer();
        LOGI << "  Model: " << device->getModel();
        LOGI << "  Firmware: " << device->getFirmwareVersion();
        LOGI << "  Serial: " << device->getSerialNumber();

        // Get and configure streams
        configureDeviceStreams(device.get());

        // Store device for later use
        connectedDevices_[device->getUuid().toString()] = std::move(device);
    }

    void configureDeviceStreams(OnvifDeviceImpl* device) {
        auto streams = device->getStreams();

        LOGI << "Available streams for " << device->getName() << ":";
        for (const auto& [token, stream] : streams) {
            LOGI << "  Profile: " << stream.name;
            LOGI << "    Token: " << stream.token;
            LOGI << "    Resolution: " << stream.width << "x" << stream.height;
            LOGI << "    Frame Rate: " << stream.framerate << " fps";
            LOGI << "    Encoding: " << stream.encoding;
            LOGI << "    URI: " << stream.uri;

            // Configure preferred stream
            if (stream.width >= 1920 && stream.height >= 1080) {
                // Use high resolution stream
                configureHighResolutionStream(device, stream);
            }
        }
    }

private:
    std::unique_ptr<WSDiscoveryImpl> wsDiscovery_;
    std::map<std::string, std::unique_ptr<OnvifDeviceImpl>> connectedDevices_;

    void configureHighResolutionStream(OnvifDeviceImpl* device, 
                                     const iface::OnvifStream& stream) {
        // Configure stream for optimal quality
        StreamConfig config;
        config.width = 1920;
        config.height = 1080;
        config.framerate = 30.0f;
        config.bitrate = 4000000;  // 4 Mbps
        config.encoding = "H264";

        auto result = device->configureStream(stream.token, config);
        if (result) {
            LOGI << "Configured high-resolution stream for " << device->getName();
        }
    }
};

PTZ Camera Control

// PTZ camera control and management
class ONVIFPTZController {
public:
    void initializePTZControl(OnvifDeviceImpl* device) {
        device_ = device;

        // Verify PTZ capabilities
        auto caps = device_->getCapabilities();
        if (!caps || !caps->get("ptz_support").getBool()) {
            LOGE << "Device does not support PTZ control";
            return;
        }

        // Get PTZ presets
        loadPresets();

        LOGI << "PTZ control initialized for " << device_->getName();
    }

    void performPTZOperations() {
        // Absolute positioning
        moveToPosition(0.5f, 0.0f, 0.3f);  // Pan=50%, Tilt=0%, Zoom=30%

        std::this_thread::sleep_for(std::chrono::seconds(2));

        // Relative movement
        moveRelative(0.1f, 0.1f, 0.0f);    // Small pan and tilt adjustment

        std::this_thread::sleep_for(std::chrono::seconds(2));

        // Continuous movement
        startContinuousMovement(0.2f, 0.0f, 0.0f);  // Slow pan right

        std::this_thread::sleep_for(std::chrono::seconds(5));

        // Stop movement
        stopMovement();

        // Go to preset position
        gotoPreset("Home");
    }

    void moveToPosition(float pan, float tilt, float zoom) {
        auto result = device_->moveAbsolute(pan, tilt, zoom);
        if (result) {
            LOGI << "PTZ moved to position - Pan: " << pan 
                 << ", Tilt: " << tilt << ", Zoom: " << zoom;
        } else {
            LOGE << "PTZ absolute move failed: " << result.error().message();
        }
    }

    void moveRelative(float panDelta, float tiltDelta, float zoomDelta) {
        auto result = device_->moveRelative(panDelta, tiltDelta, zoomDelta);
        if (result) {
            LOGI << "PTZ relative move completed";
        }
    }

    void startContinuousMovement(float panVel, float tiltVel, float zoomVel) {
        auto result = device_->moveContinuous(panVel, tiltVel, zoomVel);
        if (result) {
            LOGI << "PTZ continuous movement started";
        }
    }

    void stopMovement() {
        auto result = device_->stopMovement();
        if (result) {
            LOGI << "PTZ movement stopped";
        }
    }

    void createPreset(const std::string& name) {
        auto result = device_->setPreset(name);
        if (result) {
            LOGI << "Created PTZ preset: " << name;
            loadPresets();  // Refresh preset list
        }
    }

    void gotoPreset(const std::string& name) {
        // Find preset by name
        auto it = std::find_if(presets_.begin(), presets_.end(),
            [&name](const PresetInfo& preset) {
                return preset.name == name;
            });

        if (it != presets_.end()) {
            auto result = device_->gotoPreset(it->token);
            if (result) {
                LOGI << "Moved to preset: " << name;
            }
        } else {
            LOGE << "Preset not found: " << name;
        }
    }

private:
    OnvifDeviceImpl* device_ = nullptr;
    std::vector<PresetInfo> presets_;

    void loadPresets() {
        auto presets = device_->getPresets();
        if (presets) {
            presets_ = presets.value();
            LOGI << "Loaded " << presets_.size() << " PTZ presets";

            for (const auto& preset : presets_) {
                LOGI << "  Preset: " << preset.name << " (" << preset.token << ")";
            }
        }
    }
};

Complete ONVIF Integration with Lua Scripting

-- Complete ONVIF integration for surveillance system
local onvif = api.factory.onvif.create(instance, "surveillance_onvif")
local video = api.factory.videoreader.create(instance, "onvif_video")

-- ONVIF device management
local devices = {}
local activeStreams = {}

-- Discover and initialize ONVIF devices
function initializeONVIFSystem()
    print("Initializing ONVIF surveillance system")

    -- Configure discovery parameters
    local discoveryConfig = {
        timeout = 15000,
        probe_interval = 60000,
        device_filters = {"NetworkVideoTransmitter"},
        scope_filters = {"onvif://www.onvif.org/Profile/Streaming"}
    }

    -- Discover devices
    local discoveredDevices = onvif:discoverDevices(discoveryConfig)

    if discoveredDevices and #discoveredDevices > 0 then
        print("Discovered " .. #discoveredDevices .. " ONVIF devices")

        for _, deviceInfo in ipairs(discoveredDevices) do
            connectToONVIFDevice(deviceInfo)
        end
    else
        print("No ONVIF devices discovered")
    end
end

-- Connect to individual ONVIF device
function connectToONVIFDevice(deviceInfo)
    local device = onvif:createDevice(deviceInfo)

    -- Set credentials (could be from configuration)
    device:setCredentials("admin", "admin123")

    -- Populate device information
    local success = device:populate()
    if success then
        local deviceId = device:getUuid()
        devices[deviceId] = device

        print("Connected to ONVIF device:", device:getName())
        print("  Manufacturer:", device:getManufacturer())
        print("  Model:", device:getModel())
        print("  IP:", deviceInfo.ip_address)

        -- Configure device streams
        configureDeviceStreams(device)

        -- Setup PTZ control if available
        if device:hasPTZSupport() then
            setupPTZControl(device)
        end

        -- Setup event subscription
        setupEventSubscription(device)

    else
        print("Failed to connect to device:", deviceInfo.name or deviceInfo.ip_address)
    end
end

-- Configure video streams for device
function configureDeviceStreams(device)
    local streams = device:getStreams()
    local deviceId = device:getUuid()

    print("Configuring streams for device:", device:getName())

    -- Find best quality stream
    local bestStream = nil
    local maxResolution = 0

    for profileToken, stream in pairs(streams) do
        local resolution = stream.width * stream.height
        print("  Stream: " .. stream.name .. " (" .. stream.width .. "x" .. stream.height .. " @ " .. stream.framerate .. "fps, " .. stream.encoding .. ")")

        if resolution > maxResolution then
            maxResolution = resolution
            bestStream = stream
        end
    end

    -- Configure video reader for best stream
    if bestStream then
        local streamUri = device:getStreamUri(bestStream.token)
        if streamUri then
            -- Configure video reader
            local videoConfig = {
                uri = streamUri,
                transport = "tcp",
                timeout = 30000,
                reconnect = true,
                buffer_size = "1MB"
            }

            local videoReader = api.factory.videoreader.create(
                instance, "onvif_stream_" .. deviceId
            )
            videoReader:configure(videoConfig)
            videoReader:openUri(streamUri)

            activeStreams[deviceId] = {
                device = device,
                stream = bestStream,
                reader = videoReader,
                uri = streamUri
            }

            print("Configured video stream:", streamUri)
        end
    end
end

-- Setup PTZ control for camera
function setupPTZControl(device)
    local deviceId = device:getUuid()

    -- Load presets
    local presets = device:getPresets()
    if presets and #presets > 0 then
        print("PTZ presets for", device:getName() .. ":")
        for _, preset in ipairs(presets) do
            print("  Preset:", preset.name, "(", preset.token, ")")
        end
    end

    -- Create PTZ control interface
    -- Implement PTZ patrol in your main processing loop
    -- Use frame counters or time checks for periodic patrol
    -- Example: Store last patrol time and check elapsed
end

-- Perform PTZ patrol sequence
function performPTZPatrol(device)
    local presets = device:getPresets()
    if presets and #presets > 1 then
        -- Cycle through presets
        local currentTime = api.system.getCurrentTime()
        local presetIndex = (math.floor(currentTime / 30) % #presets) + 1
        local preset = presets[presetIndex]

        device:gotoPreset(preset.token)
        print("PTZ patrol - moved to preset:", preset.name)
    end
end

-- Setup event subscription
function setupEventSubscription(device)
    local deviceId = device:getUuid()

    -- Subscribe to motion detection events
    device:subscribeToEvents({
        "tns1:VideoSource/MotionAlarm",
        "tns1:Device/Trigger/DigitalInput"
    }, function(event)
        handleONVIFEvent(deviceId, event)
    end)

    print("Event subscription configured for:", device:getName())
end

-- Handle ONVIF events
function handleONVIFEvent(deviceId, event)
    local device = devices[deviceId]

    print("ONVIF Event [" .. device:getName() .. "]: " .. event.type .. " at " .. event.timestamp)

    -- Process specific event types
    if event.type == "MotionAlarm" then
        handleMotionDetection(deviceId, event)
    elseif event.type == "DigitalInput" then
        handleDigitalInput(deviceId, event)
    end
end

-- Handle motion detection events
function handleMotionDetection(deviceId, event)
    local streamInfo = activeStreams[deviceId]
    if streamInfo then
        -- Move PTZ to motion area if available
        if event.region and streamInfo.device:hasPTZSupport() then
            local pan = event.region.center_x - 0.5  -- Convert to PTZ coordinates
            local tilt = 0.5 - event.region.center_y

            streamInfo.device:moveAbsolute(pan, tilt, 0.0)
            print("PTZ moved to motion region")
        end

        -- Trigger recording or alerting
        triggerMotionAlert(deviceId, event)
    end
end

-- System monitoring and health check
function monitorONVIFSystem()
    -- Implement periodic health checks in main loop
    -- Use os.time() to track last check time
    local function performHealthCheck()
        for deviceId, streamInfo in pairs(activeStreams) do
            local device = streamInfo.device

            -- Check device connectivity
            local state = device:getState()
            if state ~= "Connected" then
                print("Device disconnected:", device:getName())
                -- Attempt reconnection
                reconnectDevice(deviceId)
            end

            -- Check stream health
            local reader = streamInfo.reader
            if reader and not reader:isConnected() then
                print("Stream disconnected for:", device:getName())
                -- Attempt stream reconnection
                reader:openUri(streamInfo.uri)
            end
        end
    end)
end

-- Initialize the system
initializeONVIFSystem()
monitorONVIFSystem()

print("ONVIF surveillance system initialized")

Best Practices

Network Configuration

  • Multicast Support: Ensure network infrastructure supports UDP multicast for device discovery
  • Firewall Rules: Configure appropriate firewall rules for ONVIF communication ports
  • Network Segmentation: Use dedicated VLAN for IP cameras when possible
  • Bandwidth Management: Monitor and manage network bandwidth for video streams

Security Considerations

  • Authentication: Always use strong passwords and digest authentication
  • SSL/TLS: Enable HTTPS when supported by devices
  • Network Security: Secure camera network with appropriate access controls
  • Credential Management: Store credentials securely and rotate regularly

Performance Optimization

  • Connection Pooling: Reuse SOAP connections when possible
  • Timeout Configuration: Set appropriate timeouts for network operations
  • Stream Selection: Choose optimal stream profiles based on requirements
  • Event Filtering: Filter events to reduce processing overhead

Integration Guidelines

  • Device Compatibility: Test with specific camera models for compatibility
  • Profile Support: Verify ONVIF profile support (Profile S, Profile T, etc.)
  • Capability Discovery: Use capability discovery to determine available features
  • Error Handling: Implement robust error handling for network failures

Troubleshooting

Common Issues

Discovery Problems

// Check multicast connectivity
if (!checkMulticastSupport()) {
    LOGE << "Multicast not supported. Check network configuration.";
    // Try unicast discovery as fallback
    performUnicastDiscovery();
}

// Verify network interface
if (!checkNetworkInterface()) {
    LOGE << "Network interface not available for discovery.";
    return;
}

Authentication Failures

  • Wrong Credentials: Verify username and password
  • Authentication Method: Try different authentication methods (basic vs. digest)
  • Time Synchronization: Ensure device and client clocks are synchronized
  • Nonce Issues: Check nonce generation and validation

Stream Connection Issues

  • Network Connectivity: Verify network path to device
  • Stream URI: Validate stream URI format and accessibility
  • Transport Protocol: Try different transport protocols (TCP, UDP, HTTP)
  • Codec Support: Ensure codec compatibility

PTZ Control Problems

  • Capability Check: Verify PTZ capabilities are supported
  • Coordinate System: Check PTZ coordinate system and ranges
  • Speed Limits: Respect device-specific speed and position limits

Debugging Tools

// ONVIF diagnostics
void diagnoseONVIFConnectivity(OnvifDeviceImpl* device) {
    // Test basic connectivity
    if (!testHTTPConnectivity(device->getXaddr())) {
        LOGE << "HTTP connectivity failed to " << device->getXaddr();
    }

    // Test SOAP communication
    if (!testSOAPCommunication(device)) {
        LOGE << "SOAP communication failed";
    }

    // Verify capabilities
    auto caps = device->getCapabilities();
    if (caps) {
        LOGI << "Device Capabilities:";
        for (const auto& [key, value] : caps->getMap()) {
            LOGI << "  " << key << ": " << value.toString();
        }
    }
}

Integration Examples

Enterprise Video Management System

// Complete ONVIF-based video management system
class ONVIFVideoManagementSystem {
public:
    void initialize() {
        // Initialize discovery and device management
        initializeDiscovery();

        // Setup device monitoring
        startDeviceMonitoring();

        // Initialize stream management
        initializeStreamManager();

        // Setup event processing
        initializeEventProcessor();
    }

    void processVideoFeeds() {
        for (auto& [deviceId, deviceInfo] : managedDevices_) {
            if (deviceInfo.streamReader && deviceInfo.streamReader->isConnected()) {
                auto frame = deviceInfo.streamReader->readFrame();
                if (frame) {
                    processFrameWithAI(deviceId, frame.value());
                }
            }
        }
    }

private:
    struct ManagedDevice {
        std::unique_ptr<OnvifDeviceImpl> device;
        std::unique_ptr<VideoReader> streamReader;
        std::string streamUri;
        OnvifDeviceState lastState;
        std::chrono::steady_clock::time_point lastHealthCheck;
    };

    std::map<std::string, ManagedDevice> managedDevices_;
    std::unique_ptr<WSDiscoveryImpl> discovery_;

    void initializeDiscovery() {
        discovery_ = std::make_unique<WSDiscoveryImpl>();

        // Periodic discovery
        discoveryTimer_ = std::make_unique<Timer>([this]() {
            performPeriodicDiscovery();
        }, std::chrono::minutes(5));
    }

    void processFrameWithAI(const std::string& deviceId, const VideoFrame& frame) {
        // AI processing integration
        auto detections = aiProcessor_->processFrame(frame);

        // Event generation based on detections
        if (!detections.empty()) {
            generateSmartEvents(deviceId, detections);
        }
    }
};

See Also