aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2009-02-28 20:43:23 +0100
committerMax Kellermann <max@duempel.org>2009-02-28 20:43:23 +0100
commitec4fd9fd88a10bfc88154e8e6791d5d69858a2e5 (patch)
treec98fe447adcafe85ba9ee94d93d98377f9ffdaeb
parenta5c09c91c414ba08d915331797e717334ac06456 (diff)
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.
-rw-r--r--src/output_all.c10
-rw-r--r--src/output_command.c1
-rw-r--r--src/output_control.c22
-rw-r--r--src/output_init.c2
-rw-r--r--src/output_internal.h7
-rw-r--r--src/output_thread.c9
6 files changed, 35 insertions, 16 deletions
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 <assert.h>
#include <stdlib.h>
+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);