From ec4fd9fd88a10bfc88154e8e6791d5d69858a2e5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 28 Feb 2009 20:43:23 +0100 Subject: output: use GTimer instead of time_t for reopen after failure time() is not a monotonic timer, and MPD might get confused by clock skews. clock_gettime() provides a monotonic clock, but is not portable to non-POSIX systems (i.e. Windows). This patch uses GLib's GTimer API, which aims to be portable. --- src/output_all.c | 10 ++++++++-- src/output_command.c | 1 - src/output_control.c | 22 ++++++++++++++++++++-- src/output_init.c | 2 +- src/output_internal.h | 7 ++++--- src/output_thread.c | 9 ++------- 6 files changed, 35 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/output_all.c b/src/output_all.c index c90a875d..953a11bd 100644 --- a/src/output_all.c +++ b/src/output_all.c @@ -162,8 +162,14 @@ static void audio_output_wait_all(void) static void audio_output_all_reset_reopen(void) { - for (unsigned i = 0; i < num_audio_outputs; ++i) - audio_outputs[i].reopen_after = 0; + for (unsigned i = 0; i < num_audio_outputs; ++i) { + struct audio_output *ao = &audio_outputs[i]; + + if (!ao->open && ao->fail_timer != NULL) { + g_timer_destroy(ao->fail_timer); + ao->fail_timer = NULL; + } + } } static void diff --git a/src/output_command.c b/src/output_command.c index 4d6515af..2e33ca8b 100644 --- a/src/output_command.c +++ b/src/output_command.c @@ -38,7 +38,6 @@ audio_output_enable_index(unsigned idx) ao = audio_output_get(idx); - ao->reopen_after = 0; ao->enabled = true; idle_add(IDLE_OUTPUT); diff --git a/src/output_control.c b/src/output_control.c index 5516af60..c2b7c56d 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -24,6 +24,12 @@ #include #include +enum { + /** after a failure, wait this number of seconds before + automatically reopening the device */ + REOPEN_AFTER = 10, +}; + struct notify audio_output_client_notify; static void ao_command_wait(struct audio_output *ao) @@ -53,7 +59,10 @@ bool audio_output_open(struct audio_output *ao, const struct audio_format *audio_format) { - ao->reopen_after = 0; + if (ao->fail_timer != NULL) { + g_timer_destroy(ao->fail_timer); + ao->fail_timer = NULL; + } if (ao->open && audio_format_equals(audio_format, &ao->in_audio_format)) { @@ -90,7 +99,8 @@ audio_output_update(struct audio_output *ao, const struct audio_format *audio_format) { if (ao->enabled) { - if (ao->reopen_after == 0 || time(NULL) > ao->reopen_after) + if (ao->fail_timer == NULL || + g_timer_elapsed(ao->fail_timer, NULL) > REOPEN_AFTER) audio_output_open(ao, audio_format); } else if (audio_output_is_open(ao)) audio_output_close(ao); @@ -127,14 +137,22 @@ void audio_output_cancel(struct audio_output *ao) void audio_output_close(struct audio_output *ao) { + assert(!ao->open || ao->fail_timer == NULL); + if (ao->open) ao_command(ao, AO_COMMAND_CLOSE); + else if (ao->fail_timer != NULL) { + g_timer_destroy(ao->fail_timer); + ao->fail_timer = NULL; + } } void audio_output_finish(struct audio_output *ao) { audio_output_close(ao); + assert(ao->fail_timer == NULL); + if (ao->thread != NULL) { ao_command(ao, AO_COMMAND_KILL); g_thread_join(ao->thread); diff --git a/src/output_init.c b/src/output_init.c index 962a805a..a007dbd1 100644 --- a/src/output_init.c +++ b/src/output_init.c @@ -93,7 +93,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param) ao->plugin = plugin; ao->enabled = config_get_block_bool(param, "enabled", true); ao->open = false; - ao->reopen_after = 0; + ao->fail_timer = NULL; pcm_convert_init(&ao->convert_state); diff --git a/src/output_internal.h b/src/output_internal.h index c5ed7652..498f45d0 100644 --- a/src/output_internal.h +++ b/src/output_internal.h @@ -65,10 +65,11 @@ struct audio_output { bool open; /** - * If not zero, the device has failed, and should not be - * reopened automatically before this time stamp. + * If not NULL, the device has failed, and this timer is used + * to estimate how long it should stay disabled (unless + * explicitly reopened with "play"). */ - time_t reopen_after; + GTimer *fail_timer; /** * The audio_format in which audio data is received from the diff --git a/src/output_thread.c b/src/output_thread.c index b5a4c611..c4d5b16e 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -29,12 +29,6 @@ #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "output" -enum { - /** after a failure, wait this number of seconds before - automatically reopening the device */ - REOPEN_AFTER = 10, -}; - static void ao_command_finished(struct audio_output *ao) { assert(ao->command != AO_COMMAND_NONE); @@ -129,6 +123,7 @@ static gpointer audio_output_task(gpointer arg) case AO_COMMAND_OPEN: assert(!ao->open); + assert(ao->fail_timer == NULL); error = NULL; ret = ao_plugin_open(ao->plugin, ao->data, @@ -145,7 +140,7 @@ static gpointer audio_output_task(gpointer arg) error->message); g_error_free(error); - ao->reopen_after = time(NULL) + REOPEN_AFTER; + ao->fail_timer = g_timer_new(); } ao_command_finished(ao); -- cgit v1.2.3