.. _camera-notifications-label: Notifications ~~~~~~~~~~~~~ .. image:: notification-events.png :width: 50% :alt: Overview of Camera- and Property-Events :align: center :class: only-light .. content-if:: :format: html .. image:: notification-events-dark.png :width: 50% :alt: Overview of Camera- and Property-Events :align: center :class: only-dark Events happening in the camera can generate *notifications* that are received on the :term:`Host computer`. These can be categorized in various ways, each indicating what payload data you can expect to receive with the notification. .. note:: The notification API has changed from CameraSDK release version 2.0 to 3.0! If you previously worked with the notifications APIs in version 2.0, you will find that the API has completely changed in version 3.0. And that these are breaking changes! See :ref:`3_0_migration_guide-label` All notifications have to be enabled for the events to generate notifications. These notifications can be enabled or disabled at any time. To listen for notifications, create an instance of the ``Listener`` class: .. code-tabs:: .. include-tab:: ../../labels/cppListener :language: cpp :title: C++ .. include-tab:: ../../labels/csListener :language: csharp :title: C# The ``Listener`` class acts as a *notification central*, where notifications from enabled events are received. You receive the incoming notifications by calling the *blocking* method: ``WaitForNotification`` on the ``Listener`` object. Since it is blocking, it should be called from a separate thread (see :ref:`camera-begin-notification-label`). A thread listening for notifications should be offloaded by using other threads to handle "reactions" to the notifications (see :ref:`thread-model-label`). If no thread is blocked inside ``WaitForNotification``, notifications are queued in a first-in, first-out (FIFO) manner. The next call to ``WaitForNotification`` will return the next waiting notification, in order. This way, notifications are not lost. Multiple notifications can be enabled per ``Listener`` instance. Furthermore, multiple ``Listener`` instances can be created as needed. Each instance of ``Listener`` acts independently of other ``Listener`` instances. You can create multiple ``Listener`` objects that are set up to receive the notifications originating from the same events. In this case, each listener will actually receive the *same* notification object. That is why notification objects are delivered inside a ``std::shared_ptr`` object in C++. .. _camera-sdk-events-label: Event Categories ---------------- All notification types belong to a category. These denote the area the notification belongs to, and define what payload data is included in the notification object. The following section provides a more detailed description of the categories. SDK Events ^^^^^^^^^^ The ``SdkEvent`` category describes a change at the CameraSDK-level. For instance, if the CameraSDK discovers a USB-connected camera, a notification of the type "``SdkEvent``" is generated. An example of listening for the event of a camera being found (``CameraFound``) is shown below: .. code-tabs:: .. include-tab:: ../../labels/cppListenerCameraFound :language: cpp :title: C++ .. include-tab:: ../../labels/csListenerCameraFound :language: csharp :title: C# *SDK Events* will tell you when USB cameras are discovered and when they disappear. The ``CameraFound`` notification and its opposite ``CameraRemoved``, inform you about the visible USB cameras. It does not matter whether you are connected (camera is *opened*) or not. .. caution:: TCP/IP cameras are *not discovered*. You will not receive any *found* or *removed* notifications from TCP/IP cameras. Camera Events ^^^^^^^^^^^^^ The ``CameraEvent`` category of notifications reflects events in a connected (and opened) camera. For example, if the camera delivers an image to the SDK host. This can be seen in the example below: .. code-tabs:: .. include-tab:: ../../labels/cppListenerImageReady :language: cpp :title: C++ .. include-tab:: ../../labels/csListenerImageReady :language: csharp :title: C# The *Camera event* category is further divided into 4 sub-categories: *image receiving*, *connection*, *LiveView* & *property lifetime*. The next few sections will examine these sub-categories in more detail. .. _image-receiving-notifications-label: Image Receiving """"""""""""""" These are camera events that provide progress reporting on the image transfer between the camera and the host. When the camera starts transferring an image, the ``ImageTransferBegin`` event is received. At rate-limited intervals, the SDK will provide the ``TransferProgress`` event until the entire image is present in SDK memory. Then ``ImageReady`` is received, and the image is included within that notification object. Connection """""""""" The ``Disconnected`` camera event indicates that the connection (USB / TCP) has been lost. This is either by intention or as a result of a link error. You will receive the ``Disconnect`` event after calling ``Close`` on the camera. Similarly, you will receive the same event if the USB or network cable is unplugged suddenly. The ``Disconnect`` event itself cannot tell you which scenario it originates from. .. caution:: TCP sockets on specific platforms are very forgiving and will try to keep the TCP connection open for several minutes. If you are on a poor-quality Wifi, this is probably a desired behavior. On the other hand, if you are on cabled and switched Ethernet, then even an unplugged cable is not enough to interrupt the established TCP connection. LiveView """""""" The LiveView-related camera events will indicate when LiveView is started or stopped. Also, the ``NewLiveViewImage`` *event type* provides you with the new LiveView image inside the notification object. If you are working with an IQ4 digital back, starting LiveView on the camera's display will *not* trigger any LiveView notifications in the SDK. LiveView notifications received in the SDK are when the SDK itself uses LiveView. Property Lifetime """"""""""""""""" These are camera events that advertise about *camera properties* that appear or disappear. The camera can change *mode*, which may trigger new properties to become available. Likewise, changing a *mode* on the camera may cause some properties to disappear. Property Events ^^^^^^^^^^^^^^^ A ``PropertyEvent``-type notification is triggered upon the changing of a value in a property, such as the "aperture" being set to "5.6". To receive notifications about property events, notifications have to be enabled for the desired property (e.g., "aperture" or "ISO"). When enabling notifications for a property, a notification arrives when the property changes its *value*. An example of how to listen for a change in the "aperture"-property can be seen below: .. code-tabs:: .. include-tab:: ../../labels/cppListenerAperture :language: cpp :title: C++ .. include-tab:: ../../labels/csListenerAperture :language: csharp :title: C# .. note:: An attempt to set the value to its current value (e.g., "5.6" --> "5.6") will not generate a notification. Specification Change Events """"""""""""""""""""""""""" By default, a *property event* denotes a change in the property's value. However, the property's *specification* (``PropertySpec``) may also change. These changes could be the *read-only* state or a change in the list of valid values (the *value map*). Just as you can listen for *value* changes, you can likewise listen for *specification* changes - that does not change the property's value. Arriving *specification* change notifications are of the ``SpecificationChange`` type, whereas *property value* change notifications are of type ``Property``. To enable notifications for *specification* changes, you use the same ``EnableNotification`` method, but provide a 3rd argument: .. code-tabs:: .. code-tab:: cpp :title: C++ listener.EnableNotification(camera, 1003, true); // 1003 is Aperture .. code-tab:: csharp :title: C# listener.EnableNotification(camera, 1003, isSpecificationChange: true); // 1003 is Aperture This third and optional argument defaults to ``false``. If you explicitly set it to ``true`` you will receive *only* specification state changes for the given *property id* and camera. You can enable both property value and specification change notifications by making two calls to the method—one for each type. They can exist independently of each other. Similarly, you disable specification changes by calling ``DisableNotification`` and providing a 3rd argument set to ``true``: .. code-tabs:: .. code-tab:: cpp :title: C++ listener.DisableNotification(camera, 1003, true); // 1003 is Aperture .. code-tab:: csharp :title: C# listener.DisableNotification(camera, 1003, isSpecificationChange: true); // 1003 is Aperture .. _camera-begin-notification-label: Begin Listening for Notifications --------------------------------- When notifications have been enabled for the desired events, the listening for notifications can begin. A thread must continuously listen for events, regardless of the event type. This thread executes the ``WaitForNotification`` method, as can be seen below: .. code-tabs:: .. include-tab:: ../../labels/cppListenThread :language: cpp :title: C++ .. include-tab:: ../../labels/csListenThread :language: csharp :title: C# Output: (*if the notification was not otherwise handled*):: Notification received: Notification CameraImageReady, CamId: 1, Stop Listening for Notifications -------------------------------- Upon terminating the application, the thread listening for notifications should also terminate. To accomplish this, the CameraSDK has a function to release the thread listening for notifications in the specific ``Listener``, as follows: .. code-tabs:: .. include-tab:: ../../labels/cppWakeUpWaitingThread :language: cpp :title: C++ .. include-tab:: ../../labels/csWakeUpWaitingThread :language: csharp :title: C# Notification Payloads --------------------- Each *notification type* can deliver optional payloads or context data. The ``NotificationEvent`` object defines members that are populated only for specific notification and event types. These members provide contextual information about the notification. The table below lists the available payload members of ``NotificationEvent`` and the conditions that must be met for them to be populated with meaningful values: +---------------------------+-----------------------------+--------------------------------------+ | Member Field | Description | Condition | +===========================+=============================+======================================+ | *ImageId* | The *image id* of the image | All *Image Receiving* sub-category | | | this event relates to | notifications | +---------------------------+-----------------------------+--------------------------------------+ | *CameraId* | The *id* of the camera that | All *Camera* category notifications | | | the notification relates to | | +---------------------------+-----------------------------+--------------------------------------+ | *PropertyId* | The Id of the property that | All ``Property`` typed notifications | | | is changed | | +---------------------------+-----------------------------+--------------------------------------+ | *BasicImageInfo* | The *BasicImageInfo* object | Present only for notifications of | | | included in the notification| ``CameraImageBasicImageInfo`` type | +---------------------------+-----------------------------+--------------------------------------+ | *Preview* | The *Preview* image object | Present only for notifications of | | | included in the notification| ``CameraPreviewReady`` type | +---------------------------+-----------------------------+--------------------------------------+ | *Tile* | The *Tile* image object | Present only for notifications of | | | included in the notification| ``CameraTileReady`` type | +---------------------------+-----------------------------+--------------------------------------+ | *LiveView* | The *LiveView* image object | Present only for notifications of | | | included in the notification| ``CameraNewLiveViewImage`` type | +---------------------------+-----------------------------+--------------------------------------+ | *FullImage* | The *FullImage* IIQ file | Present only for notifications of | | | included in the notification| ``CameraImageReady`` type | +---------------------------+-----------------------------+--------------------------------------+ | *StoredImageHandle* | The handle to the *in | Present for ``CameraImageAdded``, | | | camera* image | ``...Added`` and ``...Edited`` types | +---------------------------+-----------------------------+--------------------------------------+ | *CameraInfo* | A small *struct* describing | ``SdkEvent`` category notifications, | | | the cameras connection type,| where type is either ``CameraFound`` | | | IP, serial, etc. | or ``CameraRemoved`` | +---------------------------+-----------------------------+--------------------------------------+ | *TransferProgressPercent* | A progress status for image | *CameraEvent* category events, | | | transfers, in percent. | where the sub-category is | | | | ``ImageTransfer`` | +---------------------------+-----------------------------+--------------------------------------+ | *ImageFilename* | The filename of the image | Any of the *Transfer* sub-category | | | that was transferred | notifications | +---------------------------+-----------------------------+--------------------------------------+ Catch All Listeners ------------------- The ``Listener`` class has a special *catch-all* state that enables receiving every single notification posted by the SDK, without the need to call ``EnableNotification`` for each notification first. Notifications are received for *all* notification types, for every event, across all open cameras. Additionally, notifications will be enabled for properties that are not yet visible (due to the camera's state). If you enable the *catch all* state on a ``Listener`` before you open the first camera, you will receive the (*CameraEvent* type) notification ``CameraEventPropertyAdded``, when you open any cameras. To enable catch-all on a ``Listener`` instance: .. code-tabs:: .. code-tab:: cpp :title: C++ listener.EnableCatchAllNotifications(); .. code-tab:: csharp :title: C# listener.EnableCatchAllNotifications(); Disable Catch All State ^^^^^^^^^^^^^^^^^^^^^^^ The *catch-all* state can be disabled at any time by calling: .. code-tabs:: .. code-tab:: cpp :title: C++ listener.DisableCatchAllNotifications(); .. code-tab:: csharp :title: C# listener.DisableCatchAllNotifications(); This effectively deactivates the delivery of all notification types to the ``Listener`` instance. The instance's state is returned to normal, where only enabled notifications will be delivered. (The ones enabled by calling ``EnableNotification``.) If ``Listener`` already has any explicitly enabled notifications, these will be preserved. Thus, these are not affected by disabling the *catch-all* state. .. warning:: Be aware that disabling the *catch-all* state does *not* clear the listeners' queue of incoming notifications. Calls to ``WaitForNotification`` might return notifications queued up before the call to ``DisableCatchAllNotifications``.