Exemplo n.º 1
0
/**
 * Insert an entry at a given position in the playlist without
 * validating it.
 *
 * @internal
 */
void
xmms_playlist_insert_entry (xmms_playlist_t *playlist, const gchar *plname,
                            guint32 pos, xmms_medialib_entry_t file,
                            xmms_error_t *err)
{
    xmms_medialib_session_t *session;
    xmmsv_t *dict;
    gint currpos;
    gint len;
    xmmsv_coll_t *plcoll;
    gboolean valid;

    g_mutex_lock (playlist->mutex);

    do {
        session = xmms_medialib_session_begin_ro (playlist->medialib);
        valid = xmms_medialib_check_id (session, file);
    } while (!xmms_medialib_session_commit (session));

    if (!valid) {
        g_mutex_unlock (playlist->mutex);
        xmms_error_set (err, XMMS_ERROR_NOENT,
                        "That is not a valid medialib id!");
        return;
    }


    plcoll = xmms_playlist_get_coll (playlist, plname, err);
    if (plcoll == NULL) {
        /* FIXME: happens ? */
        g_mutex_unlock (playlist->mutex);
        return;
    }

    len = xmms_playlist_coll_get_size (plcoll);
    if (pos > len) {
        xmms_error_set (err, XMMS_ERROR_GENERIC,
                        "Could not insert entry outside of playlist!");
        g_mutex_unlock (playlist->mutex);
        return;
    }
    xmmsv_coll_idlist_insert (plcoll, pos, file);

    /** propagate the MID ! */
    dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_INSERT, file, plname);
    xmmsv_dict_set_int (dict, "position", pos);
    xmms_playlist_changed_msg_send (playlist, dict);

    /** update position once client is familiar with the new item. */
    currpos = xmms_playlist_coll_get_currpos (plcoll);
    if (pos <= currpos) {
        currpos++;
        xmms_collection_set_int_attr (plcoll, "position", currpos);
        XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
    }

    g_mutex_unlock (playlist->mutex);
}
Exemplo n.º 2
0
static xmmsv_t *
medialib_query (xmmsv_coll_t *coll, xmmsv_t *spec, xmms_error_t *err)
{
	xmms_medialib_session_t *session;
	xmmsv_t *ret;

	session = xmms_medialib_session_begin (medialib);
	ret = xmms_medialib_query (session, coll, spec, err);
	xmms_medialib_session_commit (session);

	return ret;
}
Exemplo n.º 3
0
gint32
xmms_medialib_client_get_id (xmms_medialib_t *medialib, const gchar *url,
                             xmms_error_t *error)
{
	xmms_medialib_session_t *session;
	gint32 ret;

	do {
		session = xmms_medialib_session_begin_ro (medialib);
		ret = xmms_medialib_get_id (session, url, error);
	} while (!xmms_medialib_session_commit (session));

	return ret;
}
Exemplo n.º 4
0
static void
xmms_medialib_client_add_entry (xmms_medialib_t *medialib, const gchar *url,
                                xmms_error_t *error)
{
	xmms_medialib_session_t *session;

	g_return_if_fail (medialib);
	g_return_if_fail (url);

	do {
		session = xmms_medialib_session_begin (medialib);
		xmms_medialib_entry_new_encoded (session, url, error);
	} while (!xmms_medialib_session_commit (session));
}
Exemplo n.º 5
0
/**
 * Insert an entry into the playlist at given position.
 * Creates a #xmms_medialib_entry for you and insert it
 * in the list.
 *
 * @param playlist the playlist to add it URL to.
 * @param pos the position where the entry is inserted.
 * @param url the URL to add.
 * @param err an #xmms_error_t that should be defined upon error.
 * @return TRUE on success and FALSE otherwise.
 *
 */
