Linphone Desktop Plugins

Last modified by Julien Wadel on 2021/04/21 23:45

Feature

Linphone Desktop allow the use of special plugins. Current capabilities are :

- CONTACTS

You can get an example in the `plugins/example` folder of the linphone-desktop project.

A plugin is a dynamic library that will be loaded by Linphone Desktop. They are located in the plugins folder of the application or in user folder next to linphone.db.

The first step in the use of a plugin for the applciation is to read the meta data in order to get data like ID, version, capabilities and an optional description. These informations are used internally : The ID will be used to target a plugin and recognize it from all others.

Then, Linphone Desktop will retrieve all generic data coming from the plugin without having instanciating it. It will get all GUI tokens and that allows the application to provide a way to present the plugin to the user.

When a user want to use a plugin, Linphone Desktop will create an instance from the plugin with the user data. It allows to use more than once a plugin and you could repeat the same actions but with a different context; For example,  you can use only one plugin and make few address book connectors for each providers you want. Behaviours between instances of a plugin are independant by default (as long the plugin code something against it)

When opening a new plugin, Linphone Desktop ensure that it doesn't exists in the current paths by checking name, ID and version. It will propose to upgrade or replace if it is the case.

Writting a plugin

For a plugin, you need to overload 2 generic classes: `LinphonePlugin` and `PluginDataAPI`. In addition, it must be deployed with a JSON file that will describe the meta data.

LinphonePlugin

This class is an asbtract class that will be used to get generic information from the plugin without having an instance. It also helps to create one instance of the plugin : you can have a multiple instance that will have its own behaviour. In other words, The LinphonePlugin is the root.

You need to override 2 functions :

virtual QString getGUIDescriptionToJson() const;

The GUI description use QJSON objects. It must return all fields that are used by the plugin. Each fields are describe by using these keywords:

  • "pluginID" is a protected keyword. You should never use it as it is used to identify your plugin. It is read from ID in metadata.

 There are 3 Keys to set:

  1. "pluginTitle" => the plugin title that must used to display. It is not in the meta data to allow multi-languages.
  2. "pluginDescription" => A description of the plugin to let user to know what the plugin do. Again, this field is not in the meta data to allow multi-languages.
  3. "fields" => a list of Object that describe all input fields.

Each fields are described by these keywords:

  • "placeholder" => A text that will be shown on empty inputs.
  • "fieldId" => The is an ID that will identity the field.
  • "defaultData" => the default data to use if not specify by the user. It is optional.
  • "type" => the type of input field to show. 1 = TextArea
  • "hiddenText" => a boolean that make the input field like a password (text is replace by points/stars)
virtual PluginDataAPI * createInstance(void* core, QPluginLoader * pluginLoader);

It rteturn an instance of your PluginData.

The plugin class must have specific headers to be undestrandable from Linphone Desktop. The name PluginMetaData.json must be the name of your JSON description (see below for details).

Q_OBJECT
Q_PLUGIN_METADATA(IID LinphonePlugin_iid FILE "PluginMetaData.json")
Q_INTERFACES(LinphonePlugin)

PluginData

This is the instance of the plugin. It will be used to do actions.

You can see the LinphonePlugin as a class and the PluginData, an instance of it.

The only 2 functions that need to be overloaded are :
virtual void run(const PluginCapability& actionType)=0;
This function is call by Linphone Desktop in order to do stuff related to the requested capability.

virtual bool isValid(const bool &pRequestData=true, QString * pError= nullptr) = 0;
This function is used to ensure that your data is valid before saving.

By default, The PluginDataAPI make load/save configurations and store internal data.

Here is a descrption of all functions that can be overrided:

PluginDataAPI(LinphonePlugin * plugin, void * linphoneCore, QPluginLoader * pluginLoader);
This constructor has to be called by your plugin object. It initializes the plugin with basic data and allow automatic memory managment.
The core is a `linphone::Core*`
Your inputFields will have all fields that have a default value. The data comes from the `getGUIDescriptionToJson` from your plugin.
The "enabled" flag will be set to 0 by default.

virtual void setInputFields(const QVariantMap &inputFields);// Set all inputs

This will replace the internal data by inputFields. If the data is valid, these fields are saved. A signal is emit to let knowing that fields have been changed.
So do not forget to send the signal if it is the case.

virtual QVariantMap getInputFields();// Get all inputs

This return all the internal fields to use.

virtual QVariantMap getInputFieldsToSave();// Get all inputs to save in config file.

This return all internal fields to save. If you don't want to store all data, you can override it and make a filter.
For example, we don't want to store a clear password. So, we will remove this field from the internalData in this function.
 

void setSectionConfiguration(const std::string& section);

The section will be used to set a section name in the configuration file. The Plugin Manager. will give a specific section name and pass it to this function.

virtual void loadConfiguration();

Like the name, this will load all input fields from the configuration at the section name.

virtual void saveConfiguration();
This function will save the fields in the file with the given section name.

QPluginLoader * getPluginLoader();
It is used to retrieve the loader that created this instance, in order to unload it when needed.

JSON

The file must have at least 2 fields.

  • - "ID" : This ID must be unique from all existant plugin. It is used to identify your plugin from all other
  • - "Capabilities" : A list of capabilities separated by a comma ",". The only available capability is "Contacts".

You can find an example in PluginMetaData.json in `plugins/example` folder :

{
   "ID" : "ExamplePlugin. This ID must be unique from all plugins.",
   "Version" : "1.0.0",
   "Description" : "This is an example for describing your plugin. Replace all fields above to be usable by the Application.",
   "Capabilities" : "Contacts"
}