X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fmpdclient.c;h=ffa1a5d84408e86757b82d2dbde1617dbf07c583;hb=efae3a330fbfe9b85690b0b01a5b640e95613a6e;hp=f500c9adb689de508b7de4673f73dbe141b72396;hpb=c68131c93b7682e1162b9391e120dbce23bfe554;p=ncmpc.git diff --git a/src/mpdclient.c b/src/mpdclient.c index f500c9a..ffa1a5d 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,16 +145,60 @@ 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; } +#ifdef ENABLE_ASYNC_CONNECT +#ifndef WIN32 + +static bool +is_local_socket(const char *host) +{ + return *host == '/' || *host == '@'; +} + +static bool +settings_is_local_socket(const struct mpd_settings *settings) +{ + const char *host = mpd_settings_get_host(settings); + return host != NULL && is_local_socket(host); +} + +#endif +#endif + 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"); + +#ifndef WIN32 + c->settings2 = host == NULL && port == 0 && + settings_is_local_socket(c->settings) + ? mpd_settings_new(host, 6600, timeout_ms, NULL, NULL) + : NULL; +#endif + +#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; @@ -116,9 +214,56 @@ mpdclient_free(struct mpdclient *c) mpdclient_playlist_free(&c->playlist); +#ifdef ENABLE_ASYNC_CONNECT + mpd_settings_free(c->settings); + +#ifndef WIN32 + if (c->settings2 != NULL) + mpd_settings_free(c->settings2); +#endif +#endif + g_free(c); } +static char * +settings_name(const struct mpd_settings *settings) +{ + assert(settings != NULL); + + const char *host = mpd_settings_get_host(settings); + if (host == NULL) + host = "unknown"; + + if (host[0] == '/') + return g_strdup(host); + + unsigned port = mpd_settings_get_port(settings); + if (port == 0 || port == 6600) + return g_strdup(host); + + return g_strdup_printf("%s:%u", host, port); +} + +char * +mpdclient_settings_name(const struct mpdclient *c) +{ + assert(c != NULL); + +#ifdef ENABLE_ASYNC_CONNECT + return settings_name(c->settings); +#else + struct mpd_settings *settings = + mpd_settings_new(c->host, c->port, 0, NULL, NULL); + if (settings == NULL) + return g_strdup("unknown"); + + char *name = settings_name(settings); + mpd_settings_free(settings); + return name; +#endif +} + static void mpdclient_status_free(struct mpdclient *c) { @@ -135,6 +280,15 @@ mpdclient_status_free(struct mpdclient *c) 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; @@ -158,46 +312,117 @@ 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 */ - 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_aconnect_start(struct mpdclient *c, + const struct mpd_settings *settings); + +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; + +#ifndef WIN32 + if (!c->connecting2 && c->settings2 != NULL) { + c->connecting2 = true; + mpdclient_aconnect_start(c, c->settings2); + return; + } +#endif + + mpdclient_error_callback(message); + mpdclient_failed_callback(); +} + +static const struct aconnect_handler mpdclient_connect_handler = { + .success = mpdclient_connect_success, + .error = mpdclient_connect_error, +}; + +static void +mpdclient_aconnect_start(struct mpdclient *c, + const struct mpd_settings *settings) +{ + aconnect_start(&c->async_connect, + mpd_settings_get_host(settings), + mpd_settings_get_port(settings), + &mpdclient_connect_handler, c); +} + +#endif + +void +mpdclient_connect(struct mpdclient *c) +{ + /* close any open connection */ + mpdclient_disconnect(c); + +#ifdef ENABLE_ASYNC_CONNECT +#ifndef WIN32 + c->connecting2 = false; +#endif + mpdclient_aconnect_start(c, c->settings); +#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) { @@ -244,21 +469,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) { @@ -358,39 +575,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); }