I attach a new patch that integrates some fixes and ideas proposed by Qball.
This patch replaces the previous one.

I have added the support of idle command in Ario (
http://ario-player.sourceforge.net/) and I have found something that looks
like a bug in MPD:
- When a song is finished, the next one is played and the 'player' event is
emitted.
- When the client sends the status command just after this event, the songid
is the new one but the 'elapsed' time is not reseted to 0.

This is problem because I have implemented the solution using a timer on
client side to compute the elapsed time but with this bug the elapsed time
continues to be incremented on a new song.

I propose a patch to MPD to fix this issue but I don't really know this part
of MPD so it may not be the best solution.

Marc


2008/11/23 Marc Pavot <[EMAIL PROTECTED]>

> Hi,
>
>
>> Thanks, I have merged your patch.  Please write a patch which adds
>> documentation for that feature to doc/protocol.xml.
>
> Done.
>
>
> I also attach a patch to libmpdclient that can be used as a basis for the
> discussion on 'idle' implementation on client side.
>
> Main points about this implementation:
> - It is designed to be integrated into client main loop. This solution has
> the advantage to avoid multithreading problems and to be well integrated
> into client applications. The disadvantage is that we have to implement
> something specific for each kind of loop. My patch comes with a generic
> callback mechanism to allow different implementations and with an
> implementation for GLib main loop.
> - The client application starts by initializing the main loop integration
> (mpd_glibInit)
> - It can then start or stop the idle mode (mpd_startIdle and mpd_stopIdle).
> In mpd_startIdle, the client specifies a callback to be called if a
> notification is received.
> - If the client application tries to send a command while it is in idle
> mode, 'noidle' is sent and the callback is called (if needed) before the
> real command.
>
> Hope this helps.
> Marc
>
diff --git a/libmpdclient.c b/libmpdclient.c
index 1c19dd8..2071af6 100644
--- a/libmpdclient.c
+++ b/libmpdclient.c
@@ -81,6 +81,17 @@
 #  define WSACleanup()          do { /* nothing */ } while (0)
 #endif
 
+static const char *const idle_names[] = {
+	"database",
+	"stored_playlist",
+	"playlist",
+	"player",
+	"mixer",
+	"output",
+	"options",
+	NULL
+};
+
 #ifdef WIN32
 static int winsock_dll_error(mpd_Connection *connection)
 {
@@ -367,6 +378,13 @@ mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
 	connection->doneListOk = 0;
 	connection->returnElement = NULL;
 	connection->request = NULL;
+#ifdef MPD_GLIB
+	connection->source_id = 0;
+#endif
+	connection->idle = 0;
+	connection->startIdle = NULL;
+	connection->stopIdle = NULL;
+	connection->notify_cb = NULL;
 
 	if (winsock_dll_error(connection))
 		return connection;
@@ -446,6 +464,9 @@ static void mpd_executeCommand(mpd_Connection * connection, char * command) {
 	char * commandPtr = command;
 	int commandLen = strlen(command);
 
+	if (connection->idle)
+		mpd_stopIdle(connection);
+
 	if(!connection->doneProcessing && !connection->commandList) {
 		strcpy(connection->errorStr,"not done processing current command");
 		connection->error = 1;
@@ -1965,3 +1986,105 @@ void mpd_sendPlaylistDeleteCommand(mpd_Connection *connection,
 	free(sPlaylist);
 	free(string);
 }
+
+static void mpd_readChanges(mpd_Connection *connection)
+{
+	unsigned i;
+	unsigned flags = 0;
+	mpd_ReturnElement *re;
+
+	if (!connection->returnElement) mpd_getNextReturnElement(connection);
+
+	while (connection->returnElement) {
+		re = connection->returnElement;
+		if (re->name &&!strncmp (re->name, "changed", strlen ("changed"))) {
+			for (i = 0; idle_names[i]; ++i) {
+				if (!strcmp (re->value, idle_names[i])) {
+					flags |= (1 << i);
+				}
+			}
+		}
+		mpd_getNextReturnElement(connection);
+	}
+
+	/* Notifiy application */
+	if (connection->notify_cb && flags)
+		connection->notify_cb (connection, flags, connection->userdata);
+}
+
+void mpd_startIdle(mpd_Connection *connection, mpd_NotificationCb notify_cb, void *userdata)
+{
+        if (connection->idle)
+                return;
+
+	if (connection->startIdle)
+		connection->startIdle(connection);
+
+	mpd_executeCommand(connection, "idle\n");
+	connection->idle = 1;
+	connection->notify_cb = notify_cb;
+	connection->userdata = userdata;
+}
+
+void mpd_stopIdle(mpd_Connection *connection)
+{
+	if (connection->stopIdle)
+		connection->stopIdle(connection);
+
+	connection->idle = 0;
+	connection->notify_cb = NULL;
+	connection->doneProcessing = 1;
+	mpd_executeCommand(connection, "noidle\n");
+	mpd_readChanges(connection);
+}
+
+#ifdef MPD_GLIB
+static gboolean mpd_glibReadCb (GIOChannel *iochan, GIOCondition cond, gpointer data)
+{
+	mpd_Connection *connection = data;
+
+	if (!connection->idle) {
+		connection->source_id = 0;
+		return FALSE;
+	}
+
+	if ((cond & G_IO_IN)) {
+	     connection->idle = 0;
+	     if (connection->source_id) {
+		     g_source_remove (connection->source_id);
+		     connection->source_id = 0;
+	     }
+	     mpd_readChanges(connection);
+	}
+
+	return TRUE;
+}
+
+static void mpd_glibStartIdle(mpd_Connection *connection)
+{
+	static GIOChannel* iochan = NULL;
+
+        if (!iochan)
+	        iochan = g_io_channel_unix_new (connection->sock);
+
+        connection->source_id = g_io_add_watch (iochan,
+					        G_IO_IN | G_IO_ERR | G_IO_HUP,
+					        mpd_glibReadCb,
+					        connection);
+}
+
+static void mpd_glibStopIdle(mpd_Connection *connection)
+{
+	if (connection->source_id) {
+		g_source_remove (connection->source_id);
+		connection->source_id = 0;
+	}
+}
+
+void mpd_glibInit(mpd_Connection *connection)
+{
+	connection->startIdle = mpd_glibStartIdle;
+	connection->stopIdle = mpd_glibStopIdle;
+}
+#endif
+
diff --git a/libmpdclient.h b/libmpdclient.h
index 111d52a..cec0379 100644
--- a/libmpdclient.h
+++ b/libmpdclient.h
@@ -39,6 +39,10 @@
 
 #include <sys/time.h>
 #include <stdarg.h>
+#ifdef MPD_GLIB
+#include <glib.h>
+#endif
+
 #define MPD_BUFFER_MAX_LENGTH	50000
 #define MPD_ERRORSTR_MAX_LENGTH	1000
 #define MPD_WELCOME_MESSAGE	"OK MPD "
@@ -101,6 +105,30 @@ typedef struct _mpd_ReturnElement {
 	char * value;
 } mpd_ReturnElement;
 
+enum {
+	/** song database has been updated*/
+	IDLE_DATABASE = 0x1,
+
+	/** a stored playlist has been modified, created, deleted or
+	    renamed */
+	IDLE_STORED_PLAYLIST = 0x2,
+
+	/** the current playlist has been modified */
+	IDLE_PLAYLIST = 0x4,
+
+	/** the player state has changed: play, stop, pause, seek, ... */
+	IDLE_PLAYER = 0x8,
+
+	/** the volume has been modified */
+	IDLE_MIXER = 0x10,
+
+	/** an audio output device has been enabled or disabled */
+	IDLE_OUTPUT = 0x20,
+
+	/** options have changed: crossfade, random, repeat, ... */
+	IDLE_OPTIONS = 0x40,
+};
+
 /* mpd_Connection
  * holds info about connection to mpd
  * use error, and errorStr to detect errors
@@ -126,8 +154,18 @@ typedef struct _mpd_Connection {
 	mpd_ReturnElement * returnElement;
 	struct timeval timeout;
 	char *request;
+	int idle;
+	void (*notify_cb) (struct _mpd_Connection *connection, unsigned flags, void *userdata);
+	void (*startIdle) (struct _mpd_Connection *connection);
+	void (*stopIdle) (struct _mpd_Connection *connection);
+	void *userdata;
+#ifdef MPD_GLIB
+        int source_id;
+#endif
 } mpd_Connection;
 
+typedef void (*mpd_NotificationCb) (mpd_Connection *connection, unsigned flags, void *userdata);
+
 /* mpd_newConnection
  * use this to open a new connection
  * you should use mpd_closeConnection, when your done with the connection,
@@ -663,6 +701,15 @@ void mpd_sendPlaylistMoveCommand(mpd_Connection *connection,
 
 void mpd_sendPlaylistDeleteCommand(mpd_Connection *connection,
                                    char *playlist, int pos);
+
+void mpd_startIdle(mpd_Connection *connection, mpd_NotificationCb notify_cb, void *userdata);
+
+void mpd_stopIdle(mpd_Connection *connection);
+
+#ifdef MPD_GLIB
+void mpd_glibInit(mpd_Connection *connection);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/playlist.c b/src/playlist.c
index 8581755..4bc6013 100644
--- a/src/playlist.c
+++ b/src/playlist.c
@@ -488,6 +488,7 @@ static void syncPlaylistWithQueue(void)
 	if (pc.next_song == NULL && playlist.queued != -1) {
 		playlist.current = playlist.queued;
 		playlist.queued = -1;
+                pc.elapsed_time = 0;
 
 		idle_add(IDLE_PLAYER);
 	}
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Musicpd-dev-team mailing list
Musicpd-dev-team@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team

Reply via email to