简体   繁体   English

C# 中的 Onvif 事件订阅

[英]Onvif Event Subscription in C#

I am implementing an ipCamera/encoder management system in C#.我正在用 C# 实现一个 ipCamera/编码器管理系统。 The system will manage multiple ipCameras and/or encoders from a multiple vendors.该系统将管理来自多个供应商的多个 ipCameras 和/或编码器。 Using Onvif instead off each ipcamera or encoders sdk will be a benefit.使用 Onvif 而不是关闭每个 ipcamera 或编码器 sdk 将是一个好处。

One of the key concepts of the management system is to listen on events, such as motion detection events, from the cameras.管理系统的关键概念之一是侦听来自摄像机的事件,例如运动检测事件。 Onvif supports this by use of the ws-basenotification or a pull type support. Onvif 通过使用 ws-basenotification 或拉式支持来支持这一点。 I don't like pull, so I will use ws-basenotification support in Onvif (Onvif spec 9.1).我不喜欢拉,所以我将在 Onvif(Onvif 规范 9.1)中使用 ws-basenotification 支持。

I have successfully added subscription to a Sony SNC-RH164, Bosh VIP X1 XF IVA and Acti TCD2100.我已成功订阅 Sony SNC-RH164、Bosh VIP X1 XF IVA 和 Acti TCD2100。

My problem is: I don't get any notifications from any of the devices.我的问题是:我没有从任何设备收到任何通知。 Can anyone see what I'm doing wrong or give my som pointers on how to get notifications from devices.任何人都可以看到我做错了什么或给我一些关于如何从设备获取通知的指示。 My pc is on the same subnet as the devices.我的电脑与设备在同一个子网上。 And my firewall is turned off for the test.我的防火墙已关闭以进行测试。

My test console app initiating the OnvifManager class.我的测试控制台应用程序启动 OnvifManager 类。

using (var manager = new OnvifManager())
        {
            //manager.ScanForDevices();
            var sonyDevice = new OnvifClassLib.OnvifDevice
            {
                OnvifDeviceServiceUri = new Uri(@"http://192.168.0.101/onvif/device_service"),

            };
            manager.AddDevice(sonyDevice);
            manager.AddEventSubscription(sonyDevice, "PT1H");

            var boshDevice = new OnvifClassLib.OnvifDevice
            {
                OnvifDeviceServiceUri = new Uri(@"http://192.168.0.102/onvif/device_service"),


            };
            manager.AddDevice(boshDevice);
            manager.AddEventSubscription(boshDevice, string.Empty);

            var actiDevice = new OnvifClassLib.OnvifDevice
            {
                OnvifDeviceServiceUri = new Uri(@"http://192.168.0.103/onvif/device_service"),
                UserName = "uid",
                Password = "pwd"

            };
            manager.AddDevice(actiDevice);
            manager.AddEventSubscription(actiDevice);

            Console.WriteLine("Waiting...");
            Console.Read();
        }

My managerClass will in the Constructor initialize my NotificationConsumer interface.我的 managerClass 将在构造函数中初始化我的 NotificationConsumer 接口。

private void InitializeNotificationConsumerService()
    {
        _notificationConsumerService = new NotificationConsumerService();
        _notificationConsumerService.NewNotification += NotificationConsumerService_OnNewNotification;
        _notificationConsumerServiceHost = new ServiceHost(_notificationConsumerService);
        _notificationConsumerServiceHost.Open();
    }

My NotificationConsumer interface implementation.我的 NotificationConsumer 接口实现。

 /// <summary>
/// The client reciever service for WS-BaseNotification
/// </summary>
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class NotificationConsumerService : NotificationConsumer
{

    public event EventHandler<EventArgs<Notify1>> NewNotification;

    /// <summary>
    /// Notifies the specified request.
    /// </summary>
    /// <param name="request">The request.</param>
    /// <remarks>A </remarks>
    public void Notify(Notify1 request)
    {
        var threadSafeEventHandler = NewNotification;
        if (threadSafeEventHandler != null)
            threadSafeEventHandler.Invoke(this, new EventArgs<Notify1>(request));
    }
}

public class EventArgs<T> : EventArgs
{

    public EventArgs(T data)
    {
        Data = data;
    }

    public T Data { get; set; }
}

The config for NotificationConsumerService NotificationConsumerService 的配置

<services>
  <service name="OnvifClassLib.NotificationConsumerService">
    <endpoint address="" binding="customBinding" bindingConfiguration="CustomBasicHttpBinding"
      name="CustomHttpBinding" contract="EventService.NotificationConsumer" />
    <host>
      <baseAddresses>
        <add baseAddress="http://192.168.0.10:8080/NotificationConsumerService" />
      </baseAddresses>
    </host>
  </service>
</services>
<bindings>      
  <customBinding>
    <binding name="CustomBasicHttpBinding">
      <textMessageEncoding messageVersion="Soap12">
        <readerQuotas maxStringContentLength="80000" />
      </textMessageEncoding>
      <httpTransport maxReceivedMessageSize="800000" maxBufferSize="800000" />
    </binding>        
  </customBinding>      
</bindings>

The AddDevice method添加设备方法

