aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2010-11-05 08:02:38 +0100
committerMax Kellermann <max@duempel.org>2010-11-05 09:47:43 +0100
commit2dc6ed7b3a2faf27d33fa8bbcf924031fde0e21a (patch)
treeb5ac194133bac616b12a97a875ca87fe24323a6b
parentad430c661780ed196d772564f9a49d5dacb5df0f (diff)
output_plugin: add method delay()
This method is used to reduce the delay of commands issued to the shout plugin.
-rw-r--r--src/output_plugin.h18
-rw-r--r--src/output_thread.c30
-rw-r--r--src/timer.c6
3 files changed, 51 insertions, 3 deletions
diff --git a/src/output_plugin.h b/src/output_plugin.h
index fabfe0df..36e17ed1 100644
--- a/src/output_plugin.h
+++ b/src/output_plugin.h
@@ -101,6 +101,16 @@ struct audio_output_plugin {
void (*close)(void *data);
/**
+ * Returns a positive number if the output thread shall delay
+ * the next call to play() or pause(). This should be
+ * implemented instead of doing a sleep inside the plugin,
+ * because this allows MPD to listen to commands meanwhile.
+ *
+ * @return the number of milliseconds to wait
+ */
+ unsigned (*delay)(void *data);
+
+ /**
* Display metadata for the next chunk. Optional method,
* because not all devices can display metadata.
*/
@@ -202,6 +212,14 @@ ao_plugin_close(const struct audio_output_plugin *plugin, void *data)
plugin->close(data);
}
+static inline unsigned
+ao_plugin_delay(const struct audio_output_plugin *plugin, void *data)
+{
+ return plugin->delay != NULL
+ ? plugin->delay(data)
+ : 0;
+}
+
static inline void
ao_plugin_send_tag(const struct audio_output_plugin *plugin,
void *data, const struct tag *tag)
diff --git a/src/output_thread.c b/src/output_thread.c
index c10a1552..8b120325 100644
--- a/src/output_thread.c
+++ b/src/output_thread.c
@@ -278,6 +278,30 @@ ao_reopen(struct audio_output *ao)
ao_open(ao);
}
+/**
+ * Wait until the output's delay reaches zero.
+ *
+ * @return true if playback should be continued, false if a command
+ * was issued
+ */
+static bool
+ao_wait(struct audio_output *ao)
+{
+ while (true) {
+ unsigned delay = ao_plugin_delay(ao->plugin, ao->data);
+ if (delay == 0)
+ return true;
+
+ GTimeVal tv;
+ g_get_current_time(&tv);
+ g_time_val_add(&tv, delay * 1000);
+ g_cond_timed_wait(ao->cond, ao->mutex, &tv);
+
+ if (ao->command != AO_COMMAND_NONE)
+ return false;
+ }
+}
+
static const char *
ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk,
struct filter *replay_gain_filter,
@@ -414,6 +438,9 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk)
while (size > 0 && ao->command == AO_COMMAND_NONE) {
size_t nbytes;
+ if (!ao_wait(ao))
+ break;
+
g_mutex_unlock(ao->mutex);
nbytes = ao_plugin_play(ao->plugin, ao->data, data, size,
&error);
@@ -511,6 +538,9 @@ static void ao_pause(struct audio_output *ao)
ao_command_finished(ao);
do {
+ if (!ao_wait(ao))
+ break;
+
g_mutex_unlock(ao->mutex);
ret = ao_plugin_pause(ao->plugin, ao->data);
g_mutex_lock(ao->mutex);
diff --git a/src/timer.c b/src/timer.c
index 49c2ee3a..e125b100 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -74,12 +74,12 @@ void timer_add(Timer *timer, int size)
unsigned
timer_delay(const Timer *timer)
{
- int64_t delay = timer->time - now();
+ int64_t delay = (timer->time - now()) / 1000;
if (delay < 0)
return 0;
- if (delay > 1000 * 1000 * 1000)
- return 1000 * 1000;
+ if (delay > G_MAXINT)
+ delay = G_MAXINT;
return delay / 1000;
}