Documentation/Maemo 5 Developer Guide/Using Multimedia Components/Media Application Framework (MAFW)

= Media Application Framework (MAFW) =

Introduction
The Maemo platform provides multimedia capabilities through the GStreamer framework. GStreamer takes care of all the low-level multimedia playback details (codecs, formats, protocols, etc.), makes developer's lives really easy, and allowes rapid development of typical multimedia applications.

However, there are still a few features that are not covered by frameworks like GStreamer. Usually, these topics have to do with the complexity of latest generation Media Player applications, which tried to provide integration with all kinds of multimedia services (UPnP, Last.Fm, Youtube, etc), although others are more traditional, you will find no support in relatively low-level frameworks such as GStreamer for things like manipulation playlist.

The Multimedia Applications FrameWork (MAFW) complements GStreamer to enhance the multimedia experience in the Maemo platform, providing developers with a flexible, easy to use, and extensible high level layer on top of other included multimedia related technologies. Specifically, MAFW intends to provide multimedia application developers with:


 * An extensible, pluggable framework interface, which allows you to develop new plugins which provide integration with new multimedia services or rendering engines, and which will seamlessly integrated into all MAFW based applications.
 * Easy to use APIs that speed up application developing, providing support for playback control, discovery and browsing of multimedia resources and playlist manipulation.
 * An independent technology. Since MAFW is a plugin based framework, it is not tied to a particular multimedia technology (GStreamer, MPlayer, and Tracker). Plugin developers have the freedom to choose the technologies they want to use in their plugins, and application developers do not need to care about them.

The purpose of this manual is to introduce the basic concepts of the MAFW framework to interested multimedia developers, explaining its fundamental concepts and providing insight and examples on how it should be used to develop multimedia applications in the Maemo platform.

Pre-requisites
The examples given in this section are written in C using Glib to interact with MAFW which is built upon the GObject framework, a reader will need to be familiar with these subjects in order to understand these examples.

Examples
Source code examples are available in section and are intended to illustrate many of the concepts explained in this manual. References to sections with examples are be provided as needed.

Main concepts
Here follows a brief explanation on some of the fundamental concepts concerning the MAFW framework. Most of them will be covered in more detail in later sections of this manual:


 * Renderer: An element capable of consuming multimedia content, and controlling media playback.
 * Source: An element that provides access to multimedia content, such as the media stored in the local filesystem, UPnP servers, Samba shares, Bluetooth devices, Internet services, etc..
 * Object Identifier: Sources identify multimedia resources using object identifiers. Each individual resource has one unique object identifier associated that is provided by the source serving it.
 * Shared playlist: A sorted list of multimedia resources ready to be consumed by a renderer, which can be used and manipulated by several applications in parallel. Playlists are populated with media items exacted from Source components, and assigned to a renderer to be played.
 * Extension: An element that implements a particular task by following a well defined interface. Currently, two types of extensions are allowed, those that implement new Source components and those that implement new Renderer components. Also, extensions can be used in two manners:
 * In-process extensions: Those that live in the same address space as the application that uses them.
 * Out-of-process extensions: Those that live in a separate process other than the application's. The benefit of this type of extensions is that programming flaws in the plugin code that lead to crashes or freezing of the extension, do not crash or freeze the main application. The main drawback of this approach is the need for inter-process communications to communicate the application and the extensions, which may have a performance hit and require some extra synchronization effort.
 * Plugin: A plugin is a shared object file implementing a particular Source or Renderer type of extension. For example, in the case of a UPnP source plugin, there shared file implementing the source is the plugin. However, the plugin may instantiate several source extensions, one per UPnP server discovered.
 * Wrapper: In order to make inter-process communications in the case of out-of-process plugins transparent for application developers, all components that can live in a separate process (Extensions and Shared playlists), are wrapped with local objects that handle the inter-process communication transparently. Thanks to these wrapper objects, in most situations, application developers do not need to know if they are using in-process or out-of-process components. Although wrappers play an important role in MAFW, they are only interesting for developers interested in hacking the internals of the framework, multimedia application developers do not need to know about them.

Packages
MAFW is formed by the following packages:


 * MAFW Library: The MAFW library contains the basic classes and interfaces defined in the framework. These expose the major elements of the framework, like the concepts of Extension, Source and Renderer and the APIs the developers will use to interact with them.
 * MAFW Shared: This package provides means for sharing components among different applications using MAFW. It implements the logic behind the wrapper objects, as well as the concept of Shared playlists. It is composed of:
 * libmafw-shared: A library to use the shared components exposed by sharing services (extensions and shared playlists).
 * mafw-dbus-wrapper: This service is the one responsible for loading extensions in separate processes and export their interfaces as D-BUS services. These services are used by the wrapper objects defined in libmafw-shared in the out-of-process use case.
 * mafw-playlist-daemon: A daemon that provides an API for shared playlist manipulation and storage.
 * Extensions: Extensions are provided as separate packages.

Getting started
MAFW is available as debian packages, so it can be installed using tools like dpkg or apt.

MAFW can also be built from source. To build and install a MAFW package from source, move to the root directory of the source and build a MAFW package:

 . /autogen . sh make make install 

When building from source, one can also pass certain flags to the autogen.sh script. Check the configure.ac file for a list of available build flags for the module. Common and useful supported flags among all MAFW packages are:


 * -prefix=PATH, installs MAFW files into PATH.
 * -disable-tests, disables tests (speeds up compilation time).
 * -enable-debug, compile with debug options enabled. Useful for debugging.

Also, when building MAFW from source, one should take into account the source dependencies. MAFW should be built in this order:


 * mafw
 * mafw-shared
 * source and renderer plugins

Initial preparations
Before running MAFW applications, one should ensure the build environment is properly setup.

The first thing that you should check is the playlist daemon. This manual will cover the playlist daemon in more detail in later sections, but for now it is enough to know that this daemon provides functionality for applications to access and manipulate playlists.

In order to run the playlist daemon, one should execute the following command: Running the playlist daemon

mafw-playlist-daemon -d 

Also, if you decided to use out-of-process plugins, you must be sure these plugins are running (remember that out-of-process extensions live in separate processes).

There is a tool to load out-of-process extensions called mafw-dbus-wrapper. In order to load a particular plugin in out-of-process mode do the following: Loading out-of-process plugin

mafw-dbus-wrapper PLUGIN &amp; 

This command will load the specified plugin, searching for it in the MAFW plugin directory. For this purpose, mafw-dbus-wrapper also accepts absolute paths to plugin files: Loading out-of-process plugin

mafw-dbus-wrapper /home/user/mafw-plugin/bar-mafw-plugin . so 

Usually, one would not invoke mafw-dbus-wrapper directly, instead, it is recommended to create an init script to start all the plugins and the playlist daemon at boot time. Something like this: Starting and stopping MAFW services

/etc/init . d/mafw [ start  | restart <font color="#990000"> | stop <font color="#990000">] </tt>

As with many other Maemo components, take into account that running commands in a Scrathchbox environment requires additional environment preparations. Particularly, the Maemo environment has to be running, and then any shell commands must be run using the run-standalone.sh script, so they are get appropriate environment settings: Environment setup

  <font color="#0000FF">export  <font color="#009900">DISPLAY  <font color="#990000"> =:  <font color="#993399">2 sb-fremantle-init <font color="#990000">. sh start run-standalone <font color="#990000">. sh mafw-playlist-daemon -d run-standalone <font color="#990000">. sh mafw-dbus-wrapper PLUGIN <font color="#990000">&amp; </tt>

Application initialization
As MAFW is based on GObject the first step in writing a MAFW based application is to initialize the GType system. You can do this by invoking g_type_init at the beginning of your program.

Of course, this step is not necessary if the developer is using another GObject based framework, like GTK+. In this case, initializing that framework already initializes the GType system.

The next step is to check for available extensions (sources and renderers). This process may differ depending on whether you are using in-process or out-of-process extensions.

Loading extensions
This section explains how to load extensions in a program. The example in section provides  complete source code example illustrating all this process.

Loading out-of-process extensions
As we already pointed out, with the out-of-process approach extensions are loaded by the mafw-dbus-wrapper in a separate address space and they are shared by all applications, which use these extensions through D-BUS services. In order to use these out-of-process extensions, the first step is to discover their availability via the bus. This is done by invoking mafw_shared_init after getting a reference to the registry object with mafw_registry_get_instance. Once the discovery has been started, your application will be notified of new available extensions through signals. Likewise, when a certain extension is no longer available a signal is sent to the application so that it can properly handle this.

The MafwRegistry object is a singleton instance where all the available extensions are registered. It provides an interface for application developers to access the available sources and renderers. In the case of out-of-process extensions, the registry will provide proxies to the actual remote extensions that handle the D-BUS communications transparently for you.

It is also possible that extensions were loaded in the registry before the application attached its signal handlers. In this case the application will not get any signals for these extensions and has to query the registry for them using mafw_registry_get_renderers and mafw_registry_get_sources functions. Notice that you should not free these lists of available extensions.

Loading in-process extension
Contrary to the out-of-process approach, in-process extensions are loaded in the same address space of the application's process. In this case we do not have to start a discovery process, instead we can either load all the available plugins or load specific plugins. As in the out-of-process case, this is done through the MafwRegistry object.

Loading all available extensions
After getting a reference to the registry, one should call mafw_registry_load_plugins.

Loading extensions manually
Individual extensions can be loaded manually by using mafw_registry_load_plugin and declaring the plugin to load.

The second parameter of mafw_registry_load_plugin can be just a filename (in this case the default plugin directory will be used) or the absolute path of the plugin file.

Being aware of loaded extensions
As in the out-of-process approach, the application has to be informed of loaded extensions. The same code as for the out-of-process case can be used here.

Querying available extensions after loading
This approach loads the extensions in the registry first and then queries it for the lists of available renderers and sources using mafw_registry_get_renderers and mafw_registry_get_sources.

Using signals and callbacks
This approach is more asynchronous and it is recommended because it can easily handle sources or renderers added after the application was started. It is done by connecting callbacks to the source-added and renderer-added signals As soon as a plugin is loaded, a signal is emitted and the application can react to it, preparing everything to use that extension.

In-process versus out-of-process extensions
There are a few issues to consider when making the decision of using in-process or out-of-process extensions:


 * In-process extensions do not need inter-process communications, speeding up certain operations.
 * Out-of-process extensions use multiple processes and D-BUS (which serializes and integrates these communications nicely with the main loop) avoiding the need of threads in the main application in most cases. In the in-process case, developers may need to use threads or idle calls to execute certain extension operations in order to avoid blocking the user interface while the extensions work (for example source browsing).
 * In the in-process case, signals coming from extensions are normal GObject signals. However, in the out-of-process case, these signals have to be sent through D-BUS. For developers, this means that callbacks for these signals are not invoked as soon as the signal is emitted, but as soon as the D-BUS message is received and processed by the main loop.

Playlists
This section explains how to use playlists in a program. During this explanation it is recommended to follow section for a complete source code example illustrating most of the concepts explained below.

The playlist daemon
MAFW playlists are shared, this means they are stored and exposed by the mafw-playlist-daemon, which makes them available for all MAFW based applications, that can access and manipulate them concurrently through its API.

Because the playlists are always remote objects stored and handled by a separate process, whenever the application needs to deal with a playlist there is a need for inter-process communications. However these communications are hidden to developers by using a proxy object. These proxy objects allow developers to interact with the playlists as if they were local objects, making the underlying communications with the playlist daemon transparent for the application developer.

Operations like creating or removing a playlist or obtaining the list of available playlists, are done through the MafwPlaylistManager object. This object acts as a proxy of the playlist daemon, for playlist related operations that do not deal with a particular playlist. A reference to this object can be obtained using mafw_playlist_manager_get.

The following sections explain in more detail how to use the MafwPlaylistManager and proxy playlist objects.

Creating playlists
The method mafw_playlist_manager_create_playlist is responsible for requesting the creation of a new playlist to the playlist daemon. If the operations is successful, returns a reference to a MafwProxyPlaylist that will act as a local representation of the remote playlist created in the playlist daemon. If the requested playlist name has already been used (that is, another playlist with that name already exists), no playlist is created and a reference to the already existing playlist is returned. In order to check if a certain playlist already exists, the developer can use mafw_playlist_manager_get_playlists or mafw_playlist_manager_list_playlists to list the playlist names that have been registered already.

It is important to consider the shared nature of the MAFW playlists. From the developer point of view, this means it should never be assumed that a certain MAFW based application is the only one interacting with a playlist.

The application can install a signal handler in order to be notified of the creation of new playlists. This can be done by connecting to the playlist-created signal.

Although new playlists can be used right away after calling mafw_playlist_manager_create_playlist, it is better to handle newly created playlists through the playlist-created callback, because this will work also for playlists created by other MAFW based applications.

It is possible to import an existing playlist file or the contents of a particular container of a source extension as a MAFW playlist with the help of mafw_playlist_manager_import. If this method is passed a URI as parameter, it will try to parse the file pointed by that URI and populate a playlist with the entries of the playlist file. Likewise, if a source object identifier is used instead of a URI, and it points to a valid source container, the container will be browsed, and the contents will be used to populate the playlist. If the object identifier points to a single media item instead of a container, the associated media will be treated as as a playlist file, parsing the file it points to adding its entries to the playlist.

After a playlist has been imported, the framework will invoke the callback passed as parameter to mafw_playlist_manager_import, with a reference to the imported playlist proxy object. The name of the playlist will be the URI pointing to the file, or the source container title. If a playlist with this name existed already, then a number will be added after the name as a suffix to ensure a unique name is assigned. After this, the MafwPlaylist::playlist-created signal will be emitted.

Removing playlists
Playlist deletion is achieved through the MafwPlaylistManager object in a similar way as the creation of new playlists.

The first step is to obtain a reference to the playlist that has to be removed. After a reference has been obtained, mafw_playlist_manager_destroy_playlist is ready to remove it.

If playlist removal was not possible, the playlist manager can also emit the signal playlist-destruction-failed. In general, this happens when trying to remove playlists that are being used somewhere else in the application or when they are being used by some other application.

When an application wants to mark a playlist as being in use, it should call mafw_playlist_increment_use_count. When an application tries to remove a playlist which reference count is greater than zero, the operation will fail. Renderers should always increment the reference count of a playlist when it is assigned and decrement when it is unassigned.

As in the case of playlist creation, it is also a good idea to install a signal handler for playlist deletion so the application can deal with this situation properly. For example, another MAFW based application may attempt to destroy a playlist that your application is showing as available to the user in a playlist selection widget.

Handling playlist elements
Inserting items Adding elements to the playlist is done by using mafw_playlist_insert_item and specifying the index where the item should be inserted.

A signal will be emitted whenever a playlist is modified. Notice that other MAFW based applications may be modifying the playlists in use by your application at any moment. By connecting to these signals, your application should be able to handle this situation properly.

This MafwPlaylist::contents-changed signal is used to signal changes of any kind. The from parameter is the index of the first element affected by the change, nremoved is the number of removed elements and nreplaced represents the number of elements replaced. For example, in case of insertion, the signal will be emitted with the insertion index as from, 0 as nremoved and 1 as nreplaced. More information is available in the Mafw API reference.

Also, the convenience function mafw_playlist_append_item can be used to append items to the tail of a playlist.

Removing items As in the case of insertion, one only needs to call the method on the playlist proxy object with the index of the element to remove.

The signal received when modifying the playlist is the same as when removing elements. In this case nremoved would be 1 and nreplaced would be the difference between the number of elements in the playlist and the index of the removed element plus the number of items that were removed (1). There are more examples available in the Mafw API reference.