public void AddDevice(OnvifDevice device)
    {
        LoadCapabilities(device);
        OnvifDevices.Add(device);
    }


internal void LoadCapabilities(OnvifDevice onvifDevice)
    {
        if (onvifDevice.OnvifDeviceServiceUri == null)
            return;
        if (onvifDevice.DeviceClient == null)
            LoadDeviceClient(onvifDevice);
        try
        {

            onvifDevice.Capabilities = onvifDevice.DeviceClient.GetCapabilities(new[] { OnvifClassLib.DeviceManagement.CapabilityCategory.All });

        }
        catch (Exception ex)
        {
            Console.Write(ex.ToString());
        }


    }
private void LoadDeviceClient(OnvifDevice onvifDevice)
    {

        if (onvifDevice.OnvifDeviceServiceUri == null)
            return;

        var serviceAddress = new EndpointAddress(onvifDevice.OnvifDeviceServiceUri.ToString());
        var binding = GetBindingFactory(onvifDevice);
        onvifDevice.DeviceClient = new OnvifClassLib.DeviceManagement.DeviceClient(binding, serviceAddress);
        if (!string.IsNullOrWhiteSpace(onvifDevice.UserName))
        {
            onvifDevice.DeviceClient.ClientCredentials.UserName.UserName = onvifDevice.UserName;
            onvifDevice.DeviceClient.ClientCredentials.UserName.Password = onvifDevice.Password;
        }

    }

The AddEventSubscription method AddEventSubscription 方法

 public void AddEventSubscription(OnvifDevice onvifDevice, string initialTerminationTime = "PT2H")
    {
        if (onvifDevice.Capabilities.Events == null)
            throw new ApplicationException("The streamer info does not support event");
        try
        {


            if (onvifDevice.NotificationProducerClient == null)
                LoadNotificationProducerClient(onvifDevice);

            XmlElement[] filterXml = null;


            var subScribe = new Subscribe()
            {
                ConsumerReference = new EndpointReferenceType
                {
                    Address = new AttributedURIType { Value = _notificationConsumerServiceHost.BaseAddresses.First().ToString() },

                }

            };
            if (!string.IsNullOrWhiteSpace(initialTerminationTime))
                subScribe.InitialTerminationTime = initialTerminationTime;


            onvifDevice.SubscribeResponse = onvifDevice.NotificationProducerClient.Subscribe(subScribe);

            Console.WriteLine("Listening on event from {0}", onvifDevice.NotificationProducerClient.Endpoint.Address.Uri.ToString());
        }

        catch (FaultException ex)
        {
            Console.Write(ex.ToString());
        }
        catch (Exception ex)
        {
            Console.Write(ex.ToString());
        }
    }

private void LoadNotificationProducerClient(OnvifDevice onvifDevice)
    {
        var serviceAddress = new EndpointAddress(onvifDevice.Capabilities.Events.XAddr.ToString());
        var binding = GetBindingFactory(onvifDevice);
        onvifDevice.NotificationProducerClient = new OnvifClassLib.EventService.NotificationProducerClient(binding, serviceAddress);
        if (!string.IsNullOrWhiteSpace(onvifDevice.UserName))
        {
            onvifDevice.NotificationProducerClient.ClientCredentials.UserName.UserName = onvifDevice.UserName;
            onvifDevice.NotificationProducerClient.ClientCredentials.UserName.Password = onvifDevice.Password;
        }
    }

Bindings for Soap12 Soap12 的绑定

private Binding GetBindingFactory(OnvifDevice onvifDevice)
    {            
        return GetCustomBinding(onvifDevice);
    }
private Binding GetCustomBinding(OnvifDevice onvifDevice)
    {
        HttpTransportBindingElement transportElement = new HttpTransportBindingElement();

        if (!string.IsNullOrWhiteSpace(onvifDevice.UserName))
            transportElement.AuthenticationScheme = AuthenticationSchemes.Basic;


        var messegeElement = new TextMessageEncodingBindingElement();
        messegeElement.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None);

        var binding = new CustomBinding(messegeElement, transportElement);
        binding.SendTimeout = new TimeSpan(0, 10, 0);
        return binding;

    }

I think the problem is, that your notification consumer uses AddressingVersion.None , while the notifications from the ONVIF device are formatted according to WS-Addressing 1.0.我认为问题在于,您的通知使用者使用AddressingVersion.None ,而来自 ONVIF 设备的通知根据 WS-Addressing 1.0 进行格式化。 Try to change the following line of your GetCustomBinding method:尝试更改 GetCustomBinding 方法的以下行:

messegeElement.MessageVersion = MessageVersion.CreateVersion(
    EnvelopeVersion.Soap12, AddressingVersion.None);

to

messegeElement.MessageVersion = MessageVersion.CreateVersion(
    EnvelopeVersion.Soap12, AddressingVersion.WSAddressing10);

I had this problem with a GrandStream camera.我在 GrandStream 相机上遇到了这个问题。 I had to add one or more detection zones to it using the camera web UI to get it to detect motion.我不得不使用摄像头网络用户界面为其添加一个或多个检测区域,以使其检测运动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM