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.
This commit is contained in:
parent
a5c09c91c4
commit
ec4fd9fd88
@ -162,8 +162,14 @@ static void audio_output_wait_all(void)
|
|||||||
static void
|
static void
|
||||||
audio_output_all_reset_reopen(void)
|
audio_output_all_reset_reopen(void)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < num_audio_outputs; ++i)
|
for (unsigned i = 0; i < num_audio_outputs; ++i) {
|
||||||
audio_outputs[i].reopen_after = 0;
|
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
|
static void
|
||||||
|
@ -38,7 +38,6 @@ audio_output_enable_index(unsigned idx)
|
|||||||
|
|
||||||
ao = audio_output_get(idx);
|
ao = audio_output_get(idx);
|
||||||
|
|
||||||
ao->reopen_after = 0;
|
|
||||||
ao->enabled = true;
|
ao->enabled = true;
|
||||||
idle_add(IDLE_OUTPUT);
|
idle_add(IDLE_OUTPUT);
|
||||||
|
|
||||||
|
@ -24,6 +24,12 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.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;
|
struct notify audio_output_client_notify;
|
||||||
|
|
||||||
static void ao_command_wait(struct audio_output *ao)
|
static void ao_command_wait(struct audio_output *ao)
|
||||||
@ -53,7 +59,10 @@ bool
|
|||||||
audio_output_open(struct audio_output *ao,
|
audio_output_open(struct audio_output *ao,
|
||||||
const struct audio_format *audio_format)
|
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 &&
|
if (ao->open &&
|
||||||
audio_format_equals(audio_format, &ao->in_audio_format)) {
|
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)
|
const struct audio_format *audio_format)
|
||||||
{
|
{
|
||||||
if (ao->enabled) {
|
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);
|
audio_output_open(ao, audio_format);
|
||||||
} else if (audio_output_is_open(ao))
|
} else if (audio_output_is_open(ao))
|
||||||
audio_output_close(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)
|
void audio_output_close(struct audio_output *ao)
|
||||||
{
|
{
|
||||||
|
assert(!ao->open || ao->fail_timer == NULL);
|
||||||
|
|
||||||
if (ao->open)
|
if (ao->open)
|
||||||
ao_command(ao, AO_COMMAND_CLOSE);
|
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)
|
void audio_output_finish(struct audio_output *ao)
|
||||||
{
|
{
|
||||||
audio_output_close(ao);
|
audio_output_close(ao);
|
||||||
|
|
||||||
|
assert(ao->fail_timer == NULL);
|
||||||
|
|
||||||
if (ao->thread != NULL) {
|
if (ao->thread != NULL) {
|
||||||
ao_command(ao, AO_COMMAND_KILL);
|
ao_command(ao, AO_COMMAND_KILL);
|
||||||
g_thread_join(ao->thread);
|
g_thread_join(ao->thread);
|
||||||
|
@ -93,7 +93,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param)
|
|||||||
ao->plugin = plugin;
|
ao->plugin = plugin;
|
||||||
ao->enabled = config_get_block_bool(param, "enabled", true);
|
ao->enabled = config_get_block_bool(param, "enabled", true);
|
||||||
ao->open = false;
|
ao->open = false;
|
||||||
ao->reopen_after = 0;
|
ao->fail_timer = NULL;
|
||||||
|
|
||||||
pcm_convert_init(&ao->convert_state);
|
pcm_convert_init(&ao->convert_state);
|
||||||
|
|
||||||
|
@ -65,10 +65,11 @@ struct audio_output {
|
|||||||
bool open;
|
bool open;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If not zero, the device has failed, and should not be
|
* If not NULL, the device has failed, and this timer is used
|
||||||
* reopened automatically before this time stamp.
|
* 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
|
* The audio_format in which audio data is received from the
|
||||||
|
@ -29,12 +29,6 @@
|
|||||||
#undef G_LOG_DOMAIN
|
#undef G_LOG_DOMAIN
|
||||||
#define G_LOG_DOMAIN "output"
|
#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)
|
static void ao_command_finished(struct audio_output *ao)
|
||||||
{
|
{
|
||||||
assert(ao->command != AO_COMMAND_NONE);
|
assert(ao->command != AO_COMMAND_NONE);
|
||||||
@ -129,6 +123,7 @@ static gpointer audio_output_task(gpointer arg)
|
|||||||
|
|
||||||
case AO_COMMAND_OPEN:
|
case AO_COMMAND_OPEN:
|
||||||
assert(!ao->open);
|
assert(!ao->open);
|
||||||
|
assert(ao->fail_timer == NULL);
|
||||||
|
|
||||||
error = NULL;
|
error = NULL;
|
||||||
ret = ao_plugin_open(ao->plugin, ao->data,
|
ret = ao_plugin_open(ao->plugin, ao->data,
|
||||||
@ -145,7 +140,7 @@ static gpointer audio_output_task(gpointer arg)
|
|||||||
error->message);
|
error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
|
||||||
ao->reopen_after = time(NULL) + REOPEN_AFTER;
|
ao->fail_timer = g_timer_new();
|
||||||
}
|
}
|
||||||
|
|
||||||
ao_command_finished(ao);
|
ao_command_finished(ao);
|
||||||
|
Loading…
Reference in New Issue
Block a user