Source code examples

Source browsing example
Source metadata example
Playlist example
Renderer example
This chapter contains a few full examples that illustrate some of the concepts explained during this manual. The code is ready to be built and executed to allow the reader to experiment. In order to build these programs one should use the following command:


libtool --mode=link gcc -o <output-file> `pkg-config --cflags --libs mafw mafw-shared` <source-file>

  

Some of the examples require specific plugins, so be sure you have them installed when trying to run them. Also, examples that use plugins allow both in-process and out-of-process modes. To use the plugins in out-of-process mode, be sure you have the plugins running using mafw-dbus-wrapper. To use the plugins in-process, you can define the environment variable MAFW_INP_PLUGINS to a colon separated list of plugin file paths (.so files) with the plugins to load in this mode.

Finally, these programs should be run with appropriate environment settings, be sure you have the Maemo environment properly initialized and run the programs using the run-standalone.sh script.

Source browsing example

This example illustrates a simple command line program browsing arbitrary object identifiers using the tracker source plugin. To run the program successfully, one needs to have this plugin installed.

/* 
The code examples copyrighted by Nokia Corporation that are included to
this material are licensed to you under following MIT-style License:

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <string.h>
#include <stdlib.h>

#include <glib.h>

#include <libmafw/mafw.h>
#include <libmafw/mafw-log.h>
#include <libmafw/mafw-registry.h>
#include <libmafw-shared/mafw-shared.h>

#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "mafw-example"

#define WANTED_SOURCE     "Mafw-Tracker-Source"

MafwSource *app_source = NULL;
GMainLoop * main_loop = NULL;

/*
 * This callback is invoked whenever a browse result is available
 */
static void
browse_request_cb (MafwSource *source, 
		   guint browse_id, 
		   gint remaining,
		   guint index, 
		   const gchar *object_id, 
		   GHashTable *metadata,
		   gpointer user_data, 
		   const GError *error)
{
	const gchar *title, *artist, *album, *genre;

	if (error != NULL) {
		g_error ("Browse error: %s\n", error->message);
	}

	if (object_id == NULL) {
		g_print ("[INFO]     Sorry, no songs found!\n");
	} else {
		g_print ("[INFO]     Got result %d:\n", index);
		if (metadata == NULL) {
			title = "Unknown";
			artist = "Unknown";
			album = "Unknown";
			genre = "Unknown";
		} else {
                        GValue *v;
                        v = mafw_metadata_first (metadata, 
						 MAFW_METADATA_KEY_TITLE);
                        title = v ? g_value_get_string (v) : "Unknown";
                        v = mafw_metadata_first (metadata, 
						 MAFW_METADATA_KEY_ARTIST);
                        artist = v ? g_value_get_string (v) : "Unknown";
                        v = mafw_metadata_first (metadata, 
						 MAFW_METADATA_KEY_ALBUM);
                        album = v ? g_value_get_string (v) : "Unknown";
                        v = mafw_metadata_first (metadata, 
						 MAFW_METADATA_KEY_GENRE);
                        genre = v ? g_value_get_string (v) : "Unknown";
		}

		g_print ("[INFO]       Object ID: %s\n", object_id);
		g_print ("[INFO]           Title: %s\n", title);
		g_print ("[INFO]          Artist: %s\n", artist);
		g_print ("[INFO]           Album: %s\n", album);
		g_print ("[INFO]           Genre: %s\n", genre);
	}

        if (remaining == 0) {
		g_print ("[INFO] Browse operaton finished. Exiting...\n");
		g_main_loop_quit (main_loop);
	}
}


/*
 * This function executes a browse request on the selected source.
 * This function receives the object identifier to browse as parameter.
 */
static gboolean
do_browse_request (gpointer user_data)
{
	guint browse_id;
	const gchar *const *keys;
	gchar *object_id = (gchar *) user_data;

	g_print ("[INFO] Browsing %s on "  WANTED_SOURCE ".\n", object_id);
	
	keys = MAFW_SOURCE_LIST(
	       MAFW_METADATA_KEY_TITLE,
	       MAFW_METADATA_KEY_ARTIST,
	       MAFW_METADATA_KEY_ALBUM,
	       MAFW_METADATA_KEY_GENRE);
	
	browse_id = 
		mafw_source_browse (app_source,        /* Source */
				    object_id,         /* Object identifier */
				    FALSE,             /* Recursive */
				    NULL,              /* Filter */
				    NULL,              /* Sorting */
				    keys,              /* Requested keys */
				    0, 30,             /* Offset, Count*/
				    browse_request_cb, /* Callback */
				    NULL);             /* User data */

	if (browse_id == MAFW_SOURCE_INVALID_BROWSE_ID) {
		g_warning ("Incorrect browse request.\n");
	}

	return FALSE;
}


/*
 * Hooks for extension added and removed signals
 */

/*
 * Checks for a particular source to be added and 
 * saves a reference to it.
 */
static void 
source_added_cb (MafwRegistry *registry, 
		 GObject *source, 
		 gpointer user_data)
{
	if (MAFW_IS_SOURCE(source)) {
		const gchar *name = 
			mafw_extension_get_name(MAFW_EXTENSION(source));

		g_print("[INFO] Source %s available.\n", name);

		if (strcmp (name, WANTED_SOURCE) == 0) {
			g_print ("[INFO]     Wanted source found!\n");
			app_source = g_object_ref (source);

			/* When we find the source we are interested in,
			   do a browse request */
			g_timeout_add (1000, do_browse_request, user_data);
		} else {
			g_print ("[INFO]     Not interesting. Skipping...\n");
		}
	}
}

/*
 * Checks if the referenced source is removed, and if so, exits.
 */
static void 
source_removed_cb (MafwRegistry *registry, 
		   GObject *source, 
		   gpointer user_data)
{
	if (MAFW_IS_SOURCE(source)) {
		g_print("[INFO] Source %s removed.\n", 
			mafw_extension_get_name(MAFW_EXTENSION(source)));

		if (MAFW_SOURCE (source) == app_source) {
			g_print ("[INFO]     Wanted source removed!"
				 " Exiting...\n");
			g_object_unref (app_source);
			g_main_loop_quit (main_loop);
		}
	}
}

static void 
renderer_added_cb (MafwRegistry *registry, 
		   GObject *renderer, 
		   gpointer user_data)
{
	if (MAFW_IS_RENDERER(renderer)) {
		g_print("[INFO] Renderer %s available.\n", 
			mafw_extension_get_name(MAFW_EXTENSION(renderer)));
	}
}

static void
renderer_removed_cb (MafwRegistry * registry, 
		     GObject *renderer, 
		     gpointer user_data)
{
	if (MAFW_IS_RENDERER(renderer)) {
		g_print("Renderer %s removed.\n", 
			mafw_extension_get_name(MAFW_EXTENSION(renderer)));
	}
}

/*
 * Loads MAFW plugins.
 *
 * This function lods out-of-process extensions and hooks to
 * source-added and source-removed signals for dynamic extension
 * discovery and removal.
 *
 * Also, this function allows loading of in-process extensions
 * defined through an environment variable.
 *
 * The object_id parameter is used to browse that object as soon
 * as the source of interest is loaded.
 */
gboolean static
app_init (gchar *object_id) 
{
        GError *error = NULL;
	gchar **plugins = NULL;
	GList *extension_list = NULL;
	MafwRegistry *registry = NULL;

	/* ----- Basic MAFW setup ---- */

	/* Init GType */
        g_type_init ();

	/* Init MAFW log (show all messages) */
	mafw_log_init (G_LOG_DOMAIN ":ALL");

	/* ---- Start out-of-process plugin loading ---- */

	g_print ("[INFO] Checking for out-of-process plugins...\n");

	/* Check available plugins  */
	registry = MAFW_REGISTRY (mafw_registry_get_instance());
	if (registry == NULL) {
		g_error ("app_init: Failed to get MafwRegistry reference\n");
		return FALSE;
	}

	/* Start out-of-process extension discovery */
	mafw_shared_init (registry, &error);
	if (error != NULL)
	{
		g_warning ("Ext. discovery failed: %s",
			   error->message);
		g_error_free(error);
		error = NULL;
	} 

	/* Connect to extension discovery signals. These signals will be
	   emitted when new extensions are started or removed */
	g_signal_connect (registry,
			  "renderer_added", 
			  G_CALLBACK(renderer_added_cb), NULL);

	g_signal_connect (registry,
			  "renderer_removed", 
			  G_CALLBACK(renderer_removed_cb), NULL);

	g_signal_connect (registry,
			  "source_added", 
			  G_CALLBACK(source_added_cb), object_id);

	g_signal_connect (registry,
			  "source_removed", 
			  G_CALLBACK(source_removed_cb), NULL);

	/* Also, check for already started extensions */
	extension_list = mafw_registry_get_renderers(registry);
	while (extension_list)
	{
		renderer_added_cb (registry, 
				   G_OBJECT(extension_list->data), NULL);
		extension_list = g_list_next(extension_list);
	}
	
	extension_list = mafw_registry_get_sources(registry);
	while (extension_list)
	{
		source_added_cb (registry, 
				 G_OBJECT(extension_list->data), NULL);
		extension_list = g_list_next(extension_list);
	}

	
	/* ---- Start in-process plugin loading ---- */

	/* MAFW_INP_PLUGINS shold contain a list of paths
	   to plugin files to be loaded in-process */

	g_print ("[INFO] Checking for in-process plugins...\n");
	if (g_getenv("MAFW_INP_PLUGINS") != NULL) {
		plugins = g_strsplit (g_getenv ("MAFW_INP_PLUGINS"),
				      G_SEARCHPATH_SEPARATOR_S, 
				      0);

		for (; NULL != *plugins; plugins++) {
			g_print ("[INFO] Loading in-process plugin %s...\n",
				 *plugins);

			mafw_registry_load_plugin (MAFW_REGISTRY(registry),
						   *plugins, 
						   &error);

			if (error != NULL) {
				gchar* msg;
				msg = g_strdup_printf (
					"Unable to load inp. plugin %s: %s", 
					*plugins,
					error->message);

				g_warning ("Plugin loading failed: %s", msg);

				g_free(msg);
				g_error_free(error);
				error = NULL;
			} 
		}
	} else {
		g_print ("[INFO]     No in-process plugins requested.\n");
	}
}

int
main (int argc, gchar *argv[])
{
	if (argc != 2) {
		g_error ("Please, provide exactly one argument specifying "
			 "the object identifier of the item to browse.");
	}

	g_print ("[INFO] Starting example...\n");
	app_init (argv[1]);
	g_print ("[INFO] Example started.\n");

	main_loop = g_main_loop_new (NULL, FALSE);
	g_main_loop_run (main_loop);

	return 0;
}