Fork MediaPortal on GitHub
MediaPortal Windows Media Center
MediaPortal Wiki > MediaPortal 2 > Contribute > Plugin Development > Developing Plugins

Developing Plugins

Was this page helpful?
Redirected from 2 MEDIAPORTAL 2/Contribute/Plugin Development/Developing Plugins

    Overview

    Plugins in MediaPortal 2 can add various functionality to the system. They can add language resources, skin resources and code. Language resources are string translations, typically for one plugin or for a set of plugins, for different languages. Examples for skin resources are skinfiles, style files, media content, fonts and workflow descriptor files.

    Plugin Directory Structure

    Plugins are composed of files and subdirectories which are located in a plugin directory. The plugin directory should be named similar to the plugin's name and is located in the Plugins directory under the MP2 application's directory.

    Plugins consist of those files and directories:

    File/directory Purpose
    plugin.xml The plugin descriptor file. This file contains meta information about the plugin which is read by the plugin manager.
    Assembly .dll files Executable modules provided by the plugin.
    Skin directory Resource directory containing skin resources.
    Language directory Resource directory containing language resources.

    Resource Plugins

    Currently, there are two kinds of resources which can be provided by plugins: Skin resources and language resources. Skin resources are screen files, media data, theme data, fonts or any other files used in the Skin Engine. As an example for a plugin implementing a skin, see the DefaultSkin plugin of the MediaPortal 2 application. Language resources contain localization strings for special languages.

    All those resources must be registered as a Resource in the registration location /Resources/Skin or /Resources/Language.

    Example for a skin resource registration:

      <Register Location="/Resources/Skin">
        <Resource Id="MyPluginSkin" Directory="Skin" Type="Skin"/>
      </Register>

    Example for a language resource registration:

      <Register Location="/Resources/Language">
        <Resource Id="MyPluginLanguage" Directory="Language" Type="Language"/>
      </Register>

    For a complete description of the plugin descriptor file see the chapter later on this site.

    Executable/Code plugins

    Code plugins bring in executable code into the MediaPortal 2 application. They can contain code which may be automatically run (with setting the AutoActivate setting to true), or they can register code modules for a special purpose, for example to provide a special MediaPortal service or to be instantiated as a media player or to be used by any other MediaPortal 2 module which imports plugin items.

    Plugin States

    The plugin state reflects the status of the plugin in the system. There are currently defined 6 plugin states:

    Plugin state Meaning
    Available The plugin descriptor file was parsed without an error and the plugin is ready to be enabled or disabled. This is a temporary state of a plugin directly after it was loaded.
    Enabled The plugin is ready to be used. Its items are registered in the plugin tree, but none of them is used by clients. If the plugin wasn't active before, the plugin's dll files aren't loaded yet.
    Active The plugin's dlls are loaded and/or its items have been accessed by clients. The state tracker instance is active, if it is available.
    EndRequest The plugin is about to be disabled (phase 1). In this state, it mustn't expose any more functions to the system.
    Stopping The plugin is about to be disabled (phase 2). In this state, it mustn't expose any more functions to the system.
    Disabled The plugin is disabled. Neither any of the plugin's items is exposed to the system nor its state tracker instance is active.

    Plugin State Tracker Instance

    The plugin state tracker is a kind of "main" class of the plugin. This class has to implement the interface MediaPortal.Core.PluginManager.IPluginStateTracker. The state tracker instance will be called when the plugin is activated, when it should be stopped and when the system is shut down. Plugins don't need to expose a plugin's state tracker.

    Example for a plugin state tracker registration:

      <Runtime>
        <Assembly FileName="MediaPortal.SkinEngine.dll"/>
        <PluginStateTracker ClassName="MediaPortal.SkinEngine.SkinEnginePlugin"/>
      </Runtime>

    Together with the AutoActivate option, the plugin state tracker's Activated() method can be used to immediately gather an execution thread to execute plugin code on startup.

    Plugin Descriptor File (plugin.xml)

    To register itself each plugin needs a plugin.xml file, that provides meta configuration to the plugin manager about the plugin.

    Example for a plugin.xml file:

    <Plugin
        Version="1.0"
        Name="SkinEngine"
        Author="Frodo, Albert78"
        Copyright="GPL"
        AutoActivate="true" 
        Description="DirectX Window Manager"
        PluginVersion="1.0">
    
      <DependsOn>
        <PluginReference Name="Configuration"/>
      </DependsOn>
    
      <Runtime>
        <Assembly FileName="MediaPortal.SkinEngine.dll"/>
        <PluginStateTracker ClassName="MediaPortal.SkinEngine.DirectxGui"/>
      </Runtime>
    
      <Register Location="/Configuration/Settings/Appearance">
        <Setting
            Id="system"
            Type="Group"
            Text="[configuration.system]" />
      </Register>
    
      <Register Location="/Configuration/Settings/Appearance/System">
        <Setting
            Id="fullscreen"
            Type="YesNo"
            Text="[configuration.system.fullscreen]"
            Help="[configuration.system.fullscreen.help]"
            ClassName="MediaPortal.SkinEngine.Settings.Fullscreen"/>
      </Register>
    </Plugin>
    

    Root Element

    The Plugin element provides details about the plugin: Its name, author(s), copyright, decription, its plugin version. If the AutoActivate flag is set to true, the plugin will be activated automatically when it is enabled. The plugin metadata will be displayed in the config system to allow installation and enable/disable plugins. The Version attribute is needed for the parser to reject plugin.xml files which do not fit to the expected file specification.

    Sections

    Under the Plugin element, there are additional elements which control the plugin's features and behavior.

    Plugin Runtime

    The Runtime element provides details of the assemblies required to be loaded for this plugin and specifies the plugin state tracker class.

    <Runtime>
      <Assembly FileName="MediaPortal.SkinEngine.dll"/>
      <PluginStateTracker ClassName= "MediaPortal.SkinEngine.DirectxGui"/>
    </Runtime>

    In this section, all assemblies used in this plugin have to be named. The file names are relative to the plugin root directory.

    The PluginStateTracker class is optional. If specified, this class will be instantiated when the plugin is activated. It is used to make the plugin able to "watch" its state. A special method will be called on this instance when the plugin is activated, and this instance will be able to control if the plugin can be deactivated. The plugin state tracker class has to implement the interface MediaPortal.Core.PluginManager.IPluginStateTracker.

    Plugin Dependencies

    In the DependsOn element the plugin developer can put a list of names of those plugins, which have to be loaded before this plugin can be loaded. The plugin manager will automatically reject to enable this plugin if one of the dependencies is not available or cannot be enabled.

    In this example, the plugin depends on another plugin with the name Configuration:

    <DependsOn>
      <PluginReference Name="Configuration"/>
    </DependsOn>

    Plugin Conflicts

    In the ConflictsWith element the plugin developer can put a list of names of those plugins, which stand in conflict with this plugin. The plugin manager will automatically reject to load this plugin if one of the conflicting plugins is already loaded and enabled.

    In this example, the plugin won't be enabled if a conflicting skin engine, the WpfSkinEngine, is enabled:

    <ConflictsWith>
      <PluginReference Name="WpfSkinEngine"/>
    </ConflictsWith>

    Plugin Item Registration

    Register exposes plugin items to the system. An item can be almost everything: it can be an instance, a resource, a player, an importer, ...

    Items of the correct type must be registered at defined locations to be found by the system.

    The Location attribute is needed to specify the registration location for the item, which together with the item's id is the primary key to access an item. In the MediaPortal 2 application, there are several defined registration locations accessed by the system, which can be used to add functionality to the system.

    For example, models are registered using the Model item type at the location "/Models":

    <Register Location="/Models">
        <Model Id="D4B7FEDD-243F-4afc-A8BE-28BBBF17D799" Name="ScreenSaverModel" ClassName="UiComponents.SkinBase.Models.ScreenSaverModel"/>
        <Model Id="9E9D0CD9-4FDB-4c0f-A0C4-F356E151BDE0" Name="MenuModel" ClassName="UiComponents.SkinBase.Models.MenuModel"/>
    </Register>

    The item types available in the system are defined by plugin item builders. There are several default builders defined: Instance, Resource, Model, ConfigSection, ConfigGroup, ConfigSetting, Background and many more. Each item type has special attributes and different things are done by its builder when the added asset is registered. For every item registration, the Id attribute is mandatory. Other attributes are defined by the plugin item builder which is responsible for the item type. For example the Instance builder has the Id attribute and a single additional attribute ClassName which specifies a class to be instanciate. The created instance will simply be added into the internal plugin item registration tree. The Resource builder, as a second example, creates a special wrapper instance which holds a directory path.

    If needed, plugins can add more item types by using the <Builder> element.

    Plugin Item Builders

    Plugin item builders can be used to extend the plugin item instantiation system. Builders are responsible for creating/loading item instances out of the attributes specified in the item registration. The Instance builder is a simple example for a builder. Take an item which is declared like this:

    <Register Location="...">
      <Instance Id="SqlServer" ClassName="Components.Database.Sql.SqlDatabaseBuilder"/>
    </Register>

    This item will be created by the Instance builder, because its element name is Instance. There are some default builders in the system, for example Instance, Resource and Setting. Creating custom builders can improve lazy loading and enable config information to be stored in the .plugin file without requiring an extra file.

    Example for an item registration requiring a custom item builder:

    <Register Location="/Media/Players">
      <Player Id="BassPlugin" ClassName="Media.Players.BassPlayer.BassPlugin" Type="audio" Extensions=".mp3,.wav,.asx,.mod,.s3m,.mp4,.wma"/>
    </Register>

    This item can only be loaded if the special item builder, the Player builder, is registered.

    Plugin item builders can be defined by the usage of the the Builder element (as a child of the top-level Plugin element):

    <Builder Name="Player" ClassName="Components.Services.PlayerManager.PlayerBuilder"/>

    A plugin builder has to implement the interface MediaPortal.Core.PluginManager.IPluginItemBuilder. All plugins, which make use of a custom item builder to register their items, need to define a dependency to the plugin which defines the builder.

    Default Plugin Item Builders

    Builder-Name/Item type Meaning Usage Where to use
    Instance Exposes an instance from a class of the plugin's dll(s). <Instance Id="IImporterManager" ClassName="Components.Services.ImporterManager.ImporterManager"/> Everywhere where no no special builder is available.
    Resource Exposes a plugin's resource directory to the system. <Resource Id="DefaultSkin" Directory="Skin" Type="Skin"/> At locations /Resources/Language and /Resources/Skin.
    Model Exposes a skin model to the system. <Model Id="D4B7FEDD-243F-4afc-A8BE-28BBBF17D799" Name="ScreenSaverModel" ClassName="UiComponents.SkinBase.Models.ScreenSaverModel"/> At location /Models.
    ConfigSection Exposes a configuration section to be used in the configuration part. <ConfigSection Id="Appearance" Redundant="true" Text="[Settings.Appearance]" IconSmallPath="Resources\ConfigurationImages\skin-22.png" IconLargePath="Resources\ConfigurationImages\skin-48.png"/> At location /Configuration/Settings and sub locations.
    ConfigGroup Exposes a configuration group to the configuration part. <ConfigGroup Id="System" Redundant="true" Text="[Settings.General.System]"/> At locations /Configuration/Settings/[Setting sub path].
    ConfigSetting Exposes a configuration setting to the configuration part. <ConfigSetting Id="TimeFormat" Text="[Settings.Appearance.Skin.Formats.TimeFormat]" HelpText="[Settings.Appearance.Skin.Formats.TimeFormat.Help]" ClassName="UiComponents.SkinBase.Settings.Configuration.Appearance.Skin.TimeFormat"/> At locations /Configuration/Settings/[Group sub path].
    Background Exposes a skin's background or background manager. <Background Id="Background" BackgroundManagerClassName="UiComponents.SkinBase.PlayerBackgroundManager"/> or <Background Id="Background" StaticScreen="some-background-screen.xaml"/> At locations /Skins/[Skin name].
    PlayerBuilder Exposes a player builder to the system <PlayerBuilder Id="1CBD4219-4ABD-4543-A3FE-37F6D7DDD78D" ClassName="Ui.Players.BassPlayer.BassPlayerPlugin"/> At location /Media/Players.

    Using Plugin Items from Clients

    Using plugin items is one important way for a component to expose an "extension point" to the outside. Using such an extension point, plugins are able to add functionality to the system.

    Technically, using an item means to request its usage at the plugin manager:

      IPluginManager pluginManager = ServiceScope.Get<IPluginManager>();
      ConfigBaseMetadata metadata = pluginManager.RequestPluginItem<ConfigBaseMetadata>(
        "/Configuration/Settings/General/System", "Autostart", new FixedItemStateTracker());

    The specified IPluginItemStateTracker instance is responsible to attend the item's usage lifetime. It is necessary to have such a callback instance, because the plugin manager sometimes needs to deactivate plugins, which means it has to remove items once exposed to the system. Using such a plugin item state tracker instance, item users get the chance to revoke items (if they can) or to prevent the removal, which makes the plugin deactivation fail. For more information how to implement a plugin item state tracker, see the interface docs for MediaPortal.Core.PluginManager.IPluginItemStateTracker.

    There is a default implementation for a plugin state tracker which will always prevent an item from being removed by the plugin manager, MediaPortal.Core.PluginManager.FixedItemStateTracker. Use this implementation, if your extension point isn't able to cope with an item's removal. This will prevent the plugin manger from disabling a plugin which added items to your extension point, and thus should be avoided, if possible.

    Lifetime management

    A plugin must handle two different lifetime cycles:

    • Each plugin can be installed and uninstalled during the lifetime of the system. That means if the plugin manager uninstalls a plugin and enters the two-phase-stopping process of a plugin, the plugin must react correctly to that and, if supported, remove its allocated resources from the system.
    • When the system is started, hibernated or shut down, plugins need to react to those events if necessary. During the startup and shutdown sequences, many things are done. You can see that in class ApplicationLauncher, in the MP2 client and server main projects. The startup of plugins is done early during system startup. If your plugin needs to execute some system integration code at startup, typically it will do so after the system startup sequence is finished. That can be achieved by using a message queue like shown below. But also during the shutdown phase, it might be necessary to shut your plugin down before the system services are removed from the ServiceRegistration and disposed.

    Reacting to system state transitions

    To be called back when the system has finished with its startup process or before it is being shut down, you can register at the system messaging message queue.

    To subscribe to messages of this queue, use code like this:

    void SubscribeToMessages()
    {
      _messageQueue = new AsynchronousMessageQueue(this, new string[]
        {
           SystemMessaging.CHANNEL
        });
      _messageQueue.MessageReceived += OnMessageReceived;
      _messageQueue.Start();
    }
    
    void OnMessageReceived(AsynchronousMessageQueue queue, SystemMessage message)
    {
      if (message.ChannelName == SystemMessaging.CHANNEL)
      {
        SystemMessaging.MessageType messageType =
            (SystemMessaging.MessageType) message.MessageType;
        if (messageType == SystemMessaging.MessageType.SystemStateChanged)
        {
          SystemState newState = (SystemState) message.MessageData[SystemMessaging.NEW_STATE];
          if (newState == SystemState.Running)
          {
            // Execute startup code of the plugin
            [...]
          }
          else if (newState == SystemState.ShuttingDown)
          {
            // Execute shutdown code of the plugin
            [...]
          }
        }
      }
    }
    

    Plugin template

    A plugin template project is located in the MediaPortal/Resources folder of the MediaPortal 2 source code.




    Running the latest version?

    V1.8.0 - released July 2014
    Releasenews | Download
    Changelog
     | Requirements
    HTPC
    Team-MediaPortal
     
    About
    Contact |  Press
    Partners