Hi,

I propose you a patch that improves different aspects of idle command:
- It adds a new 'elapsed' event to notify clients when the elapsed time has
changed (in absolute value in second)
- It adds the possibility to choose which notification you want to receive.
The idle command can now take no argument (same behavior as before) or
several arguments.
For example if a client uses command 'idle mixer elapsed', it will only
receive notifications when the volume changed or when the elapsed time
changed.
- And last, with this patch MPD doesn't leave idle mode anymore when a
notification has been done. It means that idle mode will continue until
'noidle' command is sent. I think this will easy client implementation of
idle command and reduce a lot the amount of useless traffic. Please tell me
if you see a major drawback with this behavior.

Marc
diff --git a/src/client.c b/src/client.c
index ee98464..224dfff 100644
--- a/src/client.c
+++ b/src/client.c
@@ -91,6 +91,9 @@ struct client {
 	/** idle flags pending on this client, to be sent as soon as
 	    the client enters "idle" */
 	unsigned idle_flags;
+
+	/** idle flags that the client wants to receive */
+	unsigned idle_subscriptions;
 };
 
 static LIST_HEAD(clients);
@@ -766,16 +769,6 @@ mpd_fprintf void client_printf(struct client *client, const char *fmt, ...)
 	va_end(args);
 }
 
-static const char *const idle_names[] = {
-	"database",
-	"stored_playlist",
-	"playlist",
-	"player",
-	"mixer",
-	"output",
-	"options",
-};
-
 /**
  * Send "idle" response to this client.
  */
@@ -783,23 +776,21 @@ static void
 client_idle_notify(struct client *client)
 {
 	unsigned flags, i;
+        const char *const* idle_names;
 
 	assert(client->idle_waiting);
 	assert(client->idle_flags != 0);
 
 	flags = client->idle_flags;
 	client->idle_flags = 0;
-	client->idle_waiting = false;
-
-	for (i = 0; i < sizeof(idle_names) / sizeof(idle_names[0]); ++i) {
-		assert(idle_names[i] != NULL);
 
-		if (flags & (1 << i))
+        idle_names = idle_get_names();
+	for (i = 0; idle_names[i]; ++i) {
+		if (flags & (1 << i) & client->idle_subscriptions)
 			client_printf(client, "changed: %s\n",
 				      idle_names[i]);
 	}
 
-	client_puts(client, "OK\n");
 	client->lastTime = time(NULL);
 }
 
@@ -821,11 +812,13 @@ void client_manager_idle_add(unsigned flags)
 	}
 }
 