Moving items

Moving one element from one index to another can be done by calling mafw_playlist_move_item.

The example moves the element at position 3 to position 1, moving elements in positions 1 and 2 forward to positions 2 and 3. When invoking this method, the signal item-moved is emitted.

Getting information from playlists
Synchronously without metadata Developers traverse a playlist with a loop after obtaining the size of the playlist with mafw_playlist_get_size. For each element in the playlist one can use mafw_playlist_get_item to obtain the object identifier assigned to that entry. In order to obtain information other than the object identifier, the asynchronous API must be used.

Asynchronously with metadata In this case, mafw_playlist_get_items_md should be used, which allows to obtain metadata for the entries enclosed in a particular range of the playlist. This method requires a callback function that will be invoked once per entry in the playlist. The callback is passed a hash table with metadata associated to the media resource associated to the object identifier specified by object_id. This hash table may contain metadata with multiple values for each metadata key and this is why MAFW provides mafw_metadata_first to access the first (or only) value in the hash table for a particular metadata key. In order to obtain all the values for a particular metadata key, the developer can use the normal hash table API. In this case, if there is only one value for that metadata key, the hash table will return a GValue holding the value. If it is multi-valued, it will return a GValueArray. Take a look at the Mafw API reference for more info.

Shuffle and unshuffle When a playlist is created, it is unshuffled, which means that playing its contents in a renderer would play the items in the playlist in the same order they were inserted.

It is also possible to shuffle the elements in the playlist using mafw_playlist_shuffle, changing the default playing order.

The method mafw_playlist_get_starting_index can be called to obtain the index and object identifier of the first item of the playlist according to the playing order. The methods mafw_playlist_get_next and mafw_playlist_get_prev can be used to move to the next and previous elements respectively.

Because playlists are played in renderers, the only way to obtain information on which item of a playlist is being played is to obtain it from a renderer object to which the playlist has been assigned. The MafwRenderer::media-changed signal is emitted when the selected item in the playlist assigned to a particular renderer changes.

The application developer can also query the currently selected entry in the playlist assigned to a renderer using the method mafw_renderer_get_status (see the MAFW API reference for details).

Introduction
Sources are used to get access to multimedia repositories. For example, a source might provide access to UPnP servers, the multimedia files located at the local filesystem, or those housed at Bluetooth devices, etc. The main target of sources is to provide a way to query and retrieve information about available media files.

Sources identify media items by means of object identifiers. These identifiers are strings in the form:

&lt;Source-ID&gt;::&lt;Item-ID&gt;

consisting of the Source ID of the originating source and a unique (within the individual scope of the source) Item ID, separated by two colons. Each object ID should be unique, persistent and portable, if possible. Applications may assume that an object ID corresponds to a single content item, and this should be maintained across shutdowns, reboots and reinstalls. A specific object ID is meaningful only for the source that has produced it.

Sources provide a few services to applications, however, the most important are:


 * Browsing
 * Metadata retrieval

Browsing is the operation used to explore, query and filter contents from a particular source of media. Developers will use the browse interface, for example, to get a list of the songs or videos available, to access the songs of a particular artist, etc. Sources provide access to their contents exposing them through the browse interface using a container model: there is a root container, which object ID is &lt;Source-ID&gt;::, any container can contain other containers or media resources, very much like navigating a file system. The structure of containers exposed by the source is decided by the source developer.

Metadata retrieval is the operation used to obtain meta-information from a certain media resource. Developers will use this interface to obtain information like the title, artist or album of a particular media.

In addition to getting content information, one can also modify the contents with optional methods, intended for creating and removing contents from the source, as well as updating metadata for particular media items.

Sources are represented by the MafwSource class, which inherits from MafwExtension. Thus, sources have name, uuid and plugin properties and support run-time properties too. This class is intended to be an abstract base class for any source and it provides the definition of various of the interfaces commented above: mafw_source_browse, mafw_source_get_metadata, mafw_source_set_metadata, etc.

Application developers will use sources to browse available media resources and select media items to create playlists. Once a playlist has been created it can be assigned to a renderer to play its contents.

Sources can also communicate certain events using signals:


 * MafwSource::metadata-changed, informs about metadata changes in a particular media provided by a given source.
 * MafwSource::container-changed, informs about changes in the contents of a certain container provided by a given source.

Browsing the contents of a source
The major use case of a source is browsing. Developers can explore the contents of a particular container exposed by the source using the method mafw_source_browse and the object identifier of the container. The list of parameters is:


 * Source, the MafwSource instance to be browsed.
 * ObjectID, the object identifier of the container to be browsed.
 * Recursive, whether the container should be browsed recursively or not.
 * Filter, specifies an optional filter string in a syntax similar to that used in LDAP search filters.
 * Sort criteria, a string used to specify the criteria that should be followed to sort the browse results.
 * Keys, metadata keys we are interested in retrieving along with each object identifier returned with the browse operation.
 * Offset, the index of the first item to retrieve from the list of items that match the browse query.
 * Offset, the maximum number of elements to retrieve from the list of items that match the browse query, starting at the index specified by the Offset parameter.
 * Callback, this callback function is called whenever a matching result is found.
 * Callback user data, user data for the callback.

For more details, please check the MAFW API reference.

The mafw_source_browse function returns a browse identifier that can be used to match browse results with the corresponding browse operations.

The results of the browse call are returned using the provided callback. This callback is invoked each time a matching result is found by the source. Each time the callback is invoked it informs about:


 * Source, the MafwSource that is producing the result.
 * Browse ID, that allows the developer to match a result with a particular browse operation.
 * Remaining, which informs about the remaining items that have matched the browse query and are pending to be sent through the callback. When this value reaches 0 it means that all the results have been sent and the operations has finished.
 * Index, the index of the current item in the list of matched results.
 * Object ID, the object ID of the current item.
 * Metadata, the metadata values associated to the current item.
 * User Data, user data of the callback.
 * Error, a GError that, if set, informs of an error in the browse operation.

Also, in case that no results match the browse operation, the callback is invoked once, with the object ID parameter set to NULL.

Getting metadata
Another important use case of a source is to provide metadata about particular media. This can be achieved using mafw_source_get_metadata. This function queries metadata for a particular object ID (which should be valid for the source being queried, probably returned by a previous browse operation). The parameters passed to mafw_source_get_metadata are:


 * Source, the MafwSource to be queried.
 * Object ID, the object ID to get metadata from.
 * Keys, metadata information we are interested in.
 * Callback, the callback used to get the results.
 * User data, the user data for the callback.

The result of the metadata operation is returned using the callback provided. The parameters passed to the callback function are:


 * Source, the MafwSource that produced the result.
 * Object ID, the object ID the metadata comes from.
 * Metadata, the metadata values.
 * User data, the user data for the callback.
 * Error, a GError that, if set, informs of an error in the metadata retrieval operation.

This callback should be called only once.

