From 5ad2d293890a7d197532e85fe0eacf55550ea0a1 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 2 Apr 2026 10:47:53 -0400 Subject: [PATCH] Test with poll Signed-off-by: Hugo Villeneuve --- src/main.c | 122 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 28 deletions(-) diff --git a/src/main.c b/src/main.c index 08dc18d..c65358c 100644 --- a/src/main.c +++ b/src/main.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -22,6 +23,8 @@ #define URI_PREFIX_HTTP "http://" #define URI_PREFIX_HTTPS "https://" +#define MPDSTREAM_POLL_TIMEOUT 10000 // Set to 3000?????????? + extern struct options_t options; static enum mpd_state last_state; @@ -188,6 +191,78 @@ end: return 0; } +void mpdstream_monitor_loop(struct pollfd *pfd) +{ + int rc; + + while (true) { + bool recv_idle = false; + + (void) mpdstream_monitor_status(); + + /* + * Configure idle event(s): + * MPD_IDLE_PLAYER: state has changed: play, stop, pause, seek, etc + */ + rc = mpd_send_idle_mask(mpdc, MPD_IDLE_PLAYER); + if (!rc) { + log_warn("Unable to set idle mask\n"); + continue; /* Or abort/break? */ + } + + /* Wait for event, or timeout. */ + rc = poll(pfd, 1, MPDSTREAM_POLL_TIMEOUT); + if (rc < 0) { + if (errno == EAGAIN) { + log_warn("poll returned EAGAIN\n"); + } else if (errno == EINTR) { + /* Signal occurred, continue... */ + log_warn("poll returned EINTR\n"); + } else { + log_err("poll error: %s\n", strerror(errno)); + // return -1; + } + } else if (rc == 0) { + /* Timeout. */ + log_debug("poll TIMEOUT\n"); + + /* + * Tells MPD to leave the "idle" mode. MPD will then + * respond with a list of events which have occurred + * (which may be empty). + */ + mpd_send_noidle(mpdc); + recv_idle = true; + } else { + if (pfd->revents & POLLIN) { + /* Data received. */ + recv_idle = true; + } else if (pfd->revents & (POLLHUP | POLLERR | POLLNVAL)) { + // The connection is broken + log_err("MPD connection lost or error occurred\n"); + return; + } + } + + if (recv_idle) { + enum mpd_idle events; + + /* + * Waits until MPD sends the list of idle events + * and returns it in a bit mask. + */ + events = mpd_recv_idle(mpdc, 0); + if (events == 0) { + /* Maybe empty in case of valid timeout. */ + (void) mpd_check_for_error(); + log_debug("Empty idle event\n"); + } else if (events & MPD_IDLE_PLAYER) { + log_debug("MPD_IDLE_PLAYER idle event\n"); + } + } + } +} + int main(int argc, char **argv) { @@ -199,42 +274,33 @@ main(int argc, char **argv) if (rc) exit(EXIT_FAILURE); - mpdc = mpd_connection_new(options.host, options.port, 0); - if (mpdc == NULL) { - log_err("MPD connection error: out of memory\n"); - exit(EXIT_FAILURE); - } + while (true) { + struct pollfd pfd; - if (mpd_check_for_error()) - exit(EXIT_FAILURE); + mpdc = mpd_connection_new(options.host, options.port, 0); + if (mpdc == NULL) { + log_err("MPD connection error: out of memory\n"); + exit(EXIT_FAILURE); + } - log_debug("Waiting for events...\n"); + if (mpd_check_for_error()) + exit(EXIT_FAILURE); - is_stream = false; - song_id = -1; - last_state = -1; + pfd.fd = mpd_connection_get_fd(mpdc); + pfd.events = POLLIN; - while (true) { - enum mpd_idle mask; + is_stream = false; + song_id = -1; + last_state = -1; - (void) mpdstream_monitor_status(); + log_debug("Waiting for events...\n"); - /* - * Wait for specified event(s): - * MPD_IDLE_PLAYER: state has changed: play, stop, pause, seek, etc - */ - mask = mpd_run_idle_mask(mpdc, MPD_IDLE_PLAYER | MPD_IDLE_QUEUE); - if (mask == 0) { - (void) mpd_check_for_error(); - log_warn("Empty idle event"); - continue; /* Or abort/break? */ - } else if (mask &= ~MPD_IDLE_QUEUE) { - log_debug("MPD_IDLE_QUEUE idle event"); - continue; - } + /* Should only return in case of connection error(s). */ + mpdstream_monitor_loop(&pfd); + + mpd_connection_free(mpdc); } - mpd_connection_free(mpdc); closelog(); exit(EXIT_SUCCESS); -- 2.47.3