Menu

onvifdm library - trouble with Subscribe

2012-04-02
2013-06-27
  • Daniel Lesage

    Daniel Lesage - 2012-04-02

    I'm developing an application that needs to receive motion events from AXIS cameras.

    I've downloaded version 1.8.5495 from the Synesis website, and was able to compile and use the provided ui applications; my cameras show up, and I do see motion events in the ui.

    Actually using the library in my own source is another story entirely. I'm having a devil of a time figuring out what part of the code is from the library itself, and what part is ui-specific.

    Here's my first problem. I'm trying to setup a session subscription like this (strongly inspired from your own "DeviceViewModel.cs"), but neither of my lambdas ever gets invoked. Can you provide me with any hints?

    Dan.

    NvtSessionFactory _sessionFactory = new NvtSessionFactory(null);

    Uri camUri = new Uri { CamUri };

    _sessionFactory.CreateSession(camUri)
      .ObserveOnCurrentDispatcher()
      .Subscribe(isession =>
      {
      System.Diagnostics.Trace.WriteLine(isession.deviceUri.ToString());
      }, err =>
      {
      dbg.Error(err);
      });

     
  • Andrey Vrana

    Andrey Vrana - 2012-04-03

    Hi.
    First of all - please update your sources from the sourceforge - the latest available version is "1.8.5726"

    There are two possible ways to create session
    One-assync (if you are using several Uris.) And sincronouse - if you are using the only one uri.

    the syncronuse way is:

    NvtSessionFactory factory = new NvtSessionFactory (Account); / / Is you want to use anonynous you need to call NvtSessionFactory (null);

    invtSession = factory.CreateSession (uri);

    this will create session in any case if it is possible to connect to device.

    By the way, You can connect to me by skype, to improve the speed of communication (skype: andreyvrana)

    Regards,
    Andrey Vrana

     
  • Daniel Lesage

    Daniel Lesage - 2012-04-03

    Hello Andrey.

    First of all, thanks for your help. I wish I could skype you, but it's not allowed here at work.

    I looked at the synchronous version of Subscribe, and it does seem to work, but I am then unable to setup a subscription, since I don't understand the parameters Subscribe() takes, and can't find a sample for

    Dan.

     
  • Daniel Lesage

    Daniel Lesage - 2012-04-03

    Ok, I think I 've got it.

    This is what I ended up with. Does it make sense to you?

    INvtSession session = _sessionFactory.CreateSession(CamUri);
    _facade = new OdmSession(session);
    if (EventSubscriptions != null && !EventSubscriptions.IsDisposed)
    {
    EventSubscriptions.Dispose();
    EventSubscriptions = new CompositeDisposable();
    }

    List<MessageContentFilter> contArray = new List<MessageContentFilter>();
    List<TopicExpressionFilter> topArray = new List<TopicExpressionFilter>();

    EventSubscriptions.Add(
    _facade.GetBaseEvents(8085, topArray, contArray).Subscribe(
    onvifEvent =>
    {
    foreach (var item in onvifEvent.message.Data.SimpleItem)
    {
    OnEvent(item.Name, item.Value);
    }

    }, err =>
    {
    }
    ));

    Dan.

     
  • Andrey Vrana

    Andrey Vrana - 2012-04-03

    Ok, Dan.

    maybe it suitable for You to use e-mail andrey.vrana@gmail.com.
    But anyway, we can continue here.

    var Account = new System.Net.NetworkCredential(devconf.accountName, devconf.accountPassword);
    NvtSessionFactory factory = new NvtSessionFactory(Account);

    Uri uri = new Uri(devUriString); //devUriString == "http://192.168.0.1/onvif/device_service" as an example

    invtSession = factory.CreateSession(uri);

    here an example how to get stream uri:

    var ProfileTokens = invtSession .GetProfiles().RunSynchronously();
    var profile = invtSession .GetProfile(ProfileTokens).RunSynchronously(); //ProfileTokens == token of one of device profiles.

    StreamSetup strSetup = new StreamSetup();
    strSetup.Stream = StreamType.RTPUnicast;
    strSetup.Transport = new Transport();
    strSetup.Transport.Protocol = TransportProtocol.UDP; //as an example of using UDP
    strSetup.Transport.Tunnel = null;

    var strUri = invtSession.GetStreamUri(strSetup, profile ).RunSynchronously();

    at the end You will have th rtsp uri for video stream.

     
    • Maryam

      Maryam - 2013-06-27

      Dear Mr. Andrey

      I used the code to get the stream from an onvif-compliant IP camera but I could not. When I try to build, I get the error:

      "Microsoft.FSharp.Control.FSharpAsync<onvif.services.Profile[]>' does not contain a definition for 'RunSynchronously' and no extension method 'RunSynchronously' accepting a first argument of type Microsoft.FSharp.Control.FSharpAsync<onvif.services.Profile[]>' could be found (are you missing a using directive or an assembly reference?)"

      var ProfileTokens = invtSession .GetProfiles().RunSynchronously();

      Could you please help me in this? More specifically, how can I get the stream from an IP camera and show in a screen?

      Thanks in advance.

       
  • Andrey Vrana

    Andrey Vrana - 2012-04-03

    It would be convenient if you have determined what specific scenario you are interested in.

    Then I could give an example how to use our library.

     
  • Andrey Kolomentsev

    Hi, there are the following methods for receiving events:
            /// <summary>Returns observable which can be used to retrieve events via PullPoint mechanism.</summary>
            member this.GetPullPointEvents():IObservable<OnvifEvent>

            /// <summary>Returns observable which can be used to retrieve events via PullPoint mechanism.</summary>
            /// <param name="topicExpressionFilters">Describe subset of filters, which notification producer should use to filter events.</param>
            /// <param name="messageContentFilters">Describe subset of filters, which notification producer should use to filter events.</param>
            member this.GetPullPointEvents(topicExpressionFilters:seq<TopicExpressionFilter>, messageContentFilters:seq<MessageContentFilter>):IObservable<OnvifEvent>

            /// <summary>Returns observable which can be used to retrieve events via PullPoint mechanism.</summary>
            /// <param name="filters">Describe set of filters, which notification producer should use to filter events.</param>
            member this.GetPullPointEvents(filters:seq<XElement>):IObservable<OnvifEvent>
           
            /// <summary>Returns observable which can be used to retrieve events via PullPoint mechanism.</summary>
            /// <param name="filter">
            /// Describe set of filters, which notification producer should use to filter events.
            /// If null the pullpoint should notify all occurring events to the client.
            /// </param>
            member this.GetPullPointEvents(filter:FilterType):IObservable<OnvifEvent>

            /// <summary>Returns observable which can be used to retrieve events via BaseNotification mechanism.</summary>
            /// <param name="port">Number of tcp port, that will be used to listen for events from subscribtion manager</param>
            member this.GetBaseEvents(port:int):IObservable<OnvifEvent>

            /// <summary>Returns observable which can be used to retrieve events via BaseNotification mechanism.</summary>
            /// <param name="port">Number of tcp port, that will be used to listen for events from subscribtion manager</param>
            /// <param name="topicExpressionFilters">Describe subset of filters, which notification producer should use to filter events. </param>
            /// <param name="messageContentFilters">Describe subset of filters, which notification producer should use to filter events. </param>
            member this.GetBaseEvents(port:int, topicExpressionFilters:seq<TopicExpressionFilter>, messageContentFilters:seq<MessageContentFilter>):IObservable<OnvifEvent>

            /// <summary>Returns observable which can be used to retrieve events via BaseNotification mechanism.</summary>
            /// <param name="port">Number of tcp port, that will be used to listen for events from subscribtion manager</param>
            /// <param name="filters">Describe set of filters, which notification producer should use to filter events. </param>
            member this.GetBaseEvents(port:int, filters:seq<XElement>):IObservable<OnvifEvent>

            /// <summary>Returns observable which can be used to retrieve events via BaseNotification mechanism.</summary>
            /// <param name="port">Number of tcp port, that will be used to listen for events from subscribtion manager</param>
            /// <param name="filter">
            /// Describe set of filters, which notification producer should use to filter events.
            /// If null the notification producer should notify all occurring events to the client.
            /// </param>
            member this.GetBaseEvents(port:int, filter:FilterType):IObservable<OnvifEvent>

     
  • Daniel Lesage

    Daniel Lesage - 2012-04-03

    Hi.

    Thanks to both of you, I managed to get my subscription code working.

    As a final question, is there any way to unsubscribe from notifications?

    Dan.

     
  • Andrey Kolomentsev

    to unsubscribe you just need to call Dispose from IDisposable returned by Subscribe

     
  • Daniel Lesage

    Daniel Lesage - 2012-04-18

    It's me again.

    I thought I had solved all my problems, but now that I'm moving the code to the production environment, motion events are not detected. Both computers are on the same network, running the same code; the firewall is disabled on both.

    Any thoughts?

    Dan.

    Here's my code:

    public void Scan()
    {
    Status = CameraStatus.Ok;

    int listenPort = 8085;
    int.TryParse(EventListeningPort, out listenPort);

    OdmSession facade = new OdmSession(_sessionFactory.CreateSession(CamUri));

    Console.WriteLine(string.Format("Camera {0} Subscribing on port {1}…", Name, listenPort));

    _subscription = facade.GetBaseEvents(listenPort).Subscribe(
    onvifEvent =>
    {
    Console.WriteLine(string.Format("Received ONVIF event"));

    foreach (var item in onvifEvent.message.Data.SimpleItem)
    {
    Console.WriteLine(string.Format("Name is {0} value is {1}", item.Name, item.Value));

    if (item.Name.ToLower() == "motion" && item.Value == "1")
    {
    Console.WriteLine(string.Format("Motion detected on camera {0} (IP {1})", Name, IPAddress));
    Status = CameraStatus.MotionDetected;
    DoneEvent.Set();
    }
    }

    }, err =>
    {
    Console.WriteLine(err);
    Status = CameraStatus.NotResponding;
    DoneEvent.Set();
    }
    );
    Console.WriteLine(string.Format("Subscription done…"));
    }

    Here's the output when testing on my test computer:

    Starting scan for camera "camera1 (Opened)"
    Camera camera1 (Opened) Subscribing on port 8085…
    Subscription done…
    Received ONVIF event
    Name is state value is 0
    Received ONVIF event
    Name is motion value is 1
    Motion detected on camera camera1 (Opened) (IP 192.168.192.90)
    Received ONVIF event
    Name is motion value is 1
    Motion detected on camera camera1 (Opened) (IP 192.168.192.90)
    Received ONVIF event
    Name is motion value is 0
    Received ONVIF event
    Name is motion value is 0

    And the same output on my production machine

    Starting scan for camera "camera1 (Opened)"
    Camera camera1 (Opened) Subscribing on port 8085…
    Subscription done…
    Received ONVIF event
    Name is state value is 0

     
  • Daniel Lesage

    Daniel Lesage - 2012-04-19

    I thinking I might be missing a dependency. Here's what I deploy, on top of my own library:

    onvif.services.dll
    onvif.session.dll
    onvif.utils.dll
    System.Reactive.dll
    utils.bindings.dll
    utils.common.dll
    utils.diagnostics.dll
    utils.fsharp.dll
    utils.linq.dll
    utils.wpf.dll
    utils.xml.dll

    Dan.

     
  • Andrey Kolomentsev

    Here some my suggestions how to find what went wrong. First we need to ensure that all libraries is compatible, they all have to be same version, except System.Reactive, behaviour can be unstable if it is not. After we need to be convinced that subscription is not disposed before we expected, if it is hard to do that by analysing your code, wireshark can help us, we will see unsubscribe request when subscription is disposed. Also we need to check that subscription is rooted, and will not be collected by GC, wireshark can help us here too, in case if subscription working well we should see periodically renew requests from client to nvt's subsription manager, with interval about 60sec. In case if it's not or incoming requests from nvt to client (port 8085) are refused or aborted we can assert that subscription was closed. Hope this will be helpful for you. If not, so kindly provide us additional details to investigate this issue more precisely (wireshark logs or simplified but integral example that reproduce this issue, so we can run it and debug by ourself).

     
  • Andrey Kolomentsev

    Also here is some aspects, that you should take into account when using onvif libraries.
    Add following settings into your app.config file:

    <system.net>
        <settings>
            <!-- 
                follow reccomendation RFC 2616, section 19.3 "Tolerant Applications".
                allow to work with devices that separate headers only with LF.
            -->
            <httpWebRequest useUnsafeHeaderParsing="true"/>
        </settings>
        <connectionManagement>
            <!-- 
                set maximum number of simultaneous http connections per uri, default is 3.
                for normal work of onvif session it should be at least 10
            -->
            <add address = "*" maxconnection = "100" />
        </connectionManagement>
        <authenticationModules>
            <!-- 
                add support for utf encoded username and password contained non-ASCII chars
                for http basic authentication
            -->
            <remove type="System.Net.BasicClient" />
            <add type="utils.UtfBasicAuthenticationModule, utils.common" />
        </authenticationModules>
    </system.net>
    

    somewhere in bootsrapper code, add following:

    //some devices don't understand http header "Expect: 100-Continue"
    ServicePointManager.Expect100Continue = false;
    //accept any certificate for tls connections
    ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, policyErrors) => {
        return true;
    };
    
     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.