static void
xmms_playlist_client_insert_url (xmms_playlist_t *playlist, const gchar *plname,
                                 gint32 pos, const gchar *url, xmms_error_t *err)
{
    xmms_medialib_session_t *session;
    xmms_medialib_entry_t entry = 0;

    do {
        session = xmms_medialib_session_begin (playlist->medialib);
        entry = xmms_medialib_entry_new_encoded (session, url, err);
    } while (!xmms_medialib_session_commit (session));

    if (entry)
        xmms_playlist_insert_entry (playlist, plname, pos, entry, err);
}
Exemplo n.º 6
0
static void
xmms_medialib_client_remove_entry (xmms_medialib_t *medialib,
                                   xmms_medialib_entry_t entry,
                                   xmms_error_t *error)
{
	xmms_medialib_session_t *session;

	do {
		session = xmms_medialib_session_begin (medialib);
		if (xmms_medialib_check_id (session, entry)) {
			xmms_medialib_entry_remove (session, entry);
		} else {
			xmms_error_set (error, XMMS_ERROR_NOENT, "No such entry");
		}
	} while (!xmms_medialib_session_commit (session));
}
Exemplo n.º 7
0
xmms_xform_t *
xmms_xform_chain_setup (xmms_medialib_t *medialib, xmms_medialib_entry_t entry,
                        GList *goal_formats, gboolean rehash)
{
	xmms_medialib_session_t *session;
	xmms_xform_t *ret = NULL;

	do {
		session = xmms_medialib_session_begin (medialib);
		if (ret != NULL)
			xmms_object_unref (ret);
		ret = xmms_xform_chain_setup_session (medialib, session, entry, goal_formats, rehash);
	} while (!xmms_medialib_session_commit (session));

	return ret;
}
Exemplo n.º 8
0
static void
xmms_xform_metadata_update (xmms_xform_t *xform)
{
	xmms_medialib_session_t *session;
	metadata_festate_t info;

	g_return_if_fail (xform->medialib);

	do {
		session = xmms_medialib_session_begin (xform->medialib);

		info.entry = xform->entry;
		info.session = session;

		xmms_xform_metadata_collect_one (xform, &info);
	} while (!xmms_medialib_session_commit (session));
}
Exemplo n.º 9
0
/**
  * Convenient function for adding a URL to the playlist,
  * Creates a #xmms_medialib_entry_t for you and adds it
  * to the list.
  *
  * @param playlist the playlist to add it URL to.
  * @param plname the name of the playlist to modify.
  * @param nurl the URL to add
  * @param err an #xmms_error_t that should be defined upon error.
  * @return TRUE on success and FALSE otherwise.
  */
void
xmms_playlist_client_add_url (xmms_playlist_t *playlist, const gchar *plname,
                              const gchar *nurl, xmms_error_t *err)
{
    xmms_medialib_session_t *session;
    xmms_medialib_entry_t entry = 0;

    do {
        session = xmms_medialib_session_begin (playlist->medialib);
        entry = xmms_medialib_entry_new_encoded (session, nurl, err);
    } while (!xmms_medialib_session_commit (session));

    if (entry) {
        xmms_playlist_add_entry (playlist, plname, entry, err);
    }

}
Exemplo n.º 10
0
/**
 * Recursively scan a directory for media files.
 *
 * @return a reverse sorted list of encoded urls
 */
static gboolean
process_dir (xmms_medialib_t *medialib, xmmsv_t *entries,
             const gchar *directory, xmms_error_t *error)
{
	xmmsv_list_iter_t *it;
	xmmsv_t *list, *val;

	list = xmms_xform_browse (directory, error);
	if (!list) {
		return FALSE;
	}

	xmmsv_get_list_iter (list, &it);

	while (xmmsv_list_iter_entry (it, &val)) {
		const gchar *str;
		gint isdir;

		xmmsv_dict_entry_get_string (val, "path", &str);
		xmmsv_dict_entry_get_int (val, "isdir", &isdir);

		if (isdir == 1) {
			process_dir (medialib, entries, str, error);
		} else {
			xmms_medialib_session_t *session;
			xmms_medialib_entry_t entry;

			do {
				session = xmms_medialib_session_begin (medialib);
				entry = xmms_medialib_entry_new_encoded (session, str, error);
			} while (!xmms_medialib_session_commit (session));

			if (entry) {
				xmmsv_coll_idlist_append (entries, entry);
			}
		}

		xmmsv_list_iter_remove (it);
	}

	xmmsv_unref (list);

	return TRUE;
}
Exemplo n.º 11
0
static void
xmms_medialib_client_remove_property (xmms_medialib_t *medialib,
                                      xmms_medialib_entry_t entry,
                                      const gchar *source, const gchar *key,
                                      xmms_error_t *error)
{
	xmms_medialib_session_t *session;

	do {
		session = xmms_medialib_session_begin (medialib);
		if (g_ascii_strcasecmp (source, "server") == 0) {
			xmms_error_set (error, XMMS_ERROR_GENERIC, "Can't remove properties set by the server!");
		} else if (xmms_medialib_check_id (session, entry)) {
			xmms_medialib_property_remove (session, entry, source, key, error);
		} else {
			xmms_error_set (error, XMMS_ERROR_NOENT, "No such entry");
		}
	} while (!xmms_medialib_session_commit (session));
}
Exemplo n.º 12
0
static xmmsv_t *
xmms_medialib_client_get_info (xmms_medialib_t *medialib,
                               xmms_medialib_entry_t entry,
                               xmms_error_t *err)
{
	xmms_medialib_session_t *session;
	xmmsv_t *ret = NULL;

	do {
		session = xmms_medialib_session_begin_ro (medialib);
		if (xmms_medialib_check_id (session, entry)) {
			ret = xmms_medialib_entry_to_tree (session, entry);
		} else {
			xmms_error_set (err, XMMS_ERROR_NOENT, "No such entry");
		}
	} while (!xmms_medialib_session_commit (session));

	return ret;
}
Exemplo n.º 13
0
/**
 * Performance test predicate
 */
