X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fmpdclient.c;h=5903f1430fb3c9288c1c99d1fe208db07990e76f;hb=9eedd15314515b6d9f51aa64926c14d8bda3a99a;hp=13937516897838b43b2f883758af8d966562d272;hpb=91d04f21397cd391e13b583b2e500e8dbcfd038e;p=ncmpc.git diff --git a/src/mpdclient.c b/src/mpdclient.c index 1393751..5903f14 100644 --- a/src/mpdclient.c +++ b/src/mpdclient.c @@ -24,10 +24,48 @@ #include "gidle.h" #include "charset.h" +#ifdef ENABLE_ASYNC_CONNECT +#include "aconnect.h" +#endif + #include #include +static gboolean +mpdclient_enter_idle_callback(gpointer user_data) +{ + struct mpdclient *c = user_data; + assert(c->enter_idle_source_id != 0); + assert(c->source != NULL); + assert(!c->idle); + + c->enter_idle_source_id = 0; + c->idle = mpd_glib_enter(c->source); + return false; +} + +static void +mpdclient_schedule_enter_idle(struct mpdclient *c) +{ + assert(c != NULL); + assert(c->source != NULL); + + if (c->enter_idle_source_id == 0) + /* automatically re-enter MPD "idle" mode */ + c->enter_idle_source_id = + g_idle_add(mpdclient_enter_idle_callback, c); +} + +static void +mpdclient_cancel_enter_idle(struct mpdclient *c) +{ + if (c->enter_idle_source_id != 0) { + g_source_remove(c->enter_idle_source_id); + c->enter_idle_source_id = 0; + } +} + static void mpdclient_invoke_error_callback(enum mpd_error error, const char *message) @@ -43,6 +81,21 @@ mpdclient_invoke_error_callback(enum mpd_error error, g_free(allocated); } +static void +mpdclient_invoke_error_callback1(struct mpdclient *c) +{ + assert(c != NULL); + assert(c->connection != NULL); + + struct mpd_connection *connection = c->connection; + + enum mpd_error error = mpd_connection_get_error(connection); + assert(error != MPD_ERROR_SUCCESS); + + mpdclient_invoke_error_callback(error, + mpd_connection_get_error_message(connection)); +} + static void mpdclient_gidle_callback(enum mpd_error error, gcc_unused enum mpd_server_error server_error, @@ -69,7 +122,8 @@ mpdclient_gidle_callback(enum mpd_error error, c->events = 0; - mpdclient_put_connection(c); + if (c->source != NULL) + mpdclient_schedule_enter_idle(c); } /****************************************************************************/ @@ -91,19 +145,37 @@ mpdclient_handle_error(struct mpdclient *c) mpdclient_invoke_error_callback(error, mpd_connection_get_error_message(c->connection)); - if (!mpd_connection_clear_error(c->connection)) + if (!mpd_connection_clear_error(c->connection)) { mpdclient_disconnect(c); + mpdclient_lost_callback(); + } return false; } struct mpdclient * -mpdclient_new(void) +mpdclient_new(const gchar *host, unsigned port, + unsigned timeout_ms, const gchar *password) { struct mpdclient *c = g_new0(struct mpdclient, 1); + +#ifdef ENABLE_ASYNC_CONNECT + c->settings = mpd_settings_new(host, port, timeout_ms, + NULL, NULL); + if (c->settings == NULL) + g_error("Out of memory"); +#else + c->host = host; + c->port = port; +#endif + + c->timeout_ms = timeout_ms; + c->password = password; + playlist_init(&c->playlist); c->volume = -1; c->events = 0; + c->playing = false; return c; } @@ -115,6 +187,10 @@ mpdclient_free(struct mpdclient *c) mpdclient_playlist_free(&c->playlist); +#ifdef ENABLE_ASYNC_CONNECT + mpd_settings_free(c->settings); +#endif + g_free(c); } @@ -128,11 +204,21 @@ mpdclient_status_free(struct mpdclient *c) c->status = NULL; c->volume = -1; + c->playing = false; } void mpdclient_disconnect(struct mpdclient *c) { +#ifdef ENABLE_ASYNC_CONNECT + if (c->async_connect != NULL) { + aconnect_cancel(c->async_connect); + c->async_connect = NULL; + } +#endif + + mpdclient_cancel_enter_idle(c); + if (c->source != NULL) { mpd_glib_free(c->source); c->source = NULL; @@ -156,43 +242,95 @@ mpdclient_disconnect(struct mpdclient *c) c->events |= MPD_IDLE_ALL; } -bool -mpdclient_connect(struct mpdclient *c, - const gchar *host, - gint port, - unsigned timeout_ms, - const gchar *password) +static bool +mpdclient_connected(struct mpdclient *c, + struct mpd_connection *connection) { - /* close any open connection */ - if (c->connection) - mpdclient_disconnect(c); - - /* connect to MPD */ - c->connection = mpd_connection_new(host, port, timeout_ms); - if (c->connection == NULL) - g_error("Out of memory"); + c->connection = connection; - if (mpd_connection_get_error(c->connection) != MPD_ERROR_SUCCESS) { - mpdclient_handle_error(c); + if (mpd_connection_get_error(connection) != MPD_ERROR_SUCCESS) { + mpdclient_invoke_error_callback1(c); mpdclient_disconnect(c); + mpdclient_failed_callback(); return false; } +#ifdef ENABLE_ASYNC_CONNECT + if (c->timeout_ms > 0) + mpd_connection_set_timeout(connection, c->timeout_ms); +#endif + /* send password */ - if (password != NULL && !mpd_run_password(c->connection, password)) { - mpdclient_handle_error(c); + if (c->password != NULL && + !mpd_run_password(connection, c->password)) { + mpdclient_invoke_error_callback1(c); mpdclient_disconnect(c); + mpdclient_failed_callback(); return false; } - c->source = mpd_glib_new(c->connection, + c->source = mpd_glib_new(connection, mpdclient_gidle_callback, c); + mpdclient_schedule_enter_idle(c); ++c->connection_id; + mpdclient_connected_callback(); return true; } +#ifdef ENABLE_ASYNC_CONNECT + +static void +mpdclient_connect_success(struct mpd_connection *connection, void *ctx) +{ + struct mpdclient *c = ctx; + assert(c->async_connect != NULL); + c->async_connect = NULL; + + mpdclient_connected(c, connection); +} + +static void +mpdclient_connect_error(const char *message, void *ctx) +{ + struct mpdclient *c = ctx; + assert(c->async_connect != NULL); + c->async_connect = NULL; + + mpdclient_error_callback(message); + mpdclient_failed_callback(); +} + +static const struct aconnect_handler mpdclient_connect_handler = { + .success = mpdclient_connect_success, + .error = mpdclient_connect_error, +}; + +#endif + +void +mpdclient_connect(struct mpdclient *c) +{ + /* close any open connection */ + mpdclient_disconnect(c); + +#ifdef ENABLE_ASYNC_CONNECT + aconnect_start(&c->async_connect, + mpd_settings_get_host(c->settings), + mpd_settings_get_port(c->settings), + &mpdclient_connect_handler, c); +#else + /* connect to MPD */ + struct mpd_connection *connection = + mpd_connection_new(c->host, c->port, c->timeout_ms); + if (connection == NULL) + g_error("Out of memory"); + + mpdclient_connected(c, connection); +#endif +} + bool mpdclient_update(struct mpdclient *c) { @@ -210,6 +348,7 @@ mpdclient_update(struct mpdclient *c) return mpdclient_handle_error(c); c->volume = mpd_status_get_volume(c->status); + c->playing = mpd_status_get_state(c->status) == MPD_STATE_PLAY; /* check if the playlist needs an update */ if (c->playlist.version != mpd_status_get_queue_version(c->status)) { @@ -238,21 +377,13 @@ mpdclient_get_connection(struct mpdclient *c) if (c->source != NULL && c->idle) { c->idle = false; mpd_glib_leave(c->source); + + mpdclient_schedule_enter_idle(c); } return c->connection; } -void -mpdclient_put_connection(struct mpdclient *c) -{ - assert(c->source == NULL || c->connection != NULL); - - if (c->source != NULL && !c->idle) { - c->idle = mpd_glib_enter(c->source); - } -} - static struct mpd_status * mpdclient_recv_status(struct mpdclient *c) { @@ -352,39 +483,26 @@ mpdclient_cmd_volume(struct mpdclient *c, gint value) bool mpdclient_cmd_volume_up(struct mpdclient *c) { + if (c->volume < 0 || c->volume >= 100) + return true; + struct mpd_connection *connection = mpdclient_get_connection(c); if (connection == NULL) return false; - if (c->status == NULL || - mpd_status_get_volume(c->status) == -1) - return true; - - if (c->volume < 0) - c->volume = mpd_status_get_volume(c->status); - - if (c->volume >= 100) - return true; - return mpdclient_cmd_volume(c, ++c->volume); } bool mpdclient_cmd_volume_down(struct mpdclient *c) { + if (c->volume <= 0) + return true; + struct mpd_connection *connection = mpdclient_get_connection(c); if (connection == NULL) return false; - if (c->status == NULL || mpd_status_get_volume(c->status) < 0) - return true; - - if (c->volume < 0) - c->volume = mpd_status_get_volume(c->status); - - if (c->volume <= 0) - return true; - return mpdclient_cmd_volume(c, --c->volume); }