-bool client_idle_wait(struct client *client)
+bool client_idle_wait(struct client *client,
+                      unsigned flags)
 {
 	assert(!client->idle_waiting);
 
 	client->idle_waiting = true;
+	client->idle_subscriptions = flags;
 
 	if (client->idle_flags != 0) {
 		client_idle_notify(client);
diff --git a/src/client.h b/src/client.h
index e6661e2..9c70318 100644
--- a/src/client.h
+++ b/src/client.h
@@ -78,6 +78,6 @@ void client_manager_idle_add(unsigned flags);
  * sent immediately and "true" is returned".  If no, it puts the
  * client into waiting mode and returns false.
  */
-bool client_idle_wait(struct client *client);
+bool client_idle_wait(struct client *client, unsigned flags);
 
 #endif
diff --git a/src/command.c b/src/command.c
index dc71f1d..7a7cdfb 100644
--- a/src/command.c
+++ b/src/command.c
@@ -39,6 +39,7 @@
 #include "tag_print.h"
 #include "path.h"
 #include "os_compat.h"
+#include "idle.h"
 
 #define COMMAND_STATUS_VOLUME           "volume"
 #define COMMAND_STATUS_STATE            "state"
@@ -1253,8 +1254,31 @@ static enum command_return
 handle_idle(struct client *client,
 	    mpd_unused int argc, mpd_unused char *argv[])
 {
+        unsigned flags = 0, j;
+        int i;
+        const char *const* idle_names;
+
+        idle_names = idle_get_names();
+        for (i = 1; i < argc; ++i) {
+                if (!argv[i])
+                        continue;
+
+                for (j = 0; idle_names[j]; ++j) {
+                        if (!strcasecmp(argv[i], idle_names[j])) {
+                                flags |= (1 << j);
+                        }
+                }
+        }
+
+        /* No argument means that the client wants to receive everything */
+        if (flags == 0) {
+                for (j = 0; idle_names[j]; ++j) {
+                        flags |= (1 << j);
+                }
+        }
+
 	/* enable "idle" mode on this client */
-	client_idle_wait(client);
+	client_idle_wait(client, flags);
 
 	/* return value is "1" so the caller won't print "OK" */
 	return 1;
@@ -1280,7 +1304,7 @@ static const struct command commands[] = {
 	{ "disableoutput", PERMISSION_ADMIN, 1, 1, handle_disableoutput },
 	{ "enableoutput", PERMISSION_ADMIN, 1, 1, handle_enableoutput },
 	{ "find", PERMISSION_READ, 2, -1, handle_find },
-	{ "idle", PERMISSION_READ, 0, 0, handle_idle },
+	{ "idle", PERMISSION_READ, 0, -1, handle_idle },
 	{ "kill", PERMISSION_ADMIN, -1, -1, handle_kill },
 	{ "list", PERMISSION_READ, 1, -1, handle_list },
 	{ "listall", PERMISSION_READ, 0, 1, handle_listall },
diff --git a/src/idle.c b/src/idle.c
index c779d0a..477a676 100644
--- a/src/idle.c
+++ b/src/idle.c
@@ -30,6 +30,24 @@
 static unsigned idle_flags;
 static pthread_mutex_t idle_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+static const char *const idle_names[] = {
+	"database",
+	"stored_playlist",
+	"playlist",
+	"player",
+	"mixer",
+	"output",
+	"options",
+	"elapsed",
+        NULL
+};
+
+const char*const*
+idle_get_names(void)
+{
+        return idle_names;
+}
+
 void
 idle_add(unsigned flags)
 {
diff --git a/src/idle.h b/src/idle.h
index 69756b1..1f8c235 100644
--- a/src/idle.h
+++ b/src/idle.h
@@ -46,9 +46,18 @@ enum {
 
 	/** options have changed: crossfade, random, repeat, ... */
 	IDLE_OPTIONS = 0x40,
+
+	/** elapsed time has changed */
+	IDLE_ELAPSED = 0x80,
 };
 
 /**
+ * Get idle names
+ */
+const char*const*
+idle_get_names(void);
+
+/**
  * Adds idle flag (with bitwise "or") and queues notifications to all
  * clients.
  */
diff --git a/src/player_thread.c b/src/player_thread.c
index ac060dd..a28fd46 100644
--- a/src/player_thread.c
+++ b/src/player_thread.c
@@ -133,8 +133,10 @@ static bool player_seek_decoder(struct player *player)
 		where = 0.0;
 
 	ret = dc_seek(&pc.notify, where);
-	if (ret)
+	if (ret) {
 		pc.elapsed_time = where;
+                idle_add(IDLE_ELAPSED);
+        }
 
 	player_command_finished();
 
@@ -221,9 +223,16 @@ static int
 play_chunk(struct song *song, struct music_chunk *chunk,
 	   const struct audio_format *format, double sizeToTime)
 {
+        int before, after;
+
+        before = getPlayerElapsedTime();
 	pc.elapsed_time = chunk->times;
+        after = getPlayerElapsedTime();
 	pc.bit_rate = chunk->bit_rate;
 
+        if (before != after)
+                idle_add(IDLE_ELAPSED);
+
 	if (chunk->tag != NULL) {
 		sendMetadataToAudioDevice(chunk->tag);
 
@@ -285,6 +294,8 @@ static void do_play(void)
 	}
 
 	pc.elapsed_time = 0;
+        idle_add(IDLE_ELAPSED);
+
 	pc.state = PLAYER_STATE_PLAY;
 	player_command_finished();
 
-------------------------------------------------------------------------
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