static gboolean
run_performance_test (xmms_medialib_t *medialib, const gchar *name, xmmsv_t *content,
                      xmmsv_t *coll, xmmsv_t *specification, xmmsv_t *expected,
                      gint format, const gchar *datasetname)
{
	xmms_medialib_session_t *session;
	xmms_error_t err;
	GTimeVal t0, t1;
	guint64 duration;
	xmmsv_t *ret;

	session = xmms_medialib_session_begin (medialib);

	g_get_current_time (&t0);
	ret = xmms_medialib_query (session, coll, specification, &err);
	g_get_current_time (&t1);

	xmms_medialib_session_commit (session);

	duration = (guint64)((t1.tv_sec - t0.tv_sec) * G_USEC_PER_SEC) + (t1.tv_usec - t0.tv_usec);

	if (format == FORMAT_PRETTY)
		g_print ("* Test %s\n", name);

	if (xmms_error_iserror (&err)) {
		if (format == FORMAT_CSV) {
			g_print ("\"%s\",\"%s\",0,0\n", datasetname, name);
		} else {
			g_print ("   - Query failed: %s\n", xmms_error_message_get (&err));
		}
	} else {
		if (format == FORMAT_CSV) {
			g_print ("\"%s\",\"%s\",1,%" G_GUINT64_FORMAT "\n", datasetname, name, duration);
		} else {
			g_print ("   - Time elapsed: %.3fms\n", duration / 1000.0);
		}
	}

	xmmsv_unref (ret);

	return TRUE;
}
Exemplo n.º 14
0
static void
xmms_medialib_client_rehash (xmms_medialib_t *medialib,
                             xmms_medialib_entry_t entry,
                             xmms_error_t *error)
{
	xmms_medialib_session_t *session;

	do {
		session = xmms_medialib_session_begin (medialib);
		if (xmms_medialib_check_id (session, entry)) {
			xmms_medialib_entry_status_set (session, entry, XMMS_MEDIALIB_ENTRY_STATUS_REHASH);
		} else if (entry == 0) {
			s4_sourcepref_t *sourcepref;
			s4_resultset_t *set;
			s4_val_t *status;
			gint i;

			sourcepref = xmms_medialib_session_get_source_preferences (session);

			status = s4_val_new_int (XMMS_MEDIALIB_ENTRY_STATUS_OK);
			set = xmms_medialib_filter (session, XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS,
			                            status, 0, sourcepref, "song_id", S4_FETCH_PARENT);
			s4_val_free (status);
			s4_sourcepref_unref (sourcepref);

			for (i = 0; i < s4_resultset_get_rowcount (set); i++) {
				const s4_result_t *res;

				res = s4_resultset_get_result (set, i, 0);
				for (; res != NULL; res = s4_result_next (res)) {
					xmms_medialib_entry_t item;
					s4_val_get_int (s4_result_get_val (res), &item);
					xmms_medialib_entry_status_set (session, item, XMMS_MEDIALIB_ENTRY_STATUS_REHASH);
				}
			}

			s4_resultset_free (set);
		} else {
			xmms_error_set (error, XMMS_ERROR_NOENT, "No such entry");
		}
	} while (!xmms_medialib_session_commit (session));
}
Exemplo n.º 15
0
static void
xmms_medialib_client_set_property_int (xmms_medialib_t *medialib,
                                       xmms_medialib_entry_t entry,
                                       const gchar *source, const gchar *key,
                                       gint32 value, xmms_error_t *error)
{
	xmms_medialib_session_t *session;

	do {
		session = xmms_medialib_session_begin (medialib);
		if (g_ascii_strcasecmp (source, "server") == 0) {
			xmms_error_set (error, XMMS_ERROR_GENERIC, "Can't write to source server!");
		} else if (xmms_medialib_check_id (session, entry)) {
			xmms_medialib_entry_property_set_int_source (session, entry, key,
			                                             value, source);
		} else {
			xmms_error_set (error, XMMS_ERROR_NOENT, "No such entry");
		}
	} while (!xmms_medialib_session_commit (session));
}
Exemplo n.º 16
0
xmms_medialib_entry_t
xmms_mock_entry (xmms_medialib_t *medialib, gint tracknr, const gchar *artist,
                 const gchar *album, const gchar *title)
{
	xmms_medialib_session_t *session;
	xmms_medialib_entry_t entry;
	xmms_error_t err;
	gchar *path;

	xmms_error_reset (&err);

	path = g_strconcat (artist, album, title, NULL);

	session = xmms_medialib_session_begin (medialib);

	entry = xmms_medialib_entry_new (session, path, &err);

	xmms_medialib_entry_property_set_int (session, entry,
	                                      XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR,
	                                      tracknr);
	xmms_medialib_entry_property_set_str (session, entry,
	                                      XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST,
	                                      artist);
	xmms_medialib_entry_property_set_str (session, entry,
	                                      XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM,
	                                      album);
	xmms_medialib_entry_property_set_str (session, entry,
	                                      XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE,
	                                      title);
	xmms_medialib_entry_property_set_int (session, entry,
	                                      XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS,
	                                      XMMS_MEDIALIB_ENTRY_STATUS_OK);

	xmms_medialib_session_commit (session);

	g_free (path);

	return entry;
}
Exemplo n.º 17
0
/**
 * Changes the URL of an entry in the medialib.
 *
 * @param medialib Medialib pointer
 * @param entry entry to modify
 * @param url URL to change to
 * @param error In case of error this will be filled.
 */
