繁体   English   中英

C# 中的 Onvif 事件订阅

[英]Onvif Event Subscription in C#

我正在用 C# 实现一个 ipCamera/编码器管理系统。 该系统将管理来自多个供应商的多个 ipCameras 和/或编码器。 使用 Onvif 而不是关闭每个 ipcamera 或编码器 sdk 将是一个好处。

管理系统的关键概念之一是侦听来自摄像机的事件,例如运动检测事件。 Onvif 通过使用 ws-basenotification 或拉式支持来支持这一点。 我不喜欢拉,所以我将在 Onvif(Onvif 规范 9.1)中使用 ws-basenotification 支持。

我已成功订阅 Sony SNC-RH164、Bosh VIP X1 XF IVA 和 Acti TCD2100。

我的问题是:我没有从任何设备收到任何通知。 任何人都可以看到我做错了什么或给我一些关于如何从设备获取通知的指示。 我的电脑与设备在同一个子网上。 我的防火墙已关闭以进行测试。

我的测试控制台应用程序启动 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();
        }

我的 managerClass 将在构造函数中初始化我的 NotificationConsumer 接口。

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

我的 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; }
}

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>

添加设备方法

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;
        }

    }

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;
        }
    }

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;

    }

我认为问题在于,您的通知使用者使用AddressingVersion.None ,而来自 ONVIF 设备的通知根据 WS-Addressing 1.0 进行格式化。 尝试更改 GetCustomBinding 方法的以下行:

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

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

我在 GrandStream 相机上遇到了这个问题。 我不得不使用摄像头网络用户界面为其添加一个或多个检测区域,以使其检测运动。

暂无
暂无

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

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