Using a source
Sources are extensions, therefore, the first step is to obtain a reference to them using the framework registry. Please check section [localhost#sec:mafw_loading_extensions 8.5.2] for more information on this topic.

Once a reference to the source of interest has been obtained, the developer can start to use it. The way sources are used is usually this:


 * User wants to browse the contents of the source. The application should browse the root container of the selected source using mafw_source_browse and show the results to the user. The application developer should request the metadata MAFW_METADATA_KEY_MIME to distinguish containers from media items.
 * Once users have obtained the results of the browse operation, they may want to browse one of the containers contained in the root container, in this case the application should issue a new browse operation with the Object ID of the selected container, repeating the process.
 * Also, users may want to select browse results and include them in a playlist to be played later on in a renderer.
 * The user can also request more metadata from a specific item obtained in the browse operation, to do so, the developer should use mafw_source_get_metadata passing the Object ID of the selected item.

For more information about the source API, please check the MAFW API reference. The reader can also check complete source code examples in sections [localhost#sec:mafw_examples_source_browse 8.5.3] and [localhost#sec:mafw_examples_source_metadata 8.5.3].

Renderers
This section explains how to use renderers in a program. During this explanation it is recommended to follow section for a complete source code example illustrating many of the concepts explained below.

Introduction
Renderers are used to control media playback, and they are designed so that any of them can play content from any source, and can be thought of as a GStreamer chain, although this might usually not be the actual case.

MafwRenderer is a subclass of MafwExtension, so, it inherits its semantics. Thus, renderers have name, uuid and plugin properties and support run-time properties too. This class is intended to be an abstract base class for any renderer and it provides various 'playback-related operations: mafw_renderer_play, mafw_renderer_stop, mafw_renderer_pause, mafw_renderer_resume, etc. that any application can use to control media playback in a particular renderer.

An application can assign a playlist to a renderer. When this is done, the renderer will take over the responsibility for managing it properly, saving some effort to the application developer. For example, the renderer can detect an "end of stream" situation and move automatically to the next item in the playlist, it can readjust automatically when the playlist is being edited, rewind the playlist automatically when the end of the playlist has been reached or even restart playback if the user has enabled the repeat mode in the playlist.

The application can also control playlist playback, commanding the renderer to move to any item in the playlist at any moment.

Whenever a relevant change happens in the renderer, it notifies the application about it, so it can react properly. For example, if a renderer stops playing it notifies about its state change, so that the application can enable and/or disable options according to this situation. Renderers must emit signals when their state, their playlist or the media they are ready to play change.

Renderers also emit signals to inform about buffering progress (MafwRenderer::buffering-info) in the case of media streams, and metadata in the case the renderer is able to extract metadata from the media it is playing.

State management
Renderers behave like state machines. Operations may or may not be valid depending on the renderer's state, or may change their behavior depending on it. For example, a STOP command may be ignored if the renderer is already stopped, but otherwise it should stop any ongoing playback.

The renderer's state machine has four states:


 * Stopped
 * Transitioning
 * Playing
 * Paused

A renderer is Stopped if it is not playing any media. Whenever the renderer receives the order to play some media content, it moves to the Transitioning state. In this state, the renderer attempts to get anything it may need to play the selected item, for example, it should get the URI of the item to be played by invoking mafw_source_get_metadata, and then use this URI to start playback using the underlying playback engine (for example, GStreamer). The renderer moves to the Playing state once playback has been started by the underlying playback engine. During this state, the user can call mafw_renderer_pause, which makes the renderer move to Paused state. In this state, it is possible to call mafw_renderer_resume to continue playback. Also, the user may call mafw_source_stop at any time, making the renderer move back to the Stopped state again.

Application developers should react to state changes in the renderer and update the application accordingly. For example, when the renderer is in the Stopped state the developer may want to disable the Pause button, however if the renderer state is Playing it may be enabled.

Renderers inform about their state changes using the MafwRenderer::state-changed signal. Application developers should connect to this signal and place any state related management code there. It is also possible to query a renderer about its state by using mafw_renderer_get_status.

Assigning media to a renderer
In order to play content in a renderer, a playlist should be created and assigned to it. For this purpose developers have to use mafw_renderer_assign_playlist. Once a playlist has been assigned to the renderer the user may choose to start playback right away (starting from the first item in the playlist) or choose a specific item to start from. For the latter case, the renderer offers the methods mafw_renderer_next, mafw_renderer_previous and mafw_renderer_goto_index, that allow the user to select the next and previous items to the one currently selected or move directly to a particular item in the playlist. Also, the currently selected media may change due to other factors, for example, when playback of the current item in the playlist finishes the renderer will move to the next automatically, it might also happen in the case of errors that do not allow to play the current item, in this scenario the renderer may choose to automatically move to the next item in the playlist too.

No matter the reason that has triggered a change in the current media selected in the renderer, it will notify the application about the change by emitting a MafwRenderer::media-changed signal. Application developers should connect to this signal to update the application accordingly whenever new media is selected in the renderer. It is also possible to query a renderer about its current media by using mafw_renderer_get_status.

Error management
The renderer API functions always receive a callback as parameter. These functions include a GError parameter that is set in case an error happened during the execution of the operation. Developers should provide callback functions and check this error parameter to handle error conditions properly. If the error parameter is NULL it means the operation was executed successfully.

There are certain errors that may happen after the callback has been called. For example, a call to mafw_renderer_play may have finished without error, but after some time the underlying playback engine may detect an error (corrupted data, connection lost in the case of streams, etc). Because of this, there is another channel for error communication, in the form of signals. Developers should also connect to the MafwExtension::error signal to handle these errors properly.

Using a renderer
Renderers are extensions, therefore, the first step is to obtain a reference to them using the framework registry. Please check section [localhost#sec:mafw_loading_extensions 8.5.2] for more information on this topic.

Once a reference to a renderer has been obtained, the next step is to assign a playlist to it with mafw_renderer_assign_playlist. And start playing at any moment using mafw_renderer_play. From that moment on, other playback control functions like mafw_renderer_pause or mafw_renderer_stop can also be used.

Usually, it the developer will also want to connect to the renderer signals to capture and report playback errors, enable or disable controls in the UI whenever the renderer playback state or the currently selected media changes.

For further details on the renderer API, please check the MAFW API reference.

Built-in plugins
MAFW comes with a set of plugins already available. In order to obtain these plugins one has to install the appropriate MAFW packages. Currently, each plugin is delivered in a separate package. Below is a list of these plugins along with a brief description of each one:


 * Tracker Source: A source plugin implementing a MafwSource for accessing multimedia files stored in the local filesystem using Tracker as underlying engine.
 * UPnP Source: A source plugin implementing a MafwSource for accessing multimedia files stored in UPnP servers. This plugin instantiates one source extension per UPnP server discovered. The plugin is implemented using gUPnP.
 * IRadio Source: A source plugin implementing a MafwSource for providing support for multimedia bookmarks.
 * GStreamer Renderer: A renderer plugin implementing a MafwRenderer for playback using GStreamer as playback engine.

Creating plugins
This sections provides some information for developers interested in creating new extension plugins (Sources and/or Renderers).

Creating a source
A MAFW source is an element that can provide media information, this means available media resources over a protocol and their metadata. Accessing the media files stored in your local file system or the media served through UPnP servers are some examples.

Creating a MAFW source means creating a shared library containing a GObject that inherits from MafwSource and provide an implementation for some of the methods defined in that class.

All the methods have a default implementation in MafwSource that raise an error by default, so it is not mandatory to implement all the methods, but only the ones you want to support. The most important ones are:


 * mafw_source_browse: it is used to query the source about the available media.
 * mafw_source_cancel_browse: mafw_source_browse operations can take some time, so this method is intended to cancel ongoing browse operations.
 * mafw_source_get_metadata: it is used to request the metadata associated to a given media served by a source. For example, when a renderer tries to play a certain media included in a playlist, it has to obtain the URI associated to that media, this is done by calling mafw_source_get_metadata and passing the object identifier of the media.

Other methods are those related to creation or destruction of media items or metadata modification. Even if your source does not need to implement these methods, it may still be interesting to provide dummy implementations so that other components that use the source do not get errors then using these services. For example, a renderer may use the mafw_source_set_metadata method to automatically increase the play-count of media items when played. If a source returns an error when this method is invoked instead of of providing an empty implementation, the application could end up receiving that error message or the renderer may abort the playback operation, which may or may not be the intended behaviors.


 * mafw_source_set_metadata: Sets metadata for a particular media resource.
 * mafw_source_create_object: Adds a new media resource or container to a particular source.
 * mafw_source_destroy_object: Removes a media item or container from a particular source.

Other than creating a GObject the developer has to define a symbol containing the plugin name and functions to initialize and deinitialize the plugin. An example of this is: Creating a source plugin

  <font color="#000080"> # define  MAFW_SOURCE_PLUGIN_NAME <font color="#FF0000">"MySource-Plugin"  <font color="#000080"> # define  MAFW_SOURCE_NAME       <font color="#FF0000">"My Source"  <font color="#000080"> # define  MAFW_SOURCE_UUID       <font color="#FF0000">"mysource"  <font color="#0000FF">static  <font color="#008080">gboolean   <font color="#000000">mafw_my_source_initialize   <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  					  <font color="#008080">GError  <font color="#990000"> ** error <font color="#990000">);  <font color="#0000FF">static  <font color="#009900">void   <font color="#000000">mafw_my_source_deinitialize   <font color="#990000">(  <font color="#008080">GError  <font color="#990000"> ** error <font color="#990000">);  <font color="#9A1900">/*   <font color="#9A1900"> * Registers the plugin descriptor making this plugin available to the   <font color="#9A1900"> * framework and applications   <font color="#9A1900"> */  G_MODULE_EXPORT <font color="#008080">MafwPluginDescriptor mafw_my_source_plugin_description <font color="#990000"> = <font color="#FF0000">{ <font color="#FF0000">{ <font color="#990000">. name <font color="#990000"> = MAFW_MY_SOURCE_PLUGIN_NAME <font color="#FF0000">} <font color="#990000">, <font color="#990000">. initialize <font color="#990000"> = mafw_my_source_initialize <font color="#990000">, <font color="#990000">. deinitialize <font color="#990000"> = mafw_my_source_deinitialize <font color="#990000">, <font color="#FF0000">} <font color="#990000"> ;  <font color="#9A1900">/*  '' <font color="#9A1900"> * Plugin initialization. Sets UUID and name of this source and then '' '' <font color="#9A1900"> * adds it to the registry, making it available to applications.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  gboolean  <font color="#000000">mafw_my_source_initialize  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,                            <font color="#008080">GError  <font color="#990000"> ** error <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwMySource <font color="#990000"> * self <font color="#990000"> =   <font color="#000000">MAFW_MY_SOURCE   <font color="#990000">(   <font color="#000000">mafw_my_source_new   <font color="#990000">);  <font color="#000000">mafw_registry_add_extension  <font color="#990000">( registry <font color="#990000">,   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( self <font color="#990000">));  <font color="#000000">g_object_unref  <font color="#990000">( self <font color="#990000">);  <font color="#0000FF">return  TRUE <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * Plugin deinit   <font color="#9A1900"> */   <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">mafw_my_source_deinitialize  <font color="#990000">(  <font color="#008080">GError  <font color="#990000"> ** error <font color="#990000">)  <font color="#FF0000">{  <font color="#FF0000">} </tt>

The code above shows a plugin that can be recognized and loaded. The mafw_my_source_initialize function creates an instance of the source by using the object constructor method, and registers the source in the registry, making it available to applications. The object constructor method

 <font color="#008080">MafwSource <font color="#990000"> *   <font color="#000000">mafw_my_source_new   <font color="#990000">(  <font color="#009900">void  <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">return   <font color="#000000">MAFW_MY_SOURCE   <font color="#990000">(   <font color="#000000">g_object_new   <font color="#990000">( MAFW_TYPE_MY_SOURCE <font color="#990000">, <font color="#FF0000">"plugin" <font color="#990000">, MAFW_MY_SOURCE_PLUGIN_NAME <font color="#990000">, <font color="#FF0000">"uuid" <font color="#990000">, MAFW_MY_SOURCE_UUID <font color="#990000">, <font color="#FF0000">"name" <font color="#990000">, MAFW_MY_SOURCE_NAME <font color="#990000">, NULL <font color="#990000">)); <font color="#FF0000">} </tt>

Notice that the plugin initialization function may instantiate and register several objects (sources in this case). For example, a UPnP plugin may check for available UPnP servers and register a source object per server discovered.

For further details about the parameters received by functions and a deeper description of the MafwSource class, please take a look at the MAFW API reference.

Creating a renderer
A renderer is an element capable of playing media elements and playlists of media elements.

As in the case of MAFW sources, in order to create a renderer plugin a shared library should be implemented, as well as a module initializer and a GObject inheriting from MafwRenderer. An example would be very similar to the MAFW source's one.

Of course, the methods that have to be redefined are the ones defined at MafwRenderer, and again, the developer may choose not to provide an implementation for some of them. The MafwRenderer class defines many methods that can be classified like this:


 * Playback: Those used to control playback (play, stop, pause, resume, volume, etc)
 * Playlist management: Those used to assign a playlist to the renderer and manipulate it.
 * Status: Used to query the status of the renderer, like its current playback state or selected media.
 * Position: Used to query the current playback position or set it (seeking).

Renderers also define some signals that should be taken into account, such as:


 * MafwRenderer::playlist-changed, which should be emitted when a new playlist is assigned to the renderer.
 * MafwRenderer::media-changed, which should be emitted when new media is selected in the renderer.
 * MafwRenderer::state-changed, which should be emitted when the renderer changes from on state to another.
 * MafwRenderer::buffering-info, which should be emitted to inform about the buffering progress when playing streams.
 * MafwRenderer::metadata-changed, which should be emitted when the renderer obtains metadata information from the currently selected media.

Other issues
Properties MafwExtension objects (renderers and sources) can define properties (MafwExtension properties, not GObject's) to configure them on execution time. To use them, get and set functions have to be provided and hooked in the class_init method: Using extension properties

  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">mafw_my_renderer_get_property  <font color="#990000">(  <font color="#008080">MafwExtension  <font color="#990000"> * self <font color="#990000">,  	 		       <font color="#0000FF">const   <font color="#008080">gchar  <font color="#990000"> * key <font color="#990000">,  			      <font color="#008080">MafwExtensionPropertyCallback callback <font color="#990000">,  			      <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwMyRenderer <font color="#990000"> * renderer <font color="#990000"> ; <font color="#008080">GValue <font color="#990000"> * value <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ;  <font color="#000000">g_return_if_fail  <font color="#990000">(   <font color="#000000">MAFW_IS_MY_RENDERER   <font color="#990000">( self <font color="#990000">));  <font color="#000000">g_return_if_fail  <font color="#990000">( callback <font color="#990000"> != NULL <font color="#990000">);  <font color="#000000">g_return_if_fail  <font color="#990000">( key <font color="#990000"> != NULL <font color="#990000">); renderer <font color="#990000"> =  <font color="#000000">MAFW_MY_RENDERER   <font color="#990000">( self <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( key <font color="#990000">, MAFW_PROPERTY_RENDERER_VOLUME <font color="#990000">))  <font color="#FF0000">{ value <font color="#990000"> =  <font color="#000000">g_new0   <font color="#990000">( GValue <font color="#990000">,  <font color="#993399">1  <font color="#990000">);  <font color="#000000">g_value_init  <font color="#990000">( value <font color="#990000">, G_TYPE_UINT <font color="#990000">);  <font color="#000000">g_value_set_uint  <font color="#990000">( value <font color="#990000">, volume <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#0000FF">if   <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( key <font color="#990000">, MAFW_PROPERTY_RENDERER_MUTE <font color="#990000">))  <font color="#FF0000">{ <font color="#990000">... 	 <font color="#FF0000">}  <font color="#0000FF">else  <font color="#FF0000">{  <font color="#9A1900">/* Unsupported property */  error <font color="#990000"> =  <font color="#000000">g_error_new   <font color="#990000">( MAFW_MY_RENDERER_ERROR <font color="#990000">,  				    MAFW_EXTENSION_ERROR_GET_PROPERTY <font color="#990000">,  				    <font color="#FF0000">"Unsupported property"  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">callback  <font color="#990000">( self <font color="#990000">, key <font color="#990000">, value <font color="#990000">, user_data <font color="#990000">, error <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">static  gboolean  <font color="#000000">mafw_my_renderer_set_property  <font color="#990000">(  <font color="#008080">MafwExtension  <font color="#990000"> * self <font color="#990000">,                                 <font color="#0000FF">const   <font color="#008080">gchar  <font color="#990000"> * key <font color="#990000">,                                 <font color="#0000FF">const   <font color="#008080">GValue  <font color="#990000"> * value <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwMyRenderer <font color="#990000"> * renderer <font color="#990000"> ;  <font color="#000000">g_return_if_fail  <font color="#990000">(   <font color="#000000">MAFW_IS_MY_RENDERER   <font color="#990000">( self <font color="#990000">));  <font color="#000000">g_return_if_fail  <font color="#990000">( key <font color="#990000"> != NULL <font color="#990000">); renderer <font color="#990000"> =  <font color="#000000">MAFW_MY_RENDERER   <font color="#990000">( self <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( key <font color="#990000">, MAFW_PROPERTY_RENDERER_VOLUME <font color="#990000">))  <font color="#FF0000">{ <font color="#008080">guint volume <font color="#990000"> =  <font color="#000000">g_value_get_uint   <font color="#990000">( value <font color="#990000">); volume <font color="#990000"> =  <font color="#000000">CLAMP   <font color="#990000">( volume <font color="#990000">,  <font color="#993399">0  <font color="#990000">,  <font color="#993399">100  <font color="#990000">);  <font color="#000000">_do_set_volume  <font color="#990000">( renderer <font color="#990000">, volume <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#0000FF">if   <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( key <font color="#990000">, MAFW_PROPERTY_RENDERER_MUTE <font color="#990000">))  <font color="#FF0000">{ <font color="#990000">...         <font color="#FF0000">}  <font color="#0000FF">else  <font color="#FF0000">{  <font color="#9A1900">/* Unsupported property */   <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#000000">mafw_extension_emit_property_changed  <font color="#990000">( self <font color="#990000">, key <font color="#990000">, value <font color="#990000">);  <font color="#0000FF">return  TRUE <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void   <font color="#000000">mafw_my_renderer_class_init   <font color="#990000">(  <font color="#008080">MafwMyRendererClass  <font color="#990000"> * klass <font color="#990000">) <font color="#FF0000">{ <font color="#990000">...          <font color="#000000">MAFW_EXTENSION_CLASS   <font color="#990000">( klass <font color="#990000">)-&gt; get_extension_property <font color="#990000"> = <font color="#990000">( gpointer <font color="#990000">) mafw_my_renderer_get_property <font color="#990000"> ;  <font color="#000000">MAFW_EXTENSION_CLASS  <font color="#990000">( klass <font color="#990000">)-&gt; set_extension_property <font color="#990000"> = <font color="#990000">( gpointer <font color="#990000">) mafw_my_renderer_set_property <font color="#990000"> ; <font color="#990000">... <font color="#FF0000">} </tt>

Properties declaration is done in the object's init function: Registering extension properties

  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">mafw_my_renderer_get_property  <font color="#990000">(  <font color="#008080">MafwExtension  <font color="#990000"> * self <font color="#990000">,  	 		       <font color="#0000FF">const   <font color="#008080">gchar  <font color="#990000"> * key <font color="#990000">,  			      <font color="#008080">MafwExtensionPropertyCallback callback <font color="#990000">,  			      <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwMyRenderer <font color="#990000"> * renderer <font color="#990000"> ; <font color="#008080">GValue <font color="#990000"> * value <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ;  <font color="#000000">g_return_if_fail  <font color="#990000">(   <font color="#000000">MAFW_IS_MY_RENDERER   <font color="#990000">( self <font color="#990000">));  <font color="#000000">g_return_if_fail  <font color="#990000">( callback <font color="#990000"> != NULL <font color="#990000">);  <font color="#000000">g_return_if_fail  <font color="#990000">( key <font color="#990000"> != NULL <font color="#990000">); renderer <font color="#990000"> =  <font color="#000000">MAFW_MY_RENDERER   <font color="#990000">( self <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( key <font color="#990000">, MAFW_PROPERTY_RENDERER_VOLUME <font color="#990000">))  <font color="#FF0000">{ value <font color="#990000"> =  <font color="#000000">g_new0   <font color="#990000">( GValue <font color="#990000">,  <font color="#993399">1  <font color="#990000">);  <font color="#000000">g_value_init  <font color="#990000">( value <font color="#990000">, G_TYPE_UINT <font color="#990000">);  <font color="#000000">g_value_set_uint  <font color="#990000">( value <font color="#990000">, volume <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#0000FF">if   <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( key <font color="#990000">, MAFW_PROPERTY_RENDERER_MUTE <font color="#990000">))  <font color="#FF0000">{ <font color="#990000">... 	 <font color="#FF0000">}  <font color="#0000FF">else  <font color="#FF0000">{  <font color="#9A1900">/* Unsupported property */  error <font color="#990000"> =  <font color="#000000">g_error_new   <font color="#990000">( MAFW_MY_RENDERER_ERROR <font color="#990000">,  				    MAFW_EXTENSION_ERROR_GET_PROPERTY <font color="#990000">,  				    <font color="#FF0000">"Unsupported property"  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">callback  <font color="#990000">( self <font color="#990000">, key <font color="#990000">, value <font color="#990000">, user_data <font color="#990000">, error <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">static  gboolean  <font color="#000000">mafw_my_renderer_set_property  <font color="#990000">(  <font color="#008080">MafwExtension  <font color="#990000"> * self <font color="#990000">,                                 <font color="#0000FF">const   <font color="#008080">gchar  <font color="#990000"> * key <font color="#990000">,                                 <font color="#0000FF">const   <font color="#008080">GValue  <font color="#990000"> * value <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwMyRenderer <font color="#990000"> * renderer <font color="#990000"> ;  <font color="#000000">g_return_if_fail  <font color="#990000">(   <font color="#000000">MAFW_IS_MY_RENDERER   <font color="#990000">( self <font color="#990000">));  <font color="#000000">g_return_if_fail  <font color="#990000">( key <font color="#990000"> != NULL <font color="#990000">); renderer <font color="#990000"> =  <font color="#000000">MAFW_MY_RENDERER   <font color="#990000">( self <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( key <font color="#990000">, MAFW_PROPERTY_RENDERER_VOLUME <font color="#990000">))  <font color="#FF0000">{ <font color="#008080">guint volume <font color="#990000"> =  <font color="#000000">g_value_get_uint   <font color="#990000">( value <font color="#990000">); volume <font color="#990000"> =  <font color="#000000">CLAMP   <font color="#990000">( volume <font color="#990000">,  <font color="#993399">0  <font color="#990000">,  <font color="#993399">100  <font color="#990000">);  <font color="#000000">_do_set_volume  <font color="#990000">( renderer <font color="#990000">, volume <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#0000FF">if   <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( key <font color="#990000">, MAFW_PROPERTY_RENDERER_MUTE <font color="#990000">))  <font color="#FF0000">{ <font color="#990000">...         <font color="#FF0000">}  <font color="#0000FF">else  <font color="#FF0000">{  <font color="#9A1900">/* Unsupported property */   <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#000000">mafw_extension_emit_property_changed  <font color="#990000">( self <font color="#990000">, key <font color="#990000">, value <font color="#990000">);  <font color="#0000FF">return  TRUE <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void   <font color="#000000">mafw_my_renderer_class_init   <font color="#990000">(  <font color="#008080">MafwMyRendererClass  <font color="#990000"> * klass <font color="#990000">) <font color="#FF0000">{ <font color="#990000">...          <font color="#000000">MAFW_EXTENSION_CLASS   <font color="#990000">( klass <font color="#990000">)-&gt; get_extension_property <font color="#990000"> = <font color="#990000">( gpointer <font color="#990000">) mafw_my_renderer_get_property <font color="#990000"> ;  <font color="#000000">MAFW_EXTENSION_CLASS  <font color="#990000">( klass <font color="#990000">)-&gt; set_extension_property <font color="#990000"> = <font color="#990000">( gpointer <font color="#990000">) mafw_my_renderer_set_property <font color="#990000"> ; <font color="#990000">... <font color="#FF0000">} </tt>

The code shows examples of renderer properties, but the same could be applied to sources (as this is a mechanism defined for any kind of extension), for example, a slow source could use properties to define an eager vs. lazy strategy or the use of caches.

Code examples
This section contains a few source code exampled that illustrate how to use MAFW. These examples are referenced from other parts of this tutorial.

Source browse example
This program is a simple command line program that allows the user to browse the contents of arbitrary containers of the local filesystem source using the mafw-tracker-source plugin. So, be sure you have this plugin installed (and running if you want to use it in out-of-process mode)!

To build the example : Source browse example

libtool -mode <font color="#990000"> = link gcc -o mafw-browse-example <font color="#990000">\ `pkg-config -cflags -libs mafw mafw-shared` mafw-browse-example <font color="#990000">. c </tt>

To run the example : run-standalone.sh ./mafw-browse-example &lt;object-id&gt;

For example, the object identifier of the root container of this source is localtagfs:: :

run-standalone.sh ./mafw-browse-example localtagfs::

The source code : Source browse example

  <font color="#9A1900">/*   <font color="#9A1900">The code examples copyrighted by Nokia Corporation that are included to   <font color="#9A1900">this material are licensed to you under following MIT-style License:   <font color="#9A1900">Permission is hereby granted, free of charge, to any person obtaining a   <font color="#9A1900">copy of this software and associated documentation files (the   <font color="#9A1900">"Software"), to deal in the Software without restriction, including   <font color="#9A1900">without limitation the rights to use, copy, modify, merge, publish,   <font color="#9A1900">distribute, sublicense, and/or sell copies of the Software, and to   <font color="#9A1900">permit persons to whom the Software is furnished to do so, subject to   <font color="#9A1900">the following conditions:   <font color="#9A1900">The above copyright notice and this permission notice shall be included  '' <font color="#9A1900">in all copies or substantial portions of the Software.   <font color="#9A1900">THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ''  <font color="#9A1900">OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  '' <font color="#9A1900">MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   <font color="#9A1900">IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ''  <font color="#9A1900">CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   <font color="#9A1900">TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE  '' <font color="#9A1900">SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.   <font color="#9A1900"> */ ''  <font color="#000080"> #include  <font color="#FF0000">&lt;string.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;stdlib.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;glib.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw-log.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw-registry.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw-shared/mafw-shared.h&gt;  <font color="#000080"> #undef  G_LOG_DOMAIN  <font color="#000080"> #define  G_LOG_DOMAIN <font color="#FF0000">"mafw-example"  <font color="#000080"> #define  WANTED_SOURCE    <font color="#FF0000">"Mafw-Tracker-Source" <font color="#008080">MafwSource <font color="#990000"> * app_source <font color="#990000"> = NULL <font color="#990000"> ; GMainLoop <font color="#990000"> * main_loop <font color="#990000"> = NULL <font color="#990000"> ;  <font color="#9A1900">/*   <font color="#9A1900"> * This callback is invoked whenever a browse result is available   <font color="#9A1900"> */   <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">browse_request_cb  <font color="#990000">(  <font color="#008080">MafwSource  <font color="#990000"> * source <font color="#990000">,  		   <font color="#008080">guint browse_id <font color="#990000">,  		   <font color="#008080">gint remaining <font color="#990000">,  		   <font color="#008080">guint index <font color="#990000">,  		    <font color="#0000FF">const   <font color="#008080">gchar  <font color="#990000"> * object_id <font color="#990000">,  		   <font color="#008080">GHashTable  <font color="#990000"> * metadata <font color="#990000">,  		   <font color="#008080">gpointer user_data <font color="#990000">,  		    <font color="#0000FF">const   <font color="#008080">GError  <font color="#990000"> * error <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">const  <font color="#008080">gchar  <font color="#990000"> * title <font color="#990000">,  <font color="#990000"> * artist <font color="#990000">,  <font color="#990000"> * album <font color="#990000">,  <font color="#990000"> * genre <font color="#990000"> ;  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"Browse error: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, error <font color="#990000">-&gt; message <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( object_id <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Sorry, no songs found!  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Got result %d:  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, index <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( metadata <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{ title <font color="#990000"> = <font color="#FF0000">"Unknown"  <font color="#990000"> ; artist <font color="#990000"> = <font color="#FF0000">"Unknown"  <font color="#990000"> ; album <font color="#990000"> = <font color="#FF0000">"Unknown"  <font color="#990000"> ; genre <font color="#990000"> = <font color="#FF0000">"Unknown"  <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{ <font color="#008080">GValue <font color="#990000"> * v <font color="#990000"> ; v <font color="#990000"> =  <font color="#000000">mafw_metadata_first   <font color="#990000">( metadata <font color="#990000">,  						 MAFW_METADATA_KEY_TITLE <font color="#990000">); title <font color="#990000"> = v <font color="#990000">?  <font color="#000000">g_value_get_string  <font color="#990000">( v <font color="#990000">)  <font color="#990000"> :  <font color="#FF0000">"Unknown"  <font color="#990000"> ; v <font color="#990000"> =  <font color="#000000">mafw_metadata_first   <font color="#990000">( metadata <font color="#990000">,  						 MAFW_METADATA_KEY_ARTIST <font color="#990000">); artist <font color="#990000"> = v <font color="#990000">?  <font color="#000000">g_value_get_string  <font color="#990000">( v <font color="#990000">)  <font color="#990000"> :  <font color="#FF0000">"Unknown"  <font color="#990000"> ; v <font color="#990000"> =  <font color="#000000">mafw_metadata_first   <font color="#990000">( metadata <font color="#990000">,  						 MAFW_METADATA_KEY_ALBUM <font color="#990000">); album <font color="#990000"> = v <font color="#990000">?  <font color="#000000">g_value_get_string  <font color="#990000">( v <font color="#990000">)  <font color="#990000"> :  <font color="#FF0000">"Unknown"  <font color="#990000"> ; v <font color="#990000"> =  <font color="#000000">mafw_metadata_first   <font color="#990000">( metadata <font color="#990000">,  						 MAFW_METADATA_KEY_GENRE <font color="#990000">); genre <font color="#990000"> = v <font color="#990000">?  <font color="#000000">g_value_get_string  <font color="#990000">( v <font color="#990000">)  <font color="#990000"> :  <font color="#FF0000">"Unknown"  <font color="#990000"> ; <font color="#FF0000">}  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]       Object ID: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, object_id <font color="#990000">);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]           Title: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, title <font color="#990000">);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]          Artist: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, artist <font color="#990000">);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]           Album: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, album <font color="#990000">);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]           Genre: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, genre <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( remaining <font color="#990000"> ==  <font color="#993399">0  <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Browse operaton finished. Exiting...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#000000">g_main_loop_quit  <font color="#990000">( main_loop <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">}  <font color="#9A1900">/*  '' <font color="#9A1900"> * This function executes a browse request on the selected source.   <font color="#9A1900"> * This function receives the object identifier to browse as parameter.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  gboolean  <font color="#000000">do_browse_request  <font color="#990000">(  <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{ <font color="#008080">guint browse_id <font color="#990000"> ;  <font color="#0000FF">const  <font color="#008080">gchar  <font color="#990000"> *   <font color="#0000FF">const   <font color="#990000"> * keys <font color="#990000"> ; <font color="#008080">gchar <font color="#990000"> * object_id <font color="#990000"> =  <font color="#990000">( gchar <font color="#990000"> *) user_data <font color="#990000"> ;  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Browsing %s on "  WANTED_SOURCE <font color="#FF0000">".  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, object_id <font color="#990000">); keys <font color="#990000"> =  <font color="#000000">MAFW_SOURCE_LIST   <font color="#990000">(  	       MAFW_METADATA_KEY_TITLE <font color="#990000">,  	       MAFW_METADATA_KEY_ARTIST <font color="#990000">,  	       MAFW_METADATA_KEY_ALBUM <font color="#990000">,  	       MAFW_METADATA_KEY_GENRE <font color="#990000">); browse_id <font color="#990000"> =  <font color="#000000">mafw_source_browse  <font color="#990000">( app_source <font color="#990000">,         <font color="#9A1900">/* Source */   				    object_id <font color="#990000">,          <font color="#9A1900">/* Object identifier */   				    FALSE <font color="#990000">,              <font color="#9A1900">/* Recursive */   				    NULL <font color="#990000">,               <font color="#9A1900">/* Filter */   				    NULL <font color="#990000">,               <font color="#9A1900">/* Sorting */   				    keys <font color="#990000">,               <font color="#9A1900">/* Requested keys */   				    <font color="#993399">0  <font color="#990000">,  <font color="#993399">30  <font color="#990000">,              <font color="#9A1900">/* Offset, Count*/   				    browse_request_cb <font color="#990000">,   <font color="#9A1900">/* Callback */  NULL <font color="#990000">);             <font color="#9A1900">/* User data */   	  <font color="#0000FF">if   <font color="#990000">( browse_id <font color="#990000"> == MAFW_SOURCE_INVALID_BROWSE_ID <font color="#990000">)  <font color="#FF0000">{  		  <font color="#000000">g_warning   <font color="#990000">(  <font color="#FF0000">"Incorrect browse request.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  	 <font color="#FF0000">}  	  <font color="#0000FF">return  FALSE <font color="#990000"> ;  <font color="#FF0000">}   <font color="#9A1900">/*    <font color="#9A1900"> * Hooks for extension added and removed signals    <font color="#9A1900"> */    <font color="#9A1900">/*    <font color="#9A1900"> * Checks for a particular source to be added and    <font color="#9A1900"> * saves a reference to it.   <font color="#9A1900"> */   <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">source_added_cb  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  		 <font color="#008080">GObject  <font color="#990000"> * source <font color="#990000">,  		 <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_SOURCE   <font color="#990000">( source <font color="#990000">))  <font color="#FF0000">{  <font color="#0000FF">const  <font color="#008080">gchar  <font color="#990000"> * name <font color="#990000"> =  <font color="#000000">mafw_extension_get_name  <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( source <font color="#990000">));  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Source %s available.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, name <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">strcmp   <font color="#990000">( name <font color="#990000">, WANTED_SOURCE <font color="#990000">)  <font color="#990000"> ==  <font color="#993399">0  <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Wanted source found!  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); app_source <font color="#990000"> =  <font color="#000000">g_object_ref   <font color="#990000">( source <font color="#990000">);  <font color="#9A1900">/* When we find the source we are interested in,   <font color="#9A1900">			  do a browse request */   <font color="#000000">g_timeout_add  <font color="#990000">(  <font color="#993399">1000  <font color="#990000">, do_browse_request <font color="#990000">, user_data <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Not interesting. Skipping...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">} <font color="#FF0000">}  <font color="#9A1900">/*  '' <font color="#9A1900"> * Checks if the referenced source is removed, and if so, exits.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">source_removed_cb  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  		   <font color="#008080">GObject  <font color="#990000"> * source <font color="#990000">,  		   <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_SOURCE   <font color="#990000">( source <font color="#990000">))  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Source %s removed.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  			  <font color="#000000">mafw_extension_get_name   <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( source <font color="#990000">)));  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_SOURCE   <font color="#990000">( source <font color="#990000">)  <font color="#990000"> == app_source <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Wanted source removed!"  				 <font color="#FF0000">" Exiting...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#000000">g_object_unref  <font color="#990000">( app_source <font color="#990000">);  <font color="#000000">g_main_loop_quit  <font color="#990000">( main_loop <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">renderer_added_cb  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  		   <font color="#008080">GObject  <font color="#990000"> * renderer <font color="#990000">,  		   <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_RENDERER   <font color="#990000">( renderer <font color="#990000">))  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Renderer %s available.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  			  <font color="#000000">mafw_extension_get_name   <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( renderer <font color="#990000">))); <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">renderer_removed_cb  <font color="#990000">( MafwRegistry <font color="#990000"> * registry <font color="#990000">,  		     <font color="#008080">GObject  <font color="#990000"> * renderer <font color="#990000">,  		     <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_RENDERER   <font color="#990000">( renderer <font color="#990000">))  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Renderer %s removed.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  			  <font color="#000000">mafw_extension_get_name   <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( renderer <font color="#990000">))); <font color="#FF0000">} <font color="#FF0000">}  <font color="#9A1900">/*  '' <font color="#9A1900"> * Loads MAFW plugins.   <font color="#9A1900"> * ''  <font color="#9A1900"> * This function lods out-of-process extensions and hooks to   <font color="#9A1900"> * source-added and source-removed signals for dynamic extension  '' <font color="#9A1900"> * discovery and removal.   <font color="#9A1900"> * ''  <font color="#9A1900"> * Also, this function allows loading of in-process extensions  '' <font color="#9A1900"> * defined through an environment variable.   <font color="#9A1900"> * ''  <font color="#9A1900"> * The object_id parameter is used to browse that object as soon  '' <font color="#9A1900"> * as the source of interest is loaded.   <font color="#9A1900"> */ '' gboolean  <font color="#0000FF">static   <font color="#000000">app_init  <font color="#990000">(  <font color="#008080">gchar  <font color="#990000"> * object_id <font color="#990000">) <font color="#FF0000">{ <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">gchar <font color="#990000"> ** plugins <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">GList <font color="#990000"> * extension_list <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">MafwRegistry <font color="#990000"> * registry <font color="#990000"> = NULL <font color="#990000"> ;  <font color="#9A1900">/* --- Basic MAFW setup -- */   <font color="#9A1900">/* Init GType */   <font color="#000000">g_type_init  <font color="#990000">;  <font color="#9A1900">/* Init MAFW log (show all messages) */   <font color="#000000">mafw_log_init  <font color="#990000">( G_LOG_DOMAIN <font color="#FF0000">":ALL"  <font color="#990000">);  <font color="#9A1900">/* -- Start out-of-process plugin loading -- */   <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Checking for out-of-process plugins...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#9A1900">/* Check available plugins */  registry <font color="#990000"> =  <font color="#000000">MAFW_REGISTRY   <font color="#990000">(   <font color="#000000">mafw_registry_get_instance   <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( registry <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"app_init: Failed to get MafwRegistry reference  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/* Start out-of-process extension discovery */   <font color="#000000">mafw_shared_init  <font color="#990000">( registry <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">) <font color="#FF0000">{  <font color="#000000">g_warning  <font color="#990000">(  <font color="#FF0000">"Ext. discovery failed: %s"  <font color="#990000">,  			   error <font color="#990000">-&gt; message <font color="#990000">);  <font color="#000000">g_error_free  <font color="#990000">( error <font color="#990000">); error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#FF0000">} '' <font color="#9A1900">/* Connect to extension discovery signals. These signals will be ''  <font color="#9A1900">	  emitted when new extensions are started or removed */   <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"renderer_added"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( renderer_added_cb <font color="#990000">), NULL <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"renderer_removed"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( renderer_removed_cb <font color="#990000">), NULL <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"source_added"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( source_added_cb <font color="#990000">), object_id <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"source_removed"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( source_removed_cb <font color="#990000">), NULL <font color="#990000">);  <font color="#9A1900">/* Also, check for already started extensions */  extension_list <font color="#990000"> =  <font color="#000000">mafw_registry_get_renderers   <font color="#990000">( registry <font color="#990000">);  <font color="#0000FF">while  <font color="#990000">( extension_list <font color="#990000">) <font color="#FF0000">{  <font color="#000000">renderer_added_cb  <font color="#990000">( registry <font color="#990000">,  				    <font color="#000000">G_OBJECT   <font color="#990000">( extension_list <font color="#990000">-&gt; data <font color="#990000">), NULL <font color="#990000">); extension_list <font color="#990000"> =  <font color="#000000">g_list_next   <font color="#990000">( extension_list <font color="#990000">); <font color="#FF0000">} extension_list <font color="#990000"> =  <font color="#000000">mafw_registry_get_sources   <font color="#990000">( registry <font color="#990000">);  <font color="#0000FF">while  <font color="#990000">( extension_list <font color="#990000">) <font color="#FF0000">{  <font color="#000000">source_added_cb  <font color="#990000">( registry <font color="#990000">,  				  <font color="#000000">G_OBJECT   <font color="#990000">( extension_list <font color="#990000">-&gt; data <font color="#990000">), NULL <font color="#990000">); extension_list <font color="#990000"> =  <font color="#000000">g_list_next   <font color="#990000">( extension_list <font color="#990000">); <font color="#FF0000">}  <font color="#9A1900">/* -- Start in-process plugin loading -- */   <font color="#9A1900">/* MAFW_INP_PLUGINS shold contain a list of paths   <font color="#9A1900">	  to plugin files to be loaded in-process */   <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Checking for in-process plugins...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">g_getenv   <font color="#990000">(  <font color="#FF0000">"MAFW_INP_PLUGINS"  <font color="#990000">)  <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{ plugins <font color="#990000"> =  <font color="#000000">g_strsplit   <font color="#990000">(   <font color="#000000">g_getenv   <font color="#990000">(  <font color="#FF0000">"MAFW_INP_PLUGINS"  <font color="#990000">),  				      G_SEARCHPATH_SEPARATOR_S <font color="#990000">,  				      <font color="#993399">0  <font color="#990000">);  <font color="#0000FF">for  <font color="#990000">(NULL <font color="#990000"> !=  <font color="#990000"> * plugins <font color="#990000"> ; plugins <font color="#990000">++)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Loading in-process plugin %s...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  				 <font color="#990000"> * plugins <font color="#990000">);  <font color="#000000">mafw_registry_load_plugin  <font color="#990000">(   <font color="#000000">MAFW_REGISTRY   <font color="#990000">( registry <font color="#990000">),  						   <font color="#990000"> * plugins <font color="#990000">,  						   <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{ gchar <font color="#990000"> * msg <font color="#990000"> ; msg <font color="#990000"> =  <font color="#000000">g_strdup_printf   <font color="#990000">(  					 <font color="#FF0000">"Unable to load inp. plugin %s: %s"  <font color="#990000">,  					 <font color="#990000"> * plugins <font color="#990000">,  					error <font color="#990000">-&gt; message <font color="#990000">);  <font color="#000000">g_warning  <font color="#990000">(  <font color="#FF0000">"Plugin loading failed: %s"  <font color="#990000">, msg <font color="#990000">);  <font color="#000000">g_free  <font color="#990000">( msg <font color="#990000">);  <font color="#000000">g_error_free  <font color="#990000">( error <font color="#990000">); error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#FF0000">} <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     No in-process plugins requested.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">} <font color="#009900">int  <font color="#000000">main  <font color="#990000">(  <font color="#009900">int argc <font color="#990000">,  <font color="#008080">gchar  <font color="#990000"> * argv <font color="#990000">[]) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">( argc <font color="#990000"> !=  <font color="#993399">2  <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"Please, provide exactly one argument specifying "  			 <font color="#FF0000">"the object identifier of the item to browse."  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Starting example...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#000000">app_init  <font color="#990000">( argv <font color="#990000">[  <font color="#993399">1  <font color="#990000">]);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Example started.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); main_loop <font color="#990000"> =  <font color="#000000">g_main_loop_new   <font color="#990000">( NULL <font color="#990000">, FALSE <font color="#990000">);  <font color="#000000">g_main_loop_run  <font color="#990000">( main_loop <font color="#990000">);  <font color="#0000FF">return  <font color="#993399">0  <font color="#990000"> ; <font color="#FF0000">} </tt>

Source metadata example
This program is a simple command line program that allows the user to list some metadata values of arbitrary elements of the local filesystem source using the mafw-tracker-source plugin. So, be sure you have this plugin installed (and running if you want to use it in out-of-process mode)!

To build the example : Source metadata example

libtool -mode <font color="#990000"> = link gcc -o mafw-metadata-example <font color="#990000">\ `pkg-config -cflags -libs mafw mafw-shared` mafw-metadata-example <font color="#990000">. c </tt>

To run the example : run-standalone.sh ./mafw-metadata-example &lt;object-id&gt;

A valid object identifier can be obtained using the browse example, by browsing the all songs container (localtagfs::music/songs), and checking the object identifiers of the contained songs.

The source code : Source metadata example

  <font color="#9A1900">/*   <font color="#9A1900">The code examples copyrighted by Nokia Corporation that are included to   <font color="#9A1900">this material are licensed to you under following MIT-style License:   <font color="#9A1900">Permission is hereby granted, free of charge, to any person obtaining a   <font color="#9A1900">copy of this software and associated documentation files (the   <font color="#9A1900">"Software"), to deal in the Software without restriction, including   <font color="#9A1900">without limitation the rights to use, copy, modify, merge, publish,   <font color="#9A1900">distribute, sublicense, and/or sell copies of the Software, and to   <font color="#9A1900">permit persons to whom the Software is furnished to do so, subject to   <font color="#9A1900">the following conditions:   <font color="#9A1900">The above copyright notice and this permission notice shall be included  '' <font color="#9A1900">in all copies or substantial portions of the Software.   <font color="#9A1900">THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ''  <font color="#9A1900">OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  '' <font color="#9A1900">MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   <font color="#9A1900">IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ''  <font color="#9A1900">CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   <font color="#9A1900">TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE  '' <font color="#9A1900">SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.   <font color="#9A1900"> */ ''  <font color="#000080"> #include  <font color="#FF0000">&lt;string.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;stdlib.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;glib.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw-log.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw-registry.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw-shared/mafw-shared.h&gt;  <font color="#000080"> #undef  G_LOG_DOMAIN  <font color="#000080"> #define  G_LOG_DOMAIN <font color="#FF0000">"mafw-example"  <font color="#000080"> #define  WANTED_SOURCE    <font color="#FF0000">"Mafw-Tracker-Source" <font color="#008080">MafwSource <font color="#990000"> * app_source <font color="#990000"> = NULL <font color="#990000"> ; GMainLoop <font color="#990000"> * main_loop <font color="#990000"> = NULL <font color="#990000"> ;  <font color="#9A1900">/*   <font color="#9A1900"> * This callback is invoked whenever a browse result is available   <font color="#9A1900"> */   <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">metadata_request_cb  <font color="#990000">(  <font color="#008080">MafwSource  <font color="#990000"> * source <font color="#990000">,  		      <font color="#0000FF">const   <font color="#008080">gchar  <font color="#990000"> * object_id <font color="#990000">,  		     <font color="#008080">GHashTable  <font color="#990000"> * metadata <font color="#990000">,  		     <font color="#008080">gpointer user_data <font color="#990000">,  		      <font color="#0000FF">const   <font color="#008080">GError  <font color="#990000"> * error <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">const  <font color="#008080">gchar  <font color="#990000"> * title <font color="#990000">,  <font color="#990000"> * artist <font color="#990000">,  <font color="#990000"> * album <font color="#990000">,  <font color="#990000"> * genre <font color="#990000"> ;  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"Metadata error: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, error <font color="#990000">-&gt; message <font color="#990000">); <font color="#FF0000">}  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Got metadata:  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( metadata <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{ title <font color="#990000"> = <font color="#FF0000">"Unknown"  <font color="#990000"> ; artist <font color="#990000"> = <font color="#FF0000">"Unknown"  <font color="#990000"> ; album <font color="#990000"> = <font color="#FF0000">"Unknown"  <font color="#990000"> ; genre <font color="#990000"> = <font color="#FF0000">"Unknown"  <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{ <font color="#008080">GValue <font color="#990000"> * v <font color="#990000"> ; v <font color="#990000"> =  <font color="#000000">mafw_metadata_first   <font color="#990000">( metadata <font color="#990000">,  					 MAFW_METADATA_KEY_TITLE <font color="#990000">); title <font color="#990000"> = v <font color="#990000">?  <font color="#000000">g_value_get_string  <font color="#990000">( v <font color="#990000">)  <font color="#990000"> :  <font color="#FF0000">"Unknown"  <font color="#990000"> ; v <font color="#990000"> =  <font color="#000000">mafw_metadata_first   <font color="#990000">( metadata <font color="#990000">,  					 MAFW_METADATA_KEY_ARTIST <font color="#990000">); artist <font color="#990000"> = v <font color="#990000">?  <font color="#000000">g_value_get_string  <font color="#990000">( v <font color="#990000">)  <font color="#990000"> :  <font color="#FF0000">"Unknown"  <font color="#990000"> ; v <font color="#990000"> =  <font color="#000000">mafw_metadata_first   <font color="#990000">( metadata <font color="#990000">,  					 MAFW_METADATA_KEY_ALBUM <font color="#990000">); album <font color="#990000"> = v <font color="#990000">?  <font color="#000000">g_value_get_string  <font color="#990000">( v <font color="#990000">)  <font color="#990000"> :  <font color="#FF0000">"Unknown"  <font color="#990000"> ; v <font color="#990000"> =  <font color="#000000">mafw_metadata_first   <font color="#990000">( metadata <font color="#990000">,  					 MAFW_METADATA_KEY_GENRE <font color="#990000">); genre <font color="#990000"> = v <font color="#990000">?  <font color="#000000">g_value_get_string  <font color="#990000">( v <font color="#990000">)  <font color="#990000"> :  <font color="#FF0000">"Unknown"  <font color="#990000"> ; <font color="#FF0000">}  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]           Title: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, title <font color="#990000">);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]          Artist: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, artist <font color="#990000">);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]           Album: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, album <font color="#990000">);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]           Genre: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, genre <font color="#990000">); <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * This function executes a metadata request on the selected source  '' <font color="#9A1900"> * for the object identifier passed as user data.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  gboolean  <font color="#000000">do_metadata_request  <font color="#990000">(  <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{ <font color="#008080">guint browse_id <font color="#990000"> ;  <font color="#0000FF">const  <font color="#008080">gchar  <font color="#990000"> *   <font color="#0000FF">const   <font color="#990000"> * keys <font color="#990000"> ; <font color="#008080">gchar <font color="#990000"> * object_id <font color="#990000"> =  <font color="#990000">( gchar <font color="#990000"> *) user_data <font color="#990000"> ;  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Requesting metadata for %s on "  		 WANTED_SOURCE <font color="#FF0000">".  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, object_id <font color="#990000">); keys <font color="#990000"> =  <font color="#000000">MAFW_SOURCE_LIST   <font color="#990000">(  	       MAFW_METADATA_KEY_TITLE <font color="#990000">,  	       MAFW_METADATA_KEY_ARTIST <font color="#990000">,  	       MAFW_METADATA_KEY_ALBUM <font color="#990000">,  	       MAFW_METADATA_KEY_GENRE <font color="#990000">);  <font color="#000000">mafw_source_get_metadata  <font color="#990000">( app_source <font color="#990000">,  				  object_id <font color="#990000">,  				  keys <font color="#990000">,  				  metadata_request_cb <font color="#990000">,  				  NULL <font color="#990000">);  <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * Hooks for extension added and removed signals   <font color="#9A1900"> */   <font color="#9A1900">/*   <font color="#9A1900"> * Checks for a particular source to be added and  '' <font color="#9A1900"> * saves a reference to it.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">source_added_cb  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  		 <font color="#008080">GObject  <font color="#990000"> * source <font color="#990000">,  		 <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_SOURCE   <font color="#990000">( source <font color="#990000">))  <font color="#FF0000">{  <font color="#0000FF">const  <font color="#008080">gchar  <font color="#990000"> * name <font color="#990000"> =  <font color="#000000">mafw_extension_get_name  <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( source <font color="#990000">));  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Source %s available.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, name <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">strcmp   <font color="#990000">( name <font color="#990000">, WANTED_SOURCE <font color="#990000">)  <font color="#990000"> ==  <font color="#993399">0  <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Wanted source found!  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); app_source <font color="#990000"> =  <font color="#000000">g_object_ref   <font color="#990000">( source <font color="#990000">);  <font color="#9A1900">/* When we find the source we are interested in,   <font color="#9A1900">			  do a metadata request */   <font color="#000000">g_timeout_add  <font color="#990000">(  <font color="#993399">1000  <font color="#990000">, do_metadata_request <font color="#990000">, user_data <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Not interesting. Skipping...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">} <font color="#FF0000">}  <font color="#9A1900">/*  '' <font color="#9A1900"> * Checks if the referenced source is removed, and if so, exits.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">source_removed_cb  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  		   <font color="#008080">GObject  <font color="#990000"> * source <font color="#990000">,  		   <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_SOURCE   <font color="#990000">( source <font color="#990000">))  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Source %s removed.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  			  <font color="#000000">mafw_extension_get_name   <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( source <font color="#990000">)));  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_SOURCE   <font color="#990000">( source <font color="#990000">)  <font color="#990000"> == app_source <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Wanted source removed!"  				 <font color="#FF0000">" Exiting...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#000000">g_object_unref  <font color="#990000">( app_source <font color="#990000">);  <font color="#000000">g_main_loop_quit  <font color="#990000">( main_loop <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">renderer_added_cb  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  		   <font color="#008080">GObject  <font color="#990000"> * renderer <font color="#990000">,  		   <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_RENDERER   <font color="#990000">( renderer <font color="#990000">))  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Renderer %s available.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  			  <font color="#000000">mafw_extension_get_name   <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( renderer <font color="#990000">))); <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">renderer_removed_cb  <font color="#990000">( MafwRegistry <font color="#990000"> * registry <font color="#990000">,  		     <font color="#008080">GObject  <font color="#990000"> * renderer <font color="#990000">,  		     <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_RENDERER   <font color="#990000">( renderer <font color="#990000">))  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Renderer %s removed.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  			  <font color="#000000">mafw_extension_get_name   <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( renderer <font color="#990000">))); <font color="#FF0000">} <font color="#FF0000">}  <font color="#9A1900">/*  '' <font color="#9A1900"> * Loads MAFW plugins.   <font color="#9A1900"> * ''  <font color="#9A1900"> * This function lods out-of-process extensions and hooks to   <font color="#9A1900"> * source-added and source-removed signals for dynamic extension  '' <font color="#9A1900"> * discovery and removal.   <font color="#9A1900"> * ''  <font color="#9A1900"> * Also, this function allows loading of in-process extensions  '' <font color="#9A1900"> * defined through an environment variable.   <font color="#9A1900"> * ''  <font color="#9A1900"> * The object_id parameter is used to request metadata as soon  '' <font color="#9A1900"> * as the source of interest is loaded.   <font color="#9A1900"> */ '' gboolean  <font color="#0000FF">static   <font color="#000000">app_init  <font color="#990000">(  <font color="#008080">gchar  <font color="#990000"> * object_id <font color="#990000">) <font color="#FF0000">{ <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">gchar <font color="#990000"> ** plugins <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">GList <font color="#990000"> * extension_list <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">MafwRegistry <font color="#990000"> * registry <font color="#990000"> = NULL <font color="#990000"> ;  <font color="#9A1900">/* --- Basic MAFW setup -- */   <font color="#9A1900">/* Init GType */   <font color="#000000">g_type_init  <font color="#990000">;  <font color="#9A1900">/* Init MAFW log (show all messages) */   <font color="#000000">mafw_log_init  <font color="#990000">( G_LOG_DOMAIN <font color="#FF0000">":ALL"  <font color="#990000">);  <font color="#9A1900">/* -- Start out-of-process plugin loading -- */   <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Checking for out-of-process plugins...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#9A1900">/* Check available plugins */  registry <font color="#990000"> =  <font color="#000000">MAFW_REGISTRY   <font color="#990000">(   <font color="#000000">mafw_registry_get_instance   <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( registry <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"app_init: Failed to get MafwRegistry reference  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/* Start out-of-process extension discovery */   <font color="#000000">mafw_shared_init  <font color="#990000">( registry <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">) <font color="#FF0000">{  <font color="#000000">g_warning  <font color="#990000">(  <font color="#FF0000">"Ext. discovery failed: %s"  <font color="#990000">,  			   error <font color="#990000">-&gt; message <font color="#990000">);  <font color="#000000">g_error_free  <font color="#990000">( error <font color="#990000">); error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#FF0000">} '' <font color="#9A1900">/* Connect to extension discovery signals. These signals will be ''  <font color="#9A1900">	  emitted when new extensions are started or removed */   <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"renderer_added"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( renderer_added_cb <font color="#990000">), NULL <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"renderer_removed"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( renderer_removed_cb <font color="#990000">), NULL <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"source_added"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( source_added_cb <font color="#990000">), object_id <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"source_removed"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( source_removed_cb <font color="#990000">), NULL <font color="#990000">);  <font color="#9A1900">/* Also, check for already started extensions */  extension_list <font color="#990000"> =  <font color="#000000">mafw_registry_get_renderers   <font color="#990000">( registry <font color="#990000">);  <font color="#0000FF">while  <font color="#990000">( extension_list <font color="#990000">) <font color="#FF0000">{  <font color="#000000">renderer_added_cb  <font color="#990000">( registry <font color="#990000">,  				    <font color="#000000">G_OBJECT   <font color="#990000">( extension_list <font color="#990000">-&gt; data <font color="#990000">), NULL <font color="#990000">); extension_list <font color="#990000"> =  <font color="#000000">g_list_next   <font color="#990000">( extension_list <font color="#990000">); <font color="#FF0000">} extension_list <font color="#990000"> =  <font color="#000000">mafw_registry_get_sources   <font color="#990000">( registry <font color="#990000">);  <font color="#0000FF">while  <font color="#990000">( extension_list <font color="#990000">) <font color="#FF0000">{  <font color="#000000">source_added_cb  <font color="#990000">( registry <font color="#990000">,  				  <font color="#000000">G_OBJECT   <font color="#990000">( extension_list <font color="#990000">-&gt; data <font color="#990000">), NULL <font color="#990000">); extension_list <font color="#990000"> =  <font color="#000000">g_list_next   <font color="#990000">( extension_list <font color="#990000">); <font color="#FF0000">}  <font color="#9A1900">/* -- Start in-process plugin loading -- */   <font color="#9A1900">/* MAFW_INP_PLUGINS shold contain a list of paths   <font color="#9A1900">	  to plugin files to be loaded in-process */   <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Checking for in-process plugins...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">g_getenv   <font color="#990000">(  <font color="#FF0000">"MAFW_INP_PLUGINS"  <font color="#990000">)  <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{ plugins <font color="#990000"> =  <font color="#000000">g_strsplit   <font color="#990000">(   <font color="#000000">g_getenv   <font color="#990000">(  <font color="#FF0000">"MAFW_INP_PLUGINS"  <font color="#990000">),  				      G_SEARCHPATH_SEPARATOR_S <font color="#990000">,  				      <font color="#993399">0  <font color="#990000">);  <font color="#0000FF">for  <font color="#990000">(NULL <font color="#990000"> !=  <font color="#990000"> * plugins <font color="#990000"> ; plugins <font color="#990000">++)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Loading in-process plugin %s...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  				 <font color="#990000"> * plugins <font color="#990000">);  <font color="#000000">mafw_registry_load_plugin  <font color="#990000">(   <font color="#000000">MAFW_REGISTRY   <font color="#990000">( registry <font color="#990000">),  						   <font color="#990000"> * plugins <font color="#990000">,  						   <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{ gchar <font color="#990000"> * msg <font color="#990000"> ; msg <font color="#990000"> =  <font color="#000000">g_strdup_printf   <font color="#990000">(  					 <font color="#FF0000">"Unable to load inp. plugin %s: %s"  <font color="#990000">,  					 <font color="#990000"> * plugins <font color="#990000">,  					error <font color="#990000">-&gt; message <font color="#990000">);  <font color="#000000">g_warning  <font color="#990000">(  <font color="#FF0000">"Plugin loading failed: %s"  <font color="#990000">, msg <font color="#990000">);  <font color="#000000">g_free  <font color="#990000">( msg <font color="#990000">);  <font color="#000000">g_error_free  <font color="#990000">( error <font color="#990000">); error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#FF0000">} <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     No in-process plugins requested.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">} <font color="#009900">int  <font color="#000000">main  <font color="#990000">(  <font color="#009900">int argc <font color="#990000">,  <font color="#008080">gchar  <font color="#990000"> * argv <font color="#990000">[]) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">( argc <font color="#990000"> !=  <font color="#993399">2  <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"Please, provide exactly one argument specifying "  			 <font color="#FF0000">"the object identifier of the item to get "  			 <font color="#FF0000">"metadata from."  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Starting example...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#000000">app_init  <font color="#990000">( argv <font color="#990000">[  <font color="#993399">1  <font color="#990000">]);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Example started.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); main_loop <font color="#990000"> =  <font color="#000000">g_main_loop_new   <font color="#990000">( NULL <font color="#990000">, FALSE <font color="#990000">);  <font color="#000000">g_main_loop_run  <font color="#990000">( main_loop <font color="#990000">);  <font color="#0000FF">return  <font color="#993399">0  <font color="#990000"> ; <font color="#FF0000">} </tt>

Playlist example
This program is a simple command line program that allows the user to create and remove playlists. It is necessary to have the playlist-daemon running to execute this program.

To build the example : Playlist example

libtool -mode <font color="#990000"> = link gcc -o mafw-playlist-example <font color="#990000">\ `pkg-config -cflags -libs mafw mafw-shared` mafw-playlist-example <font color="#990000">. c </tt>

To run the example :

This program accepts several commands: Playlist example

run-standalone <font color="#990000">. sh <font color="#990000">. /mafw-playlist-example create <font color="#990000">&lt; playlist-name <font color="#990000">&gt; run-standalone <font color="#990000">. sh <font color="#990000">. /mafw-playlist-example remove <font color="#990000">&lt; playlist-name <font color="#990000">&gt; run-standalone <font color="#990000">. sh <font color="#990000">. /mafw-playlist-example show <font color="#990000">&lt; playlist-name <font color="#990000">&gt; run-standalone <font color="#990000">. sh <font color="#990000">. /mafw-playlist-example add-item <font color="#990000">&lt; playlist-name <font color="#990000">&gt; <font color="#990000">&lt; object-id <font color="#990000">&gt; run-standalone <font color="#990000">. sh <font color="#990000">. /mafw-playlist-example remove-item <font color="#990000">&lt; playlist-name <font color="#990000">&gt; <font color="#990000">&lt; object-id <font color="#990000">&gt; </tt>

Valid object identifiers for adding items to a playlist can be obtained using the browse example by browsing the all songs container (localtagfs::music/songs), and checking the object identifiers of the contained songs.

The source code : Playlist example

  <font color="#9A1900">/*   <font color="#9A1900">The code examples copyrighted by Nokia Corporation that are included to   <font color="#9A1900">this material are licensed to you under following MIT-style License:   <font color="#9A1900">Permission is hereby granted, free of charge, to any person obtaining a   <font color="#9A1900">copy of this software and associated documentation files (the   <font color="#9A1900">"Software"), to deal in the Software without restriction, including   <font color="#9A1900">without limitation the rights to use, copy, modify, merge, publish,   <font color="#9A1900">distribute, sublicense, and/or sell copies of the Software, and to   <font color="#9A1900">permit persons to whom the Software is furnished to do so, subject to   <font color="#9A1900">the following conditions:   <font color="#9A1900">The above copyright notice and this permission notice shall be included  '' <font color="#9A1900">in all copies or substantial portions of the Software.   <font color="#9A1900">THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ''  <font color="#9A1900">OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  '' <font color="#9A1900">MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   <font color="#9A1900">IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ''  <font color="#9A1900">CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   <font color="#9A1900">TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE  '' <font color="#9A1900">SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.   <font color="#9A1900"> */ ''  <font color="#000080"> #include  <font color="#FF0000">&lt;string.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;stdlib.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;glib.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw-log.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw-shared/mafw-shared.h&gt;  <font color="#000080"> #undef  G_LOG_DOMAIN  <font color="#000080"> #define  G_LOG_DOMAIN <font color="#FF0000">"mafw-example"  <font color="#000080"> #define  COMMAND_CREATE      <font color="#993399">1  <font color="#000080"> #define  COMMAND_REMOVE      <font color="#993399">2  <font color="#000080"> #define  COMMAND_SHOW        <font color="#993399">3  <font color="#000080"> #define  COMMAND_ADD_ITEM    <font color="#993399">4  <font color="#000080"> #define  COMMAND_REMOVE_ITEM <font color="#993399">5 <font color="#008080">GMainLoop <font color="#990000"> * main_loop <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">gint command <font color="#990000"> ; <font color="#008080">gchar <font color="#990000"> * playlist_name <font color="#990000"> ; <font color="#008080">gchar <font color="#990000"> * object_id <font color="#990000"> ;  <font color="#9A1900">/*   <font color="#9A1900"> * This function looks for a particular playlist using its name   <font color="#9A1900"> */   <font color="#0000FF">static  MafwPlaylist <font color="#990000"> *  <font color="#000000">find_playlist  <font color="#990000">(  <font color="#008080">gchar  <font color="#990000"> * name <font color="#990000">,  <font color="#008080">GError  <font color="#990000"> ** error <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwPlaylistManager <font color="#990000"> * manager <font color="#990000"> ; <font color="#008080">MafwPlaylist <font color="#990000"> * playlist <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">GPtrArray <font color="#990000"> * list <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">gint i <font color="#990000"> ; manager <font color="#990000"> =  <font color="#000000">mafw_playlist_manager_get   <font color="#990000">; list <font color="#990000"> =  <font color="#000000">mafw_playlist_manager_get_playlists   <font color="#990000">( manager <font color="#990000">, error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(* error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  NULL <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">for  <font color="#990000">( i <font color="#990000"> =  <font color="#993399">0  <font color="#990000"> ; i <font color="#990000">&lt; list <font color="#990000">-&gt; len <font color="#990000"> ; i <font color="#990000">++)  <font color="#FF0000">{ playlist <font color="#990000"> = <font color="#990000">( MafwPlaylist <font color="#990000"> *)   <font color="#000000">g_ptr_array_index   <font color="#990000">( list <font color="#990000">, i <font color="#990000">); <font color="#008080">gchar <font color="#990000"> * name <font color="#990000"> =   <font color="#000000">mafw_playlist_get_name   <font color="#990000">( playlist <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">strcmp   <font color="#990000">( playlist_name <font color="#990000">, name <font color="#990000">)  <font color="#990000"> ==  <font color="#993399">0  <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  playlist <font color="#990000"> ; <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">return  NULL <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * This function creates a new playlist   <font color="#9A1900"> */   <font color="#0000FF">static  GError <font color="#990000"> *  <font color="#000000">create_playlist  <font color="#990000">(  <font color="#009900">void  <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwPlaylistManager <font color="#990000"> * manager <font color="#990000"> ; <font color="#008080">MafwProxyPlaylist <font color="#990000"> * playlist <font color="#990000"> ; <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ; manager <font color="#990000"> =  <font color="#000000">mafw_playlist_manager_get   <font color="#990000">;  <font color="#000000">mafw_playlist_manager_create_playlist  <font color="#990000">( manager <font color="#990000">,  					       playlist_name <font color="#990000">,  					       <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * This function removes a playlist   <font color="#9A1900"> */   <font color="#0000FF">static  GError <font color="#990000"> *  <font color="#000000">remove_playlist  <font color="#990000">(  <font color="#009900">void  <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwPlaylistManager <font color="#990000"> * manager <font color="#990000"> ; <font color="#008080">MafwPlaylist <font color="#990000"> * playlist <font color="#990000"> ; <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">GPtrArray <font color="#990000"> * list <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">gint i <font color="#990000"> ; manager <font color="#990000"> =  <font color="#000000">mafw_playlist_manager_get   <font color="#990000">; playlist <font color="#990000"> =  <font color="#000000">find_playlist   <font color="#990000">( playlist_name <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( playlist <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return   <font color="#000000">g_error_new   <font color="#990000">( MAFW_ERROR <font color="#990000">,  <font color="#993399">0  <font color="#990000">,  <font color="#FF0000">"Playlist not found"  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">mafw_playlist_manager_destroy_playlist  <font color="#990000">( manager <font color="#990000">,  						playlist <font color="#990000">,  						 <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * This function shows the object identifiers contained in a playlist   <font color="#9A1900"> */   <font color="#0000FF">static  GError <font color="#990000"> *  <font color="#000000">show_playlist  <font color="#990000">(  <font color="#009900">void  <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwPlaylist <font color="#990000"> * playlist <font color="#990000"> ; <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">gint i <font color="#990000"> ; <font color="#008080">guint size <font color="#990000"> ; playlist <font color="#990000"> =  <font color="#000000">find_playlist   <font color="#990000">( playlist_name <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( playlist <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return   <font color="#000000">g_error_new   <font color="#990000">( MAFW_ERROR <font color="#990000">,  <font color="#993399">0  <font color="#990000">,  <font color="#FF0000">"Playlist not found"  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Showing contents for playlist %s...:  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, playlist_name <font color="#990000">); size <font color="#990000"> =  <font color="#000000">mafw_playlist_get_size   <font color="#990000">( playlist <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( size <font color="#990000">&gt;  <font color="#993399">0  <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">for  <font color="#990000">( i <font color="#990000"> =  <font color="#993399">0  <font color="#990000"> ; i <font color="#990000">&lt; size <font color="#990000"> ; i <font color="#990000">++)  <font color="#FF0000">{ <font color="#008080">gchar <font color="#990000"> * id <font color="#990000"> =  <font color="#000000">mafw_playlist_get_item  <font color="#990000">( playlist <font color="#990000">, i <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_warning  <font color="#990000">(  <font color="#FF0000">"Error getting item %d "  					   <font color="#FF0000">"from playlist: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  					   i <font color="#990000">, error <font color="#990000">-&gt; message <font color="#990000">);  <font color="#000000">g_error_free  <font color="#990000">( error <font color="#990000">); error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#FF0000">}  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"  %d %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, i <font color="#990000">, id <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Playlist is empty  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * This function adds an object identifier to a playlist   <font color="#9A1900"> */   <font color="#0000FF">static  GError <font color="#990000"> *  <font color="#000000">add_item_to_playlist  <font color="#990000">(  <font color="#009900">void  <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwPlaylist <font color="#990000"> * playlist <font color="#990000"> ; <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ; playlist <font color="#990000"> =  <font color="#000000">find_playlist   <font color="#990000">( playlist_name <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( playlist <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return   <font color="#000000">g_error_new   <font color="#990000">( MAFW_ERROR <font color="#990000">,  <font color="#993399">0  <font color="#990000">,  <font color="#FF0000">"Playlist not found"  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">mafw_playlist_insert_item  <font color="#990000">( playlist <font color="#990000">,  <font color="#993399">0  <font color="#990000">, object_id <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * This function removes an item from a playlist   <font color="#9A1900"> */   <font color="#0000FF">static  GError <font color="#990000"> *  <font color="#000000">remove_item_from_playlist  <font color="#990000">(  <font color="#009900">void  <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwPlaylist <font color="#990000"> * playlist <font color="#990000"> ; <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">guint size <font color="#990000"> ; <font color="#008080">gint i <font color="#990000"> ; playlist <font color="#990000"> =  <font color="#000000">find_playlist   <font color="#990000">( playlist_name <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( playlist <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return   <font color="#000000">g_error_new   <font color="#990000">( MAFW_ERROR <font color="#990000">,  <font color="#993399">0  <font color="#990000">,  <font color="#FF0000">"Playlist not found"  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"  Searching for %s in playlist %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  		 object_id <font color="#990000">, playlist_name <font color="#990000">); size <font color="#990000"> =  <font color="#000000">mafw_playlist_get_size   <font color="#990000">( playlist <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  error <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">for  <font color="#990000">( i <font color="#990000"> =  <font color="#993399">0  <font color="#990000"> ; i <font color="#990000">&lt; size <font color="#990000"> ; i <font color="#990000">++)  <font color="#FF0000">{ <font color="#008080">gchar <font color="#990000"> * id <font color="#990000"> =   <font color="#000000">mafw_playlist_get_item   <font color="#990000">( playlist <font color="#990000">, i <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_warning  <font color="#990000">(  <font color="#FF0000">"Error getting item %d "  				   <font color="#FF0000">"from playlist: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  				   i <font color="#990000">, error <font color="#990000">-&gt; message <font color="#990000">);  <font color="#000000">g_error_free  <font color="#990000">( error <font color="#990000">); error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">else    <font color="#0000FF">if   <font color="#990000">(   <font color="#000000">strcmp   <font color="#990000">( id <font color="#990000">, object_id <font color="#990000">)  <font color="#990000"> ==  <font color="#993399">0  <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">mafw_playlist_remove_item  <font color="#990000">( playlist <font color="#990000">, i <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"  Element found at position %d  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, i <font color="#990000">);  <font color="#0000FF">break  <font color="#990000"> ; <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( i <font color="#990000"> == size <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"  Element not found  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Playlist %s removed  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, playlist_name <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * This function executes the command specified in the command line   <font color="#9A1900"> */   <font color="#0000FF">static  gboolean  <font color="#000000">execute_command  <font color="#990000">(  <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{ <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> ;  <font color="#0000FF">switch  <font color="#990000">( command <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">case  COMMAND_CREATE <font color="#990000"> : error <font color="#990000"> =  <font color="#000000">create_playlist   <font color="#990000">;  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Playlist %s created  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, playlist_name <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">break  <font color="#990000"> ;  <font color="#0000FF">case  COMMAND_REMOVE <font color="#990000"> : error <font color="#990000"> =  <font color="#000000">remove_playlist   <font color="#990000">;  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Playlist %s removed  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, playlist_name <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">break  <font color="#990000"> ;  <font color="#0000FF">case  COMMAND_SHOW <font color="#990000"> : error <font color="#990000"> =  <font color="#000000">show_playlist   <font color="#990000">;  <font color="#0000FF">break  <font color="#990000"> ;  <font color="#0000FF">case  COMMAND_ADD_ITEM <font color="#990000"> : error <font color="#990000"> =  <font color="#000000">add_item_to_playlist   <font color="#990000">;  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Item %s added to playlist %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  				 object_id <font color="#990000">, playlist_name <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">break  <font color="#990000"> ;  <font color="#0000FF">case  COMMAND_REMOVE_ITEM <font color="#990000"> : error <font color="#990000"> =  <font color="#000000">remove_item_from_playlist   <font color="#990000">;  <font color="#0000FF">break  <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Operation failed: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, error <font color="#990000">-&gt; message <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Operation executed successfully.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">g_main_loop_quit  <font color="#990000">( main_loop <font color="#990000">);  <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * This function parses the command line and extracts  '' <font color="#9A1900"> * info on the requested command and arguments.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  gboolean  <font color="#000000">check_command_line  <font color="#990000">(  <font color="#009900">int argc <font color="#990000">,  		    <font color="#008080">gchar  <font color="#990000"> * argv <font color="#990000">[],  		    <font color="#008080">gint  <font color="#990000"> * command <font color="#990000">,  		    <font color="#008080">gchar  <font color="#990000"> ** playlist_name <font color="#990000">,  		    <font color="#008080">gchar  <font color="#990000"> ** object_id <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">switch  <font color="#990000">( argc <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">case  <font color="#993399">3  <font color="#990000"> : <font color="#990000"> * playlist_name <font color="#990000"> = argv <font color="#990000">[ <font color="#993399">2  <font color="#990000">];  <font color="#0000FF">if  <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( argv <font color="#990000">[  <font color="#993399">1  <font color="#990000">],  <font color="#FF0000">"create"  <font color="#990000">))  <font color="#FF0000">{ <font color="#990000"> * command <font color="#990000"> = COMMAND_CREATE <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">else    <font color="#0000FF">if   <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( argv <font color="#990000">[  <font color="#993399">1  <font color="#990000">],  <font color="#FF0000">"remove"  <font color="#990000">))  <font color="#FF0000">{ <font color="#990000"> * command <font color="#990000"> = COMMAND_REMOVE <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">else    <font color="#0000FF">if   <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( argv <font color="#990000">[  <font color="#993399">1  <font color="#990000">],  <font color="#FF0000">"show"  <font color="#990000">))  <font color="#FF0000">{ <font color="#990000"> * command <font color="#990000"> = COMMAND_SHOW <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">break  <font color="#990000"> ;  <font color="#0000FF">case  <font color="#993399">4  <font color="#990000"> : <font color="#990000"> * playlist_name <font color="#990000"> = argv <font color="#990000">[ <font color="#993399">2  <font color="#990000">]; <font color="#990000"> * object_id <font color="#990000"> = argv <font color="#990000">[ <font color="#993399">3  <font color="#990000">];  <font color="#0000FF">if  <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( argv <font color="#990000">[  <font color="#993399">1  <font color="#990000">],  <font color="#FF0000">"add-item"  <font color="#990000">))  <font color="#FF0000">{ <font color="#990000"> * command <font color="#990000"> = COMMAND_ADD_ITEM <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">else    <font color="#0000FF">if   <font color="#990000">(!   <font color="#000000">strcmp   <font color="#990000">( argv <font color="#990000">[  <font color="#993399">1  <font color="#990000">],  <font color="#FF0000">"remove-item"  <font color="#990000">))  <font color="#FF0000">{ <font color="#990000"> * command <font color="#990000"> = COMMAND_REMOVE_ITEM <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">break  <font color="#990000"> ;  <font color="#0000FF">default  <font color="#990000"> :  <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">return  TRUE <font color="#990000"> ; <font color="#FF0000">} <font color="#009900">int  <font color="#000000">main  <font color="#990000">(  <font color="#009900">int argc <font color="#990000">,  <font color="#008080">gchar  <font color="#990000"> * argv <font color="#990000">[]) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(!   <font color="#000000">check_command_line   <font color="#990000">( argc <font color="#990000">, argv <font color="#990000">, <font color="#990000">&amp; command <font color="#990000">, <font color="#990000">&amp; playlist_name <font color="#990000">,  <font color="#990000">&amp; object_id <font color="#990000">))  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"Please, provide one of these sets of arguments:  <font color="#CC33CC">\n  <font color="#FF0000">"  			 <font color="#FF0000">"  create &lt;playlist-name&gt;  <font color="#CC33CC">\n  <font color="#FF0000">"  			 <font color="#FF0000">"  remove &lt;playlist-name&gt;  <font color="#CC33CC">\n  <font color="#FF0000">"  			 <font color="#FF0000">"  show &lt;playlist-name&gt;  <font color="#CC33CC">\n  <font color="#FF0000">"                           <font color="#FF0000">"  add-item &lt;playlist-name&gt; &lt;object-id&gt;  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  			 <font color="#FF0000">"  remove-item &lt;playlist-name&gt; &lt;object-id&gt;  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">g_type_init  <font color="#990000">;  <font color="#000000">mafw_log_init  <font color="#990000">( G_LOG_DOMAIN <font color="#FF0000">":ALL"  <font color="#990000">);  <font color="#000000">g_timeout_add  <font color="#990000">(  <font color="#993399">100  <font color="#990000">, execute_command <font color="#990000">, NULL <font color="#990000">); main_loop <font color="#990000"> =  <font color="#000000">g_main_loop_new   <font color="#990000">( NULL <font color="#990000">, FALSE <font color="#990000">);  <font color="#000000">g_main_loop_run  <font color="#990000">( main_loop <font color="#990000">);  <font color="#0000FF">return  <font color="#993399">0  <font color="#990000"> ; <font color="#FF0000">} </tt>

Renderer example
This program is a simple command line program that allows the user to play arbitrary playlists in a renderer. It is necessary to have the mafw-gst-renderer plugin installed (and running in case you intend to run the program in out-of-process mode) in order to execute the program successfully.

To build the example : Renderer example

libtool -mode <font color="#990000"> = link gcc -o mafw-renderer-example <font color="#990000">\ `pkg-config -cflags -libs mafw mafw-shared` mafw-renderer-example <font color="#990000">. c </tt>

To run the example : run-standalone.sh ./mafw-renderer-example &lt;playlist-name&gt;

One can use the playlist example to define the playlists.

The source code : Renderer example

  <font color="#9A1900">/*   <font color="#9A1900">The code examples copyrighted by Nokia Corporation that are included to   <font color="#9A1900">this material are licensed to you under following MIT-style License:   <font color="#9A1900">Permission is hereby granted, free of charge, to any person obtaining a   <font color="#9A1900">copy of this software and associated documentation files (the   <font color="#9A1900">"Software"), to deal in the Software without restriction, including   <font color="#9A1900">without limitation the rights to use, copy, modify, merge, publish,   <font color="#9A1900">distribute, sublicense, and/or sell copies of the Software, and to   <font color="#9A1900">permit persons to whom the Software is furnished to do so, subject to   <font color="#9A1900">the following conditions:   <font color="#9A1900">The above copyright notice and this permission notice shall be included  '' <font color="#9A1900">in all copies or substantial portions of the Software.   <font color="#9A1900">THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ''  <font color="#9A1900">OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  '' <font color="#9A1900">MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   <font color="#9A1900">IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ''  <font color="#9A1900">CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   <font color="#9A1900">TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE  '' <font color="#9A1900">SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.   <font color="#9A1900"> */ ''  <font color="#000080"> #include  <font color="#FF0000">&lt;string.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;stdlib.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;glib.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw-log.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw/mafw-registry.h&gt;  <font color="#000080"> #include  <font color="#FF0000">&lt;libmafw-shared/mafw-shared.h&gt;  <font color="#000080"> #undef  G_LOG_DOMAIN  <font color="#000080"> #define  G_LOG_DOMAIN <font color="#FF0000">"mafw-example"  <font color="#000080"> #define  WANTED_RENDERER    <font color="#FF0000">"Mafw-Gst-Renderer" <font color="#008080">MafwRenderer <font color="#990000"> * app_renderer <font color="#990000"> = NULL <font color="#990000"> ; GMainLoop <font color="#990000"> * main_loop <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">gchar <font color="#990000"> * state_str <font color="#990000">[]  <font color="#990000"> =  <font color="#FF0000">{  <font color="#FF0000">"STOPPED"  <font color="#990000">,  <font color="#FF0000">"PLAYING"  <font color="#990000">,  <font color="#FF0000">"PAUSED"  <font color="#990000">,  <font color="#FF0000">"TRANSITIONING"  <font color="#FF0000">}  <font color="#990000"> ;  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">play_cb  <font color="#990000">(  <font color="#008080">MafwRenderer  <font color="#990000"> * renderer <font color="#990000">,  	 <font color="#008080">gpointer user_data <font color="#990000">,  	  <font color="#0000FF">const   <font color="#008080">GError  <font color="#990000"> * error <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Play operation failed: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, error <font color="#990000">-&gt; message <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">error_cb  <font color="#990000">(  <font color="#008080">MafwRenderer  <font color="#990000"> * renderer <font color="#990000">,  	  <font color="#008080">GQuark domain <font color="#990000">,  	  <font color="#008080">gint code <font color="#990000">,  	  <font color="#008080">gchar  <font color="#990000"> * message <font color="#990000">,  	  <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Playback error received: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, message <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">state_changed_cb  <font color="#990000">(  <font color="#008080">MafwRenderer  <font color="#990000"> * renderer <font color="#990000">,                    <font color="#008080">MafwPlayState state <font color="#990000">,  		  <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"State changed! New state is %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  		state_str <font color="#990000">[ state <font color="#990000">]); <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">media_changed_cb  <font color="#990000">(  <font color="#008080">MafwRenderer  <font color="#990000"> * renderer <font color="#990000">,  		  <font color="#008080">gint index <font color="#990000">,  		  <font color="#008080">gchar  <font color="#990000"> * object_id <font color="#990000">,  		  <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">static  <font color="#008080">gboolean started <font color="#990000"> = FALSE <font color="#990000"> ;  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"Media changed: assigned media is %d - %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  		 index <font color="#990000">, object_id <font color="#990000">); '' <font color="#9A1900">/* Start playback right away! */ '' 	  <font color="#0000FF">if   <font color="#990000">( started <font color="#990000"> == FALSE <font color="#990000">)  <font color="#FF0000">{ started <font color="#990000"> = TRUE <font color="#990000"> ;  <font color="#000000">mafw_renderer_play  <font color="#990000">( renderer <font color="#990000">, play_cb <font color="#990000">, NULL <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">metadata_changed_cb  <font color="#990000">(  <font color="#008080">MafwRenderer  <font color="#990000"> * renderer <font color="#990000">,  		     <font color="#008080">gchar  <font color="#990000"> * key <font color="#990000">,  		     <font color="#008080">GValueArray  <font color="#990000"> * value <font color="#990000">,  		     <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"  Got metadata %s: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  		 key <font color="#990000">,  		  <font color="#000000">g_strdup_value_contents   <font color="#990000">(&amp;( value <font color="#990000">-&gt; values <font color="#990000">[  <font color="#993399">0  <font color="#990000">]))); <font color="#FF0000">}  <font color="#0000FF">static  MafwPlaylist <font color="#990000"> *  <font color="#000000">find_playlist  <font color="#990000">(  <font color="#008080">gchar  <font color="#990000"> * playlist_name <font color="#990000">,  <font color="#008080">GError  <font color="#990000"> ** error <font color="#990000">) <font color="#FF0000">{ <font color="#008080">MafwPlaylistManager <font color="#990000"> * manager <font color="#990000"> ; <font color="#008080">MafwPlaylist <font color="#990000"> * playlist <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">GPtrArray <font color="#990000"> * list <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">gint i <font color="#990000"> ; manager <font color="#990000"> =  <font color="#000000">mafw_playlist_manager_get   <font color="#990000">; list <font color="#990000"> =  <font color="#000000">mafw_playlist_manager_get_playlists   <font color="#990000">( manager <font color="#990000">, error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(* error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  NULL <font color="#990000"> ; <font color="#FF0000">}  <font color="#0000FF">for  <font color="#990000">( i <font color="#990000"> =  <font color="#993399">0  <font color="#990000"> ; i <font color="#990000">&lt; list <font color="#990000">-&gt; len <font color="#990000"> ; i <font color="#990000">++)  <font color="#FF0000">{ playlist <font color="#990000"> = <font color="#990000">( MafwPlaylist <font color="#990000"> *)   <font color="#000000">g_ptr_array_index   <font color="#990000">( list <font color="#990000">, i <font color="#990000">); <font color="#008080">gchar <font color="#990000"> * name <font color="#990000"> =   <font color="#000000">mafw_playlist_get_name   <font color="#990000">( playlist <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">strcmp   <font color="#990000">( playlist_name <font color="#990000">, name <font color="#990000">)  <font color="#990000"> ==  <font color="#993399">0  <font color="#990000">)  <font color="#FF0000">{  <font color="#0000FF">return  playlist <font color="#990000"> ; <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">return  NULL <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*  '' <font color="#9A1900"> * This function assigned a playlist to the renderer.   <font color="#9A1900"> * Receives the playlist name to assign as parameter.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  gboolean  <font color="#000000">do_assign_playlist_request  <font color="#990000">(  <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{ <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">MafwPlaylist <font color="#990000"> * playlist <font color="#990000"> ; <font color="#008080">gchar <font color="#990000"> * playlist_name <font color="#990000"> =  <font color="#990000">( gchar <font color="#990000"> *) user_data <font color="#990000"> ;  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Assigning playlist %s to "  WANTED_RENDERER <font color="#FF0000">".  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  		 playlist_name <font color="#990000">); playlist <font color="#990000"> =  <font color="#000000">find_playlist   <font color="#990000">( playlist_name <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"Failed to find playlist  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">if  <font color="#990000">( playlist <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"Playlist not found"  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">mafw_renderer_assign_playlist  <font color="#990000">( app_renderer <font color="#990000">, playlist <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"Failed to assign playlist: %s  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  			 error <font color="#990000">-&gt; message <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/*   <font color="#9A1900"> * Hooks for extension added and removed signals   <font color="#9A1900"> */   <font color="#9A1900">/*   <font color="#9A1900"> * Checks for a particular source to be added and  '' <font color="#9A1900"> * saves a reference to it.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">source_added_cb  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  		 <font color="#008080">GObject  <font color="#990000"> * source <font color="#990000">,  		 <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_SOURCE   <font color="#990000">( source <font color="#990000">))  <font color="#FF0000">{  <font color="#0000FF">const  <font color="#008080">gchar  <font color="#990000"> * name <font color="#990000"> =  <font color="#000000">mafw_extension_get_name  <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( source <font color="#990000">));  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Source %s available.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, name <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">}  <font color="#9A1900">/*  '' <font color="#9A1900"> * Checks if the referenced source is removed, and if so, exits.   <font color="#9A1900"> */ ''  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">source_removed_cb  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  		   <font color="#008080">GObject  <font color="#990000"> * source <font color="#990000">,  		   <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_SOURCE   <font color="#990000">( source <font color="#990000">))  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Source %s removed.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  			  <font color="#000000">mafw_extension_get_name   <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( source <font color="#990000">))); <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">renderer_added_cb  <font color="#990000">(  <font color="#008080">MafwRegistry  <font color="#990000"> * registry <font color="#990000">,  		   <font color="#008080">GObject  <font color="#990000"> * renderer <font color="#990000">,  		   <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_RENDERER   <font color="#990000">( renderer <font color="#990000">))  <font color="#FF0000">{  <font color="#0000FF">const  <font color="#008080">gchar  <font color="#990000"> * name <font color="#990000"> =  <font color="#000000">mafw_extension_get_name  <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( renderer <font color="#990000">));  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Renderer %s available.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, name <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">strcmp   <font color="#990000">( name <font color="#990000">, WANTED_RENDERER <font color="#990000">)  <font color="#990000"> ==  <font color="#993399">0  <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Wanted renderer found!  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); app_renderer <font color="#990000"> =  <font color="#000000">g_object_ref   <font color="#990000">( renderer <font color="#990000">);  <font color="#9A1900">/* Connect to a few interesting signals */   <font color="#000000">g_signal_connect  <font color="#990000">( renderer <font color="#990000">,  					  <font color="#FF0000">"media-changed"  <font color="#990000">,  					   <font color="#000000">G_CALLBACK   <font color="#990000">( media_changed_cb <font color="#990000">),  					  NULL <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( renderer <font color="#990000">,  					  <font color="#FF0000">"state-changed"  <font color="#990000">,  					   <font color="#000000">G_CALLBACK   <font color="#990000">( state_changed_cb <font color="#990000">),  					  NULL <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( renderer <font color="#990000">,  					  <font color="#FF0000">"metadata-changed"  <font color="#990000">,  					   <font color="#000000">G_CALLBACK   <font color="#990000">( metadata_changed_cb <font color="#990000">),  					  NULL <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( renderer <font color="#990000">,  					  <font color="#FF0000">"error"  <font color="#990000">,  					   <font color="#000000">G_CALLBACK   <font color="#990000">( error_cb <font color="#990000">),  					  NULL <font color="#990000">);  <font color="#9A1900">/* When we find the renderer we are interested in,   <font color="#9A1900">			  so use it to play something */   <font color="#000000">g_timeout_add  <font color="#990000">(  <font color="#993399">1000  <font color="#990000">,  				       do_assign_playlist_request <font color="#990000">,  				       user_data <font color="#990000">); <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Not interesting. Skipping...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">static  <font color="#009900">void  <font color="#000000">renderer_removed_cb  <font color="#990000">( MafwRegistry <font color="#990000"> * registry <font color="#990000">,  		     <font color="#008080">GObject  <font color="#990000"> * renderer <font color="#990000">,  		     <font color="#008080">gpointer user_data <font color="#990000">) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_IS_RENDERER   <font color="#990000">( renderer <font color="#990000">))  <font color="#FF0000">{  <font color="#0000FF">const  <font color="#008080">gchar  <font color="#990000"> * name <font color="#990000"> =  <font color="#000000">mafw_extension_get_name  <font color="#990000">(   <font color="#000000">MAFW_EXTENSION   <font color="#990000">( renderer <font color="#990000">));  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Renderer %s removed.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">, name <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">MAFW_RENDERER   <font color="#990000">( renderer <font color="#990000">)  <font color="#990000"> == app_renderer <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     Wanted renderer removed!"  				 <font color="#FF0000">" Exiting...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#000000">g_object_unref  <font color="#990000">( app_renderer <font color="#990000">);  <font color="#000000">g_main_loop_quit  <font color="#990000">( main_loop <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">} <font color="#FF0000">}  <font color="#9A1900">/*  '' <font color="#9A1900"> * Loads MAFW plugins.   <font color="#9A1900"> * ''  <font color="#9A1900"> * This function lods out-of-process extensions and hooks to   <font color="#9A1900"> * renderer/source-added and renderer/source-removed signals  '' <font color="#9A1900"> * for dynamic extension discovery and removal.   <font color="#9A1900"> * ''  <font color="#9A1900"> * Also, this function allows loading of in-process extensions  '' <font color="#9A1900"> * defined through an environment variable.   <font color="#9A1900"> * ''  <font color="#9A1900"> * The object_id parameter is used to play that object as soon  '' <font color="#9A1900"> * as the renderer of interest is loaded.   <font color="#9A1900"> */ '' gboolean  <font color="#0000FF">static   <font color="#000000">app_init  <font color="#990000">(  <font color="#008080">gchar  <font color="#990000"> * playlist_name <font color="#990000">) <font color="#FF0000">{ <font color="#008080">GError <font color="#990000"> * error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">gchar <font color="#990000"> ** plugins <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">GList <font color="#990000"> * extension_list <font color="#990000"> = NULL <font color="#990000"> ; <font color="#008080">MafwRegistry <font color="#990000"> * registry <font color="#990000"> = NULL <font color="#990000"> ;  <font color="#9A1900">/* --- Basic MAFW setup -- */   <font color="#9A1900">/* Init GType */   <font color="#000000">g_type_init  <font color="#990000">;  <font color="#9A1900">/* Init MAFW log (show all messages) */   <font color="#000000">mafw_log_init  <font color="#990000">( G_LOG_DOMAIN <font color="#FF0000">":ALL"  <font color="#990000">);  <font color="#9A1900">/* -- Start out-of-process plugin loading -- */   <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Checking for out-of-process plugins...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#9A1900">/* Check available plugins */  registry <font color="#990000"> =  <font color="#000000">MAFW_REGISTRY   <font color="#990000">(   <font color="#000000">mafw_registry_get_instance   <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( registry <font color="#990000"> == NULL <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"app_init: Failed to get MafwRegistry reference  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#0000FF">return  FALSE <font color="#990000"> ; <font color="#FF0000">}  <font color="#9A1900">/* Start out-of-process extension discovery */   <font color="#000000">mafw_shared_init  <font color="#990000">( registry <font color="#990000">,  <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">) <font color="#FF0000">{  <font color="#000000">g_warning  <font color="#990000">(  <font color="#FF0000">"Ext. discovery failed: %s"  <font color="#990000">,  			   error <font color="#990000">-&gt; message <font color="#990000">);  <font color="#000000">g_error_free  <font color="#990000">( error <font color="#990000">); error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#FF0000">} '' <font color="#9A1900">/* Connect to extension discovery signals. These signals will be ''  <font color="#9A1900">	  emitted when new extensions are started or removed */   <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"renderer_added"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( renderer_added_cb <font color="#990000">), playlist_name <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"renderer_removed"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( renderer_removed_cb <font color="#990000">), NULL <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"source_added"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( source_added_cb <font color="#990000">), NULL <font color="#990000">);  <font color="#000000">g_signal_connect  <font color="#990000">( registry <font color="#990000">,  			  <font color="#FF0000">"source_removed"  <font color="#990000">,  			   <font color="#000000">G_CALLBACK   <font color="#990000">( source_removed_cb <font color="#990000">), NULL <font color="#990000">);  <font color="#9A1900">/* Also, check for already started extensions */  extension_list <font color="#990000"> =  <font color="#000000">mafw_registry_get_renderers   <font color="#990000">( registry <font color="#990000">);  <font color="#0000FF">while  <font color="#990000">( extension_list <font color="#990000">) <font color="#FF0000">{  <font color="#000000">renderer_added_cb  <font color="#990000">( registry <font color="#990000">,  				    <font color="#000000">G_OBJECT   <font color="#990000">( extension_list <font color="#990000">-&gt; data <font color="#990000">), NULL <font color="#990000">); extension_list <font color="#990000"> =  <font color="#000000">g_list_next   <font color="#990000">( extension_list <font color="#990000">); <font color="#FF0000">} extension_list <font color="#990000"> =  <font color="#000000">mafw_registry_get_sources   <font color="#990000">( registry <font color="#990000">);  <font color="#0000FF">while  <font color="#990000">( extension_list <font color="#990000">) <font color="#FF0000">{  <font color="#000000">source_added_cb  <font color="#990000">( registry <font color="#990000">,  				  <font color="#000000">G_OBJECT   <font color="#990000">( extension_list <font color="#990000">-&gt; data <font color="#990000">), NULL <font color="#990000">); extension_list <font color="#990000"> =  <font color="#000000">g_list_next   <font color="#990000">( extension_list <font color="#990000">); <font color="#FF0000">}  <font color="#9A1900">/* -- Start in-process plugin loading -- */   <font color="#9A1900">/* MAFW_INP_PLUGINS shold contain a list of paths   <font color="#9A1900">	  to plugin files to be loaded in-process */   <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Checking for in-process plugins...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">(   <font color="#000000">g_getenv   <font color="#990000">(  <font color="#FF0000">"MAFW_INP_PLUGINS"  <font color="#990000">)  <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{ plugins <font color="#990000"> =  <font color="#000000">g_strsplit   <font color="#990000">(   <font color="#000000">g_getenv   <font color="#990000">(  <font color="#FF0000">"MAFW_INP_PLUGINS"  <font color="#990000">),  				      G_SEARCHPATH_SEPARATOR_S <font color="#990000">,  				      <font color="#993399">0  <font color="#990000">);  <font color="#0000FF">for  <font color="#990000">(NULL <font color="#990000"> !=  <font color="#990000"> * plugins <font color="#990000"> ; plugins <font color="#990000">++)  <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Loading in-process plugin %s...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">,  				 <font color="#990000"> * plugins <font color="#990000">);  <font color="#000000">mafw_registry_load_plugin  <font color="#990000">(   <font color="#000000">MAFW_REGISTRY   <font color="#990000">( registry <font color="#990000">),  						   <font color="#990000"> * plugins <font color="#990000">,  						   <font color="#990000">&amp; error <font color="#990000">);  <font color="#0000FF">if  <font color="#990000">( error <font color="#990000"> != NULL <font color="#990000">)  <font color="#FF0000">{ gchar <font color="#990000"> * msg <font color="#990000"> ; msg <font color="#990000"> =  <font color="#000000">g_strdup_printf   <font color="#990000">(  					 <font color="#FF0000">"Unable to load inp. plugin %s: %s"  <font color="#990000">,  					 <font color="#990000"> * plugins <font color="#990000">,  					error <font color="#990000">-&gt; message <font color="#990000">);  <font color="#000000">g_warning  <font color="#990000">(  <font color="#FF0000">"Plugin loading failed: %s"  <font color="#990000">, msg <font color="#990000">);  <font color="#000000">g_free  <font color="#990000">( msg <font color="#990000">);  <font color="#000000">g_error_free  <font color="#990000">( error <font color="#990000">); error <font color="#990000"> = NULL <font color="#990000"> ; <font color="#FF0000">} <font color="#FF0000">} <font color="#FF0000">}  <font color="#0000FF">else   <font color="#FF0000">{  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO]     No in-process plugins requested.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); <font color="#FF0000">} <font color="#FF0000">} <font color="#009900">int  <font color="#000000">main  <font color="#990000">(  <font color="#009900">int argc <font color="#990000">,  <font color="#008080">gchar  <font color="#990000"> * argv <font color="#990000">[]) <font color="#FF0000">{  <font color="#0000FF">if  <font color="#990000">( argc <font color="#990000"> !=  <font color="#993399">2  <font color="#990000">)  <font color="#FF0000">{  <font color="#000000">g_error  <font color="#990000">(  <font color="#FF0000">"Please, provide exactly one argument specifying "  			 <font color="#FF0000">"the name of the playlist to assign and play."  <font color="#990000">); <font color="#FF0000">}  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Starting example...  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">);  <font color="#000000">app_init  <font color="#990000">( argv <font color="#990000">[  <font color="#993399">1  <font color="#990000">]);  <font color="#000000">g_print  <font color="#990000">(  <font color="#FF0000">"[INFO] Example started.  <font color="#CC33CC">\n  <font color="#FF0000">"  <font color="#990000">); main_loop <font color="#990000"> =  <font color="#000000">g_main_loop_new   <font color="#990000">( NULL <font color="#990000">, FALSE <font color="#990000">);  <font color="#000000">g_main_loop_run  <font color="#990000">( main_loop <font color="#990000">);  <font color="#0000FF">return  <font color="#993399">0  <font color="#990000"> ; <font color="#FF0000">} </tt>