static void
xmms_medialib_client_move_entry (xmms_medialib_t *medialib,
                                 xmms_medialib_entry_t entry,
                                 const gchar *url, xmms_error_t *error)
{
	xmms_medialib_session_t *session;
	gchar *encoded;

	encoded = xmms_medialib_url_encode (url);

	do {
		session = xmms_medialib_session_begin (medialib);
		if (xmms_medialib_check_id (session, entry)) {
			xmms_medialib_entry_property_set_str_source (session, entry,
			                                             XMMS_MEDIALIB_ENTRY_PROPERTY_URL,
			                                             encoded, "server");
		} else {
			xmms_error_set (error, XMMS_ERROR_NOENT, "No such entry");
		}
	} while (!xmms_medialib_session_commit (session));

	g_free (encoded);
}
Exemplo n.º 18
0
/**
 * Unit test predicate
 */
static void
run_unit_test (xmms_medialib_t *mlib, const gchar *name, xmmsv_t *content,
               xmmsv_coll_t *coll, xmmsv_t *specification, xmmsv_t *expected,
               gint format, const gchar *datasetname)
{
	gboolean matches, ordered = FALSE;
	xmmsv_t *ret, *value;
	xmms_error_t err;
	xmms_medialib_t *medialib;
	xmms_medialib_session_t *session;

	g_debug ("Running test: %s", name);

	xmms_ipc_init ();
	xmms_config_init ("memory://");
	xmms_config_property_register ("medialib.path", "memory://", NULL, NULL);

	medialib = xmms_medialib_init ();

	populate_medialib (medialib, content);

	session = xmms_medialib_session_begin (medialib);
	ret = xmms_medialib_query (session, coll, specification, &err);
	xmms_medialib_session_commit (session);

	xmmsv_dict_get (expected, "result", &value);
	xmmsv_dict_entry_get_int (expected, "ordered", &ordered);

	if (ordered) {
		matches = xmmsv_compare (ret, value);
	} else {
		matches = xmmsv_compare_unordered (ret, value);
	}

	if (matches) {
		if (format == FORMAT_CSV) {
			g_print ("\"%s\", 1\n", name);
		} else {
			g_print ("............................................................ Success!");
			g_print ("\r%s \n", name);
		}

	} else {
		if (format == FORMAT_CSV) {
			g_print ("\"%s\", 0\n", name);
		} else {
			g_print ("............................................................ Failure!");
			g_print ("\r%s \n", name);
		}

		g_printerr ("The result: ");
		xmmsv_dump (ret);
		g_printerr ("Does not equal: ");
		xmmsv_dump (value);
	}

	xmmsv_unref (ret);

	xmms_object_unref (medialib);
	xmms_config_shutdown ();
	xmms_ipc_shutdown ();
}
Exemplo n.º 19
0
/**
 * TODO: Should check for '/' in the key, and set source if found.
 */
static void
populate_medialib (xmms_medialib_t *medialib, xmmsv_t *content)
{
	xmms_medialib_session_t *session;
	xmms_medialib_entry_t entry = 0;
	xmmsv_list_iter_t *lit;

	session = xmms_medialib_session_begin (medialib);

	xmmsv_get_list_iter (content, &lit);
	while (xmmsv_list_iter_valid (lit)) {
		xmmsv_dict_iter_t *dit;
		xmms_error_t err;
		xmmsv_t *dict;

		xmms_error_reset (&err);

		xmmsv_list_iter_entry (lit, &dict);

		if (xmmsv_dict_has_key (dict, "url")) {
			const gchar *url;
			xmmsv_dict_entry_get_string (dict, "url", &url);
			entry = xmms_medialib_entry_new (session, url, &err);
		} else {
			gchar *url;
			url = g_strdup_printf ("file://%d.mp3", entry + 1);
			entry = xmms_medialib_entry_new (session, url, &err);
			g_free (url);
		}

		xmmsv_get_dict_iter (dict, &dit);

		while (xmmsv_dict_iter_valid (dit)) {
			const gchar *key, *source;
			gchar **parts;
			xmmsv_t *container;

			xmmsv_dict_iter_pair (dit, &key, &container);

			parts = g_strsplit (key, "/", 2);

			key = (parts[1] != NULL) ? parts[1] : key;
			source = (parts[1] != NULL) ? parts[0] : NULL;

			if (xmmsv_is_type (container, XMMSV_TYPE_STRING)) {
				const gchar *value;

				xmmsv_get_string (container, &value);

				if (source != NULL) {
					xmms_medialib_entry_property_set_str_source (session, entry, key, value, source);
				} else {
					xmms_medialib_entry_property_set_str (session, entry, key, value);
				}
			} else {
				gint32 value;

				xmmsv_get_int (container, &value);

				if (source != NULL) {
					xmms_medialib_entry_property_set_int_source (session, entry, key, value, source);
				} else {
					xmms_medialib_entry_property_set_int (session, entry, key, value);
				}
			}

			g_strfreev (parts);

			xmmsv_dict_iter_next (dit);
		}

		xmmsv_list_iter_next (lit);
	}

	xmms_medialib_session_commit (session);
}
Exemplo n.º 20
0
static void *
xmms_output_filler (void *arg)
{
	xmms_output_t *output = (xmms_output_t *)arg;
	xmms_xform_t *chain = NULL;
	gboolean last_was_kill = FALSE;
	char buf[4096];
	xmms_error_t err;
	gint ret;

	xmms_error_reset (&err);

	g_mutex_lock (&output->filler_mutex);
	while (output->filler_state != FILLER_QUIT) {
		if (output->filler_state == FILLER_STOP) {
			if (chain) {
				xmms_object_unref (chain);
				chain = NULL;
			}
			xmms_ringbuf_set_eos (output->filler_buffer, TRUE);
			g_cond_wait (&output->filler_state_cond, &output->filler_mutex);
			last_was_kill = FALSE;
			continue;
		}
		if (output->filler_state == FILLER_KILL) {
			if (chain) {
				xmms_object_unref (chain);
				chain = NULL;
				output->filler_state = FILLER_RUN;
				last_was_kill = TRUE;
			} else {
				output->filler_state = FILLER_STOP;
			}
			continue;
		}
		if (output->filler_state == FILLER_SEEK) {
			if (!chain) {
				XMMS_DBG ("Seek without chain, ignoring..");
				output->filler_state = FILLER_STOP;
				continue;
			}

			ret = xmms_xform_this_seek (chain, output->filler_seek, XMMS_XFORM_SEEK_SET, &err);
			if (ret == -1) {
				XMMS_DBG ("Seeking failed: %s", xmms_error_message_get (&err));
			} else {
				XMMS_DBG ("Seek ok! %d", ret);

				output->filler_skip = output->filler_seek - ret;
				if (output->filler_skip < 0) {
					XMMS_DBG ("Seeked %d samples too far! Updating position...",
					          -output->filler_skip);

					output->filler_skip = 0;
					output->filler_seek = ret;
				}

				xmms_ringbuf_clear (output->filler_buffer);
				xmms_ringbuf_hotspot_set (output->filler_buffer, seek_done, NULL, output);
			}
			output->filler_state = FILLER_RUN;
		}

		if (!chain) {
			xmms_medialib_entry_t entry;
			xmms_output_song_changed_arg_t *hsarg;

			g_mutex_unlock (&output->filler_mutex);

			entry = xmms_playlist_current_entry (output->playlist);
			if (!entry) {
				XMMS_DBG ("No entry from playlist!");
				output->filler_state = FILLER_STOP;
				g_mutex_lock (&output->filler_mutex);
				continue;
			}

			chain = xmms_xform_chain_setup (output->medialib, entry, output->format_list, FALSE);
			if (!chain) {
				xmms_medialib_session_t *session;

				do {
					session = xmms_medialib_session_begin (output->medialib);
					if (xmms_medialib_entry_property_get_int (session, entry, XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS) == XMMS_MEDIALIB_ENTRY_STATUS_NEW) {
						xmms_medialib_entry_remove (session, entry);
					} else {
						xmms_medialib_entry_status_set (session, entry, XMMS_MEDIALIB_ENTRY_STATUS_NOT_AVAILABLE);
					}
				} while (!xmms_medialib_session_commit (session));

				if (!xmms_playlist_advance (output->playlist)) {
					XMMS_DBG ("End of playlist");
					output->filler_state = FILLER_STOP;
				}
				g_mutex_lock (&output->filler_mutex);
				continue;
			}

			hsarg = g_new0 (xmms_output_song_changed_arg_t, 1);
			hsarg->output = output;
			hsarg->chain = chain;
			hsarg->flush = last_was_kill;
			xmms_object_ref (chain);

			last_was_kill = FALSE;

			g_mutex_lock (&output->filler_mutex);
			xmms_ringbuf_hotspot_set (output->filler_buffer, song_changed, song_changed_arg_free, hsarg);
		}

		xmms_ringbuf_wait_free (output->filler_buffer, sizeof (buf), &output->filler_mutex);

		if (output->filler_state != FILLER_RUN) {
			XMMS_DBG ("State changed while waiting...");
			continue;
		}
		g_mutex_unlock (&output->filler_mutex);

		ret = xmms_xform_this_read (chain, buf, sizeof (buf), &err);

		g_mutex_lock (&output->filler_mutex);

		if (ret > 0) {
			gint skip = MIN (ret, output->toskip);

			output->toskip -= skip;
			if (ret > skip) {
				xmms_ringbuf_write_wait (output->filler_buffer,
				                         buf + skip,
				                         ret - skip,
				                         &output->filler_mutex);
			}
		} else {
			if (ret == -1) {
				/* print error */
				xmms_error_reset (&err);
			}
			xmms_object_unref (chain);
			chain = NULL;
			if (!xmms_playlist_advance (output->playlist)) {
				XMMS_DBG ("End of playlist");
				output->filler_state = FILLER_STOP;
			}
		}

	}

	if (chain)
		xmms_object_unref (chain);

	g_mutex_unlock (&output->filler_mutex);

	return NULL;
}