Architecture
Working with Messages
A message system is used to communicate within an application. The application sends a number of messages that the plug-in can subscribe to, and the plug-in can also send messages.
A plug-in can make its own messages if it needs to communicate with other plug-ins, whereby only the two plug-ins are involved in that communication. But a plug-in can also utilize the large set of built-in messages that controls the application, or triggers custom events, outputs, Matrix Monitor or camera PTZ presets.
A plug-in can trigger actions and events on items that the plug-in does not fully understand; all it needs to look for is that the item is of the category: Category.TriggerOut item.
All message communication is done via the EnvironmentManager, which again will forward to registered receivers. One message can be sent to multiple receivers.
In the Smart Client environment, the messages are used extensively to notify about mode change, current camera selection as well as used to control many parts of the Smart Client.
The built-in messages have a name convention to assist in understanding which ones are used for issuing commands, and which ones are received as indications. Also, where the data field is filled with a class or structure, it has a similar name as the command.
- Messages ending with "Command" – the sender wants the receiver to perform something
- Messages ending with "Indication" – the sender wants to inform about something, no action required
- Messages ending with "Request" – the sender wants the receiver to return a result
For example, the message with ID "SmartClient.PlaybackCommand" can be sent by a plug-in to instruct the Smart Client to perform a specific playback command. The command to perform is defined by the PlaybackCommandData class, and the message.Data is assigned this class.
EnvironmentManager.Instance.SendMessage(
new VideoOS.Platform.Messaging.Message(
MessageId.SmartClient.PlaybackCommand,
new PlaybackCommandData() {
Command=PlaybackData.PlayForward,
Speed = _speed
}
));
If _speed is set to a double e.g. 4.0 then this instruction will tell the Smart Client to start play in forward mode with speed 4 times normal. (This assumes that the Mode is currently in Playback)
To receive the FQID that is currently selected in the Smart Client:
Collection<object> result = EnvironmentManager.Instance.SendMessage(
new VideoOS.Platform.Messaging.Message(
MessageId.SmartClient.GetSelectedCameraRequest));
The result will be a collection with one element, if any camera has been selected.
Triggers Message
One other example of an action is the trigger message. This message can be sent to activate a number of different Kinds of Items, such as:
- Output on cameras and video encoders
- User-defined events
- PTZ cameras with defined presets
- Matrix Monitors
- A plug-in-defined trigger item
To start recording on a specific camera, the following instruction can be used:
EnvironmentManager.Instance.SendMessage(
new Message(MessageId.Control.StartRecordingCommand), cameraFQID);
where the cameraFQID identifies a camera in the system. Note that these commands are sent to the cameraFQID, as this field is the destination field.
It is also worth noting that plug-ins that define some Items as EventTriggers, will open up for other plug-ins to utilize and activate these triggers. If, for example, an access control system provides triggers for Open door, Close door or Light on, these Items will become selectable for an ItemPicker with Category set to Category.TriggerOut.
Methods Available on the EnvironmentManager:
public object RegisterReceiver(MessageReceiver messageReceiver,
MessageFilter messageFilter);
This method is used to register a Receiver. The Receiver will only receive messages that match the messageFilter. Whenever a Message is received, it will always be executing on the UI thread if one is available. Own MessageFilters can be created in case the Match method needs to be specialized.
public void UnRegisterReceiver(object registeredReceiver);
This method is used to unregister a receiver method. It is required to do an UnRegister call to avoid memory leaks, similar to a -= on an event. The parameter 'registeredReceiver' must be the same object as was returned during the Registration call.
public abstract Collection<object> SendMessage(Message message, FQID destination, FQID sender);
This method sends the message to all receivers that have a matching MessageFilter, all receivers are called before the SendMessage method returns. Each called received have the option to return some object or return null. The resulting Collection<object> contains all the objects where the return value was not null. The underlying technique used is the Control.Invoke() if in a Environment with UI and not on the UI thread.
public void PostMessage(Message message, FQID destination, FQID sender);
This method is similar to the SendMessage, except that the receivers are not complete when the PostMessage() returns. The underlying technique used is the Control.BeginInvoke(). To get a complete list of all MessageIds available in a system, call:
public List<String> MessageIdList { get; }
The returned List contains all defined messages in the Environment, and all messages defined by the loaded plug-ins. See PluginDefinition for how the Plugins provide their own defined MessageIds.
MessageFilter
When message receivers are registered, the registration call contains a reference to the MessageFilter to be used for this particular message receiver. The purpose of the MessageFilter is to ensure that only the messages that may be relevant for the receiver in question are actually passed on to the receiver. The built-in MessageFilters can filter on MessageId or on the Kind in a FQID. If a MessageReceiver needs all messages of ID NewEventIndication, the following registration can be used:
EnvironmentManager.Instance.RegisterReceiver(NewEventHandler,
new MessageIdFilter(MessageId.Server.NewEventIndication));
Note: the NewEventIndiction is sent by the EventServer every single event being processed in the EventServer.
If a MessageReceiver must receive all messages sent where a specific Kind is in the message.RelatedFQID.Kind, then the following registration may apply:
EnvironmentManager.Instance.RegisterReceiver(RelatedKindHandler,
new KindFilter(MyPlugin.Kind));
You can implement your own MessageFilter as needed.