Exemplo n.º 1
0
void
cmd_playlists_list (xmmsc_connection_t *conn, gint argc, gchar **argv)
{
	const gchar *active_name;
	xmmsc_result_t *res, *active_res;
	xmmsv_t *val, *active_val;
	xmmsv_list_iter_t *it;

	active_res = xmmsc_playlist_current_active (conn);
	xmmsc_result_wait (active_res);
	active_val = xmmsc_result_get_value (active_res);

	if (xmmsv_is_error (active_val) ||
	    !xmmsv_get_string (active_val, &active_name)) {
		active_name = NULL;
	}

	res = xmmsc_playlist_list (conn);
	xmmsc_result_wait (res);
	val = xmmsc_result_get_value (res);

	if (xmmsv_is_error (val)) {
		print_error ("%s", xmmsv_get_error_old (val));
	}

	xmmsv_get_list_iter (val, &it);
	while (xmmsv_list_iter_valid (it)) {
		xmmsv_t *valstr;
		const gchar *name;

		xmmsv_list_iter_entry (it, &valstr);
		if (!xmmsv_get_string (valstr, &name)) {
			print_error ("Broken resultset");
		}

		/* Hide all lists that start with _ */
		if (name[0] != '_') {
			if (active_name != NULL && strcmp (active_name, name) == 0) {
				print_info ("->%s", name);
			} else {
				print_info ("  %s", name);
			}
		}
		xmmsv_list_iter_next (it);
	}
	xmmsc_result_unref (res);
	xmmsc_result_unref (active_res);
}
Exemplo n.º 2
0
static gboolean
ol_player_xmms2_go_rel (int rel)
{
  ol_log_func ();
  ol_debugf ("  rel:%d\n", rel);
  if (!ol_player_xmms2_ensure_connection ())
    return FALSE;
  xmmsc_result_t *result = xmmsc_playlist_set_next_rel (connection, rel);
  xmmsc_result_wait (result);
  xmmsv_t *return_value = xmmsc_result_get_value (result);
  if (xmmsv_is_error (return_value))
  {
    ol_debug ("Error on setting playlist next");
    return FALSE;
  }
  xmmsc_result_unref (result);

  result = xmmsc_playback_tickle (connection);
  xmmsc_result_wait (result);
  if (xmmsc_result_iserror (result))
  {
    ol_debug ("Error on tickle playback");
    return FALSE;
  }
  xmmsc_result_unref (result);
  return TRUE;
}
Exemplo n.º 3
0
static gint
refresh_active_playlist (xmmsv_t *val, void *udata)
{
	cli_cache_t *cache = (cli_cache_t *) udata;
	xmmsv_list_iter_t *it;
	gint32 id;

	if (!xmmsv_is_error (val)) {
		/* Reset array */
		if (cache->active_playlist->len > 0) {
			gint len = cache->active_playlist->len;
			cache->active_playlist = g_array_remove_range (cache->active_playlist,
			                                               0, len);
		}

		xmmsv_get_list_iter (val, &it);

		/* .. and refill it */
		while (xmmsv_list_iter_valid (it)) {
			xmmsv_t *entry;
			xmmsv_list_iter_entry (it, &entry);
			xmmsv_get_int (entry, &id);
			g_array_append_val (cache->active_playlist, id);

			xmmsv_list_iter_next (it);
		}
	}

	freshness_received (&cache->freshness_active_playlist);

	return TRUE;
}
Exemplo n.º 4
0
static int32_t
ol_player_xmms2_get_currend_id ()
{
  /* ol_log_func (); */
  if (!ol_player_xmms2_ensure_connection ())
    return 0;
  int32_t ret = 0;
  xmmsc_result_t *result = xmmsc_playback_current_id (connection);
  xmmsc_result_wait (result);
  xmmsv_t *return_value = xmmsc_result_get_value (result);
  if (xmmsv_is_error (return_value))
  {
    ol_error ("Error on getting current id");
    ret = 0;
  }
  else
  {
    if (!xmmsv_get_int (return_value, &ret))
    {
      ol_error ("Get id from result failed");
      ret = 0;
    }
  }
  xmmsc_result_unref (result);
  return ret;
}
Exemplo n.º 5
0
static gboolean
ol_player_xmms2_get_music_length (int *len)
{
  /* ol_log_func (); */
  ol_assert_ret (len != NULL, FALSE);
  if (!ol_player_xmms2_ensure_connection ())
    return FALSE;
  *len = 0;
  int32_t id = ol_player_xmms2_get_currend_id ();
  if (id > 0)
  {
    xmmsc_result_t *result = xmmsc_medialib_get_info (connection, id);
    xmmsc_result_wait (result);
    xmmsv_t *return_value = xmmsc_result_get_value (result);
    if (xmmsv_is_error (return_value))
    {
      ol_error ("Get music info from XMMS2 failed.");
    }
    else
    {
      xmmsv_t *dict = xmmsv_propdict_to_dict (return_value, NULL);
      *len = ol_player_xmms2_get_dict_int (return_value, "duration");
      xmmsv_unref (dict);
    }
    xmmsc_result_unref (result);
  }
  return TRUE;
}
Exemplo n.º 6
0
Dict::Dict( xmmsv_t* val ) : value_( 0 )
{
    if( xmmsv_is_error( val ) ) {
        const char *buf;
        xmmsv_get_error( val, &buf );
        throw value_error( buf );
    }
    else if( xmmsv_get_type( val ) != XMMSV_TYPE_DICT ) {
        throw not_dict_error( "Value is not a dict" );
    }
    setValue( val );
}
Exemplo n.º 7
0
static gint
refresh_playback_status (xmmsv_t *val, void *udata)
{
	cli_cache_t *cache = (cli_cache_t *) udata;

	if (!xmmsv_is_error (val)) {
		xmmsv_get_int (val, &cache->playback_status);
	}

	freshness_received (&cache->freshness_playback_status);

	return TRUE;
}
Exemplo n.º 8
0
static gint
refresh_currid (xmmsv_t *val, void *udata)
{
	cli_cache_t *cache = (cli_cache_t *) udata;

	if (!xmmsv_is_error (val)) {
		xmmsv_get_int (val, &cache->currid);
	}

	freshness_received (&cache->freshness_currid);

	return TRUE;
}
Exemplo n.º 9
0
static gint
refresh_active_playlist (xmmsv_t *val, void *udata)
{
    cli_cache_t *cache = (cli_cache_t *) udata;

    if (!xmmsv_is_error (val)) {
        xmmsv_unref (cache->active_playlist);
        cache->active_playlist = xmmsv_ref (val);
    }

    freshness_received (&cache->freshness_active_playlist);

    return TRUE;
}
Exemplo n.º 10
0
static gint
refresh_active_playlist_name (xmmsv_t *val, void *udata)
{
	cli_cache_t *cache = (cli_cache_t *) udata;
	const gchar *buf;

	if (!xmmsv_is_error (val) && xmmsv_get_string (val, &buf)) {
		g_free (cache->active_playlist_name);
		cache->active_playlist_name = g_strdup (buf);
	}

	freshness_received (&cache->freshness_active_playlist_name);

	return TRUE;
}
Exemplo n.º 11
0
static gint
refresh_currpos (xmmsv_t *val, void *udata)
{
	cli_cache_t *cache = (cli_cache_t *) udata;

	if (!xmmsv_is_error (val)) {
		xmmsv_dict_entry_get_int (val, "position", &cache->currpos);
	} else {
		/* Current pos not set */
		cache->currpos = -1;
	}

	freshness_received (&cache->freshness_currpos);

	return TRUE;
}
Exemplo n.º 12
0
void
cmd_addpls (xmmsc_connection_t *conn, gint argc, gchar **argv)
{
	gchar *playlist;
	xmmsc_result_t *res, *res2;
	xmmsv_t *val;
	xmmsv_coll_t *coll;
	gchar *url;

	if (argc < 3) {
		print_error ("Supply path to playlist file");
	}

	if (argc == 3) {
		playlist = NULL;
		url = format_url (argv[2], G_FILE_TEST_IS_REGULAR);
	} else {
		playlist = argv[2];
		url = format_url (argv[3], G_FILE_TEST_IS_REGULAR);
	}

	res = xmmsc_coll_idlist_from_playlist_file (conn, url);
	g_free (url);

	xmmsc_result_wait (res);
	val = xmmsc_result_get_value (res);

	if (xmmsv_is_error (val)) {
		print_error ("%s", xmmsv_get_error_old (val));
	}

	if (!xmmsv_get_coll (val, &coll)) {
		print_error ("Couldn't get collection from result!");
	}

	res2 = xmmsc_playlist_add_idlist (conn, playlist, coll);
	xmmsc_result_wait (res2);
	if (xmmsc_result_iserror (res2)) {
		print_error ("%s", xmmsc_result_get_error (res2));
	}

	print_info ("Playlist with %d entries added", xmmsv_coll_idlist_get_size (coll));

	xmmsc_result_unref (res);
	xmmsc_result_unref (res2);
}
Exemplo n.º 13
0
void
cmd_playlist_active (xmmsc_connection_t *conn, gint argc, gchar **argv)
{
	const gchar *active_name;
	xmmsc_result_t *active_res;
	xmmsv_t *active_val;

	active_res = xmmsc_playlist_current_active (conn);
	xmmsc_result_wait (active_res);
	active_val = xmmsc_result_get_value (active_res);

	if (!xmmsv_is_error (active_val) &&
	    xmmsv_get_string (active_val, &active_name)) {
		print_info ("%s",active_name);
	}

	xmmsc_result_unref (active_res);
}
Exemplo n.º 14
0
static gboolean
ol_player_xmms2_get_music_info (OlMusicInfo *info)
{
  /* ol_log_func (); */
  ol_assert_ret (info != NULL, FALSE);
  if (!ol_player_xmms2_ensure_connection ())
    return FALSE;
  ol_music_info_clear (info);
  int32_t id = ol_player_xmms2_get_currend_id ();
  if (id > 0)
  {
    xmmsc_result_t *result = xmmsc_medialib_get_info (connection, id);
    xmmsc_result_wait (result);
    xmmsv_t *return_value = xmmsc_result_get_value (result);
    if (xmmsv_is_error (return_value))
    {
      ol_error ("Get music info from XMMS2 failed.");
    }
    else
    {
      xmmsv_t *dict = xmmsv_propdict_to_dict (return_value, NULL);
      info->title = ol_player_xmms2_get_dict_string (dict, "title");
      info->artist = ol_player_xmms2_get_dict_string (dict, "artist");
      info->album = ol_player_xmms2_get_dict_string (dict, "album");
      info->track_number = ol_player_xmms2_get_dict_int (dict, "tracknr");
      info->uri = ol_player_xmms2_get_dict_string (dict, "url");
      ol_logf (OL_DEBUG,
               "%s\n"
               "  title:%s\n"
               "  artist:%s\n"
               "  album:%s\n"
               "  uri:%s\n",
               __FUNCTION__,
               info->title,
               info->artist,
               info->album,
               info->uri);
      xmmsv_unref (dict);
    }
    xmmsc_result_unref (result);
  }
  return TRUE;
}
Exemplo n.º 15
0
static enum OlPlayerStatus
ol_player_xmms2_get_status ()
{
  if (!ol_player_xmms2_ensure_connection ())
    return OL_PLAYER_ERROR;
  int ret;
  xmmsc_result_t *result = xmmsc_playback_status (connection);
  xmmsc_result_wait (result);
  xmmsv_t *return_value = xmmsc_result_get_value (result);
  if (xmmsv_is_error (return_value))
  {
    ret = OL_PLAYER_ERROR;
  }
  else
  {
    int32_t status;
    if (xmmsv_get_int (return_value, &status))
    {
      switch (status)
      {
      case XMMS_PLAYBACK_STATUS_STOP:
        ret = OL_PLAYER_STOPPED;
        break;
      case XMMS_PLAYBACK_STATUS_PLAY:
        ret = OL_PLAYER_PLAYING;
        break;
      case XMMS_PLAYBACK_STATUS_PAUSE:
        ret = OL_PLAYER_PAUSED;
        break;
      default:
        ret = OL_PLAYER_UNKNOWN;
        break;
      }
    }
    else
    {
      ret = OL_PLAYER_ERROR;
    }
  }
  xmmsc_result_unref (result);
  return ret;
}
Exemplo n.º 16
0
gboolean
playlist_exists (cli_infos_t *infos, gchar *playlist)
{
	gboolean retval = FALSE;
	xmmsc_result_t *res;
	xmmsv_t *val;

	res = xmmsc_coll_get (infos->sync, playlist, XMMS_COLLECTION_NS_PLAYLISTS);
	xmmsc_result_wait (res);

	val = xmmsc_result_get_value (res);

	if (!xmmsv_is_error (val)) {
		retval = TRUE;
	}

	xmmsc_result_unref (res);

	return retval;
}
Exemplo n.º 17
0
int
xmmsc_connect (xmmsc_connection_t *c, const char *ipcpath)
{
	xmmsc_ipc_t *ipc;
	xmmsc_result_t *result;
	xmmsv_t *value;

	const char *buf;

	x_api_error_if (!c, "with a NULL connection", false);

	if (!ipcpath) {
		if (!xmms_default_ipcpath_get (c->path, sizeof (c->path))) {
			return false;
		}
	} else {
		snprintf (c->path, sizeof (c->path), "%s", ipcpath);
	}

	ipc = xmmsc_ipc_init ();

	if (!xmmsc_ipc_connect (ipc, c->path)) {
		c->error = strdup ("xmms2d is not running.");
		xmmsc_ipc_destroy (ipc);
		return false;
	}

	c->ipc = ipc;
	result = xmmsc_send_hello (c);
	xmmsc_result_wait (result);
	value = xmmsc_result_get_value (result);
	if (xmmsv_is_error (value)) {
		xmmsv_get_error (value, &buf);
		c->error = strdup (buf);
		xmmsc_result_unref (result);
		return false;
	}
	xmmsc_result_unref (result);
	return true;
}
Exemplo n.º 18
0
static gboolean
ol_player_xmms2_get_played_time (int *played_time)
{
  /* ol_log_func (); */
  ol_assert_ret (played_time != NULL, FALSE);
  if (!ol_player_xmms2_ensure_connection ())
    return FALSE;
  xmmsc_result_t *result = xmmsc_playback_playtime (connection);
  xmmsc_result_wait (result);
  xmmsv_t *return_value = xmmsc_result_get_value (result);
  if (xmmsv_is_error (return_value))
  {
    ol_error ("Get played time from XMMS2 failed");
    return FALSE;
  }
  int32_t elapsed = 0;
  xmmsv_get_int (return_value, &elapsed);
  *played_time = elapsed;
  xmmsc_result_unref (result);
  /* ol_debugf ("time: %d\n", *played_time); */
  return TRUE;
}
Exemplo n.º 19
0
void
cmd_list (xmmsc_connection_t *conn, gint argc, gchar **argv)
{
	gchar *playlist = NULL;
	xmmsc_result_t *res;
	xmmsv_t *val;
	xmmsv_list_iter_t *it;
	gulong total_playtime = 0;
	gint p = 0;
	guint pos = 0;

	if (argc > 2) {
		playlist = argv[2];
	}

	res = xmmsc_playlist_current_pos (conn, playlist);
	xmmsc_result_wait (res);
	val = xmmsc_result_get_value (res);

	if (!xmmsv_is_error (val)) {
		if (!xmmsv_dict_entry_get_int (val, "position", &p)) {
			print_error ("Broken resultset");
		}
		xmmsc_result_unref (res);
	}

	res = xmmsc_playlist_list_entries (conn, playlist);
	xmmsc_result_wait (res);
	val = xmmsc_result_get_value (res);

	if (xmmsv_is_error (val)) {
		print_error ("%s", xmmsv_get_error_old (val));
	}

	xmmsv_get_list_iter (val, &it);
	while (xmmsv_list_iter_valid (it)) {
		xmmsc_result_t *info_res;
		xmmsv_t *val_id, *propdict, *info_val;
		gchar line[80];
		gint playtime = 0;
		guint ui;

		xmmsv_list_iter_entry (it, &val_id);
		if (!xmmsv_get_uint (val_id, &ui)) {
			print_error ("Broken resultset");
		}

		info_res = xmmsc_medialib_get_info (conn, ui);
		xmmsc_result_wait (info_res);
		propdict = xmmsc_result_get_value (info_res);
		info_val = xmmsv_propdict_to_dict (propdict, NULL);

		if (xmmsv_is_error (info_val)) {
			print_error ("%s", xmmsv_get_error_old (info_val));
		}

		if (xmmsv_dict_entry_get_int (info_val, "duration", &playtime)) {
			total_playtime += playtime;
		}

		if (val_has_key (info_val, "channel")) {
			if (val_has_key (info_val, "title")) {
				xmmsc_entry_format (line, sizeof (line),
				                    "[stream] ${title}", info_val);
			} else {
				xmmsc_entry_format (line, sizeof (line),
				                    "${channel}", info_val);
			}
		} else if (!val_has_key (info_val, "title")) {
			const gchar *url;
			gchar dur[10];

			xmmsc_entry_format (dur, sizeof (dur),
			                    "(${minutes}:${seconds})", info_val);

			if (xmmsv_dict_entry_get_string (info_val, "url", &url)) {
				gchar *filename = g_path_get_basename (url);
				if (filename) {
					g_snprintf (line, sizeof (line), "%s %s", filename, dur);
					g_free (filename);
				} else {
					g_snprintf (line, sizeof (line), "%s %s", url, dur);
				}
			}
		} else {
			xmmsc_entry_format (line, sizeof (line), listformat, info_val);
		}

		if (p == pos) {
			print_info ("->[%d/%d] %s", pos, ui, line);
		} else {
			print_info ("  [%d/%d] %s", pos, ui, line);
		}

		pos++;

		xmmsc_result_unref (info_res);
		xmmsv_unref (info_val);
		xmmsv_list_iter_next (it);
	}
	xmmsc_result_unref (res);

	/* rounding */
	total_playtime += 500;

	print_info ("\nTotal playtime: %d:%02d:%02d", total_playtime / 3600000,
	            (total_playtime / 60000) % 60, (total_playtime / 1000) % 60);
}
Exemplo n.º 20
0
int
main (int argc, char **argv)
{
	/* 
	 * To connect to xmms2d you need to first have a
	 * connection.
	 */
	xmmsc_connection_t *connection;

	/*
	 * xmmsc_result_t is the struct returned from all
	 * commands that are given to the xmms2d server
	 * we just declare a variable of this type here,
	 * we'll need it later.
	 */
	xmmsc_result_t *result;

	/*
	 * xmmsv_t is the wrapper struct used to communicate
	 * values to/from the server.  Typically, when a client
	 * issues commands, the server answers by sending back
	 * the return value for the command. Here, we will only
	 * use it to check if the server returned an error.
	 */
	xmmsv_t *return_value;

	/*
	 * We need a string pointer to retrieve the error (if any)
	 * from the xmmsv_t.  Note that the string will still be
	 * owned by the xmmsv_t structure.
	 */
	const char *err_buf;

	/*
	 * First we need to initialize the connection;
	 * as argument you need to pass "name" of your
	 * client. The name has to be in the range [a-zA-Z0-9]
	 * because xmms is deriving configuration values
	 * from this name.
	 */
	connection = xmmsc_init ("tutorial1");

	/*
	 * xmmsc_init will return NULL if memory is
	 * not available
	 */
	if (!connection) {
		fprintf (stderr, "OOM!\n");
		exit (EXIT_FAILURE);
	}

	/*
	 * Now we need to connect to xmms2d. We need to
	 * pass the XMMS ipc-path to the connect call.
	 * If passed NULL, it will default to 
	 * unix:///tmp/xmms-ipc-<user>, but all xmms2 clients
	 * should handle the XMMS_PATH enviroment in
	 * order to configure connection path.
	 *
	 * xmmsc_connect will return NULL if an error occured
	 * and it will set the xmmsc_get_last_error() to a
	 * string describing the error
	 */
	if (!xmmsc_connect (connection, getenv ("XMMS_PATH"))) {
		fprintf (stderr, "Connection failed: %s\n",
		         xmmsc_get_last_error (connection));

		exit (EXIT_FAILURE);
	}

	/*
	 * This is all you have to do to connect to xmms2d.
	 * Now we can send commands. Let's do something easy
	 * like getting xmms2d to start playback.
	 */
	result = xmmsc_playback_start (connection);

	/*
	 * The command will be sent, and since this is a
	 * synchronous connection we can block for its 
	 * return here. The async / sync issue will be
	 * commented on later.
	 */
	xmmsc_result_wait (result);

	/*
	 * When xmmsc_result_wait() returns, we have the
	 * answer from the server. We now extract that value
	 * from the result. Note that the value is still owned
	 * by the result, and will be freed along with it.
	 */
	return_value = xmmsc_result_get_value (result);

	/*
	 * Let's check if the value returned by the server
	 * is an error, and print it out if it is.
	 */
	if (xmmsv_is_error (return_value) &&
	    xmmsv_get_error (return_value, &err_buf)) {
		fprintf (stderr, "playback start returned error, %s",
		         err_buf);
	}

	/*
	 * This is very important - when we are done with the
	 * result we need to tell that to the clientlib,
	 * we do that by unrefing it. this will free resources,
	 * including the return_value, and make sure that we don't
	 * leak memory. It is not possible to touch the result or
	 * the return_value after we have done this.
	 */
	xmmsc_result_unref (result);

	/*
	 * Now we are done, let's disconnect and free up all
	 * used resources.
	 */
	xmmsc_unref (connection);

	return (EXIT_SUCCESS);
}
Exemplo n.º 21
0
void
cmd_playlist_type (xmmsc_connection_t *conn, gint argc, gchar **argv)
{
	gchar *name;
	xmmsv_coll_type_t prevtype, newtype;
	xmmsc_result_t *res;
	xmmsv_t *val;
	xmmsv_coll_t *coll;

	/* Read playlist name */
	if (argc < 4) {
		print_error ("usage: type_playlist [playlistname] [type] [options]");
	}
	name = argv[3];

	/* Retrieve the playlist operator */
	res = xmmsc_coll_get (conn, name, XMMS_COLLECTION_NS_PLAYLISTS);
	xmmsc_result_wait (res);
	val = xmmsc_result_get_value (res);

	if (xmmsv_is_error (val)) {
		print_error ("%s", xmmsv_get_error_old (val));
	}

	xmmsv_get_coll (val, &coll);
	prevtype = xmmsv_coll_get_type (coll);

	/* No type argument, simply display the current type */
	if (argc < 5) {
		print_info (get_playlist_type_string (prevtype));

	/* Type argument, set the new type */
	} else {
		gint typelen;
		gint idlistsize;
		xmmsc_result_t *saveres;
		xmmsv_coll_t *newcoll;
		gint i;

		typelen = strlen (argv[4]);
		if (g_ascii_strncasecmp (argv[4], "list", typelen) == 0) {
			newtype = XMMS_COLLECTION_TYPE_IDLIST;
		} else if (g_ascii_strncasecmp (argv[4], "queue", typelen) == 0) {
			newtype = XMMS_COLLECTION_TYPE_QUEUE;
		} else if (g_ascii_strncasecmp (argv[4], "pshuffle", typelen) == 0) {
			newtype = XMMS_COLLECTION_TYPE_PARTYSHUFFLE;

			/* Setup operand for party shuffle (set operand) ! */
			if (argc < 6) {
				print_error ("Give the source collection for the party shuffle");
			}

		} else {
			print_error ("Invalid playlist type (valid types: list, queue, pshuffle)");
		}

		/* Copy collection idlist, attributes and operand (if needed) */
		newcoll = xmmsv_coll_new (newtype);

		idlistsize = xmmsv_coll_idlist_get_size (coll);
		for (i = 0; i < idlistsize; i++) {
			guint id;
			xmmsv_coll_idlist_get_index (coll, i, &id);
			xmmsv_coll_idlist_append (newcoll, id);
		}

		xmmsv_coll_attribute_foreach (coll, coll_copy_attributes, newcoll);

		if (newtype == XMMS_COLLECTION_TYPE_PARTYSHUFFLE) {
			playlist_setup_pshuffle (conn, newcoll, argv[5]);
		}

		/* Overwrite with new collection */
		saveres = xmmsc_coll_save (conn, newcoll, name, XMMS_COLLECTION_NS_PLAYLISTS);
		xmmsc_result_wait (saveres);

		if (xmmsc_result_iserror (saveres)) {
			print_error ("Couldn't save %s : %s",
			             name, xmmsc_result_get_error (saveres));
		}

		xmmsv_coll_unref (newcoll);
		xmmsc_result_unref (saveres);
	}

	xmmsc_result_unref (res);
}
Exemplo n.º 22
0
int
main (int argc, char **argv)
{
	/*
	 * The first part of this program is
	 * commented on in tut1.c and tut2.c
	 */
	xmmsc_connection_t *connection;
	xmmsc_result_t *result;
	xmmsv_t *return_value;
	const char *err_buf;

	/*
	 * Variables that we'll need later
	 */
	const char *val;
	int intval;
	int id;
	xmmsv_t *dict_entry;
	xmmsv_t *infos;

	connection = xmmsc_init ("tutorial3");
	if (!connection) {
		fprintf (stderr, "OOM!\n");
		exit (EXIT_FAILURE);
	}

	if (!xmmsc_connect (connection, getenv ("XMMS_PATH"))) {
		fprintf (stderr, "Connection failed: %s\n",
		         xmmsc_get_last_error (connection));

		exit (EXIT_FAILURE);
	}

	/*
	 * Ok, let' do the same thing as we did in
	 * tut2.c and retrieve the current playing
	 * entry. We need that to get information
	 * about the song.
	 */
	result = xmmsc_playback_current_id (connection);
	xmmsc_result_wait (result);
	return_value = xmmsc_result_get_value (result);

	if (xmmsv_is_error (return_value) &&
	    xmmsv_get_error (return_value, &err_buf)) {
		fprintf (stderr, "playback current id returns error, %s\n",
		         err_buf);
	}

	if (!xmmsv_get_int (return_value, &id)) {
		fprintf (stderr, "xmmsc_playback_current_id didn't "
		         "return int as expected\n");
		/* Fake id (ids are >= 1) used as an error flag. */
		id = 0;
	}

	/* Print the value */
	printf ("Currently playing id is %d\n", id);

	/*
	 * Same drill as before. Release memory
	 * so that we can reuse it in the next
	 * clientlib call.
	 * */
	xmmsc_result_unref (result);

	/*
	 * Something about the medialib and xmms2. All
	 * entries that are played, put into playlists
	 * have to be in the medialib. A song's metadata
	 * will be added to the medialib the first time
	 * you do "xmms2 add" or equivalent.
	 *
	 * When we request information for an entry, it will
	 * be requested from the medialib, not the playlist
	 * or the playback. The playlist and playback only
	 * know the unique id of the entry. All other
	 * information must be retrieved in subsequent calls.
	 *
	 * Entry 0 is non valid. Only 1-inf is valid.
	 * So let's check for 0 and don't ask medialib for it.
	 */
	if (id == 0) {
		fprintf (stderr, "Nothing is playing.\n");
		exit (EXIT_FAILURE);
	}

	/*
	 * And now for something about return types from
	 * clientlib. The clientlib will always return
	 * an xmmsc_result_t that will eventually contain the
	 * return value as a xmmsv_t struct.
	 * The value can contain an int and string as
	 * base type. It can also contain more complex
	 * types like lists and dicts.
	 * A list is a sequence of values, each of them
	 * wrapped in its own xmmsv_t struct (of any type).

	 * A dict is a key<->value representation where key
	 * is always a string but the value is again wrapped
	 * in its own xmmsv_t struct (of any type).
	 *
	 * When retrieving an entry from the medialib, you
	 * get a dict as return. Let's print out some
	 * entries from it and then traverse the dict.
	 */
	result = xmmsc_medialib_get_info (connection, id);

	/* And waaait for it .. */
	xmmsc_result_wait (result);

	/* Let's reuse the previous return_value pointer, it
	 * was invalidated as soon as we freed the result that
	 * contained it anyway.
	 */
	return_value = xmmsc_result_get_value (result);

	if (xmmsv_is_error (return_value) &&
	    xmmsv_get_error (return_value, &err_buf)) {
		/*
		 * This can return error if the id
		 * is not in the medialib
		 */
		fprintf (stderr, "medialib get info returns error, %s\n",
		         err_buf);
		exit (EXIT_FAILURE);
	}

	/*
	 * Because of the nature of the dict returned by
	 * xmmsc_medialib_get_info, we need to convert it to
	 * a simpler dict using xmmsv_propdict_to_dict.
	 * Let's not worry about that for now and accept it
	 * as a fact of life.
	 *
	 * See tut5 for a discussion about dicts and propdicts.
	 *
	 * Note that xmmsv_propdict_to_dict creates a new
	 * xmmsv_t struct, which we will need to free manually
	 * when we're done with it.
	 */
	infos = xmmsv_propdict_to_dict (return_value, NULL);

	/*
	 * We must first retrieve the xmmsv_t struct
	 * corresponding to the "artist" key in the dict,
	 * and then extract the string from that struct.
	 */
	if (!xmmsv_dict_get (infos, "artist", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &val)) {
		/*
		 * if we end up here it means that the key "artist" wasn't
		 * in the dict or that the value for "artist" wasn't a
		 * string.
		 *
		 * You can check the type of the entry (if there is one) with
		 * xmmsv_get_type (dict_entry). It will return an
		 * xmmsv_type_t enum describing the type.
		 *
		 * Actually this is no disaster, it might just mean that
		 * we don't have an artist tag on this entry. Let's
		 * call it "No Artist" for now.
		 */
		val = "No Artist";
	}

	/* print the value */
	printf ("artist = %s\n", val);

	if (!xmmsv_dict_get (infos, "title", &dict_entry) ||
	    !xmmsv_get_string (dict_entry, &val)) {
		val = "No Title";
	}
	printf ("title = %s\n", val);

	/*
	 * Let's extract an integer as well
	 */
	if (!xmmsv_dict_get (infos, "bitrate", &dict_entry) ||
	    !xmmsv_get_int (dict_entry, &intval)) {
		intval = 0;
	}
	printf ("bitrate = %i\n", intval);

	/*
	 * We need to free infos manually here, else we will leak.
	 */
	xmmsv_unref (infos);

	/*
	 * !!Important!!
	 *
	 * When unreffing the result here we will free
	 * the memory that we have extracted from the dict,
	 * and that includes all the string pointers of the
	 * dict entries! So if you want to keep strings
	 * somewhere you need to copy that memory! Very
	 * important otherwise you will get undefined behaviour.
	 */
	xmmsc_result_unref (result);

	xmmsc_unref (connection);

	return (EXIT_SUCCESS);
}