Commit 2dc6ed7b authored by Max Kellermann's avatar Max Kellermann

output_plugin: add method delay()

This method is used to reduce the delay of commands issued to the shout plugin.
parent ad430c66
...@@ -101,6 +101,16 @@ struct audio_output_plugin { ...@@ -101,6 +101,16 @@ struct audio_output_plugin {
void (*close)(void *data); 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, * Display metadata for the next chunk. Optional method,
* because not all devices can display metadata. * because not all devices can display metadata.
*/ */
...@@ -202,6 +212,14 @@ ao_plugin_close(const struct audio_output_plugin *plugin, void *data) ...@@ -202,6 +212,14 @@ ao_plugin_close(const struct audio_output_plugin *plugin, void *data)
plugin->close(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 static inline void
ao_plugin_send_tag(const struct audio_output_plugin *plugin, ao_plugin_send_tag(const struct audio_output_plugin *plugin,
void *data, const struct tag *tag) void *data, const struct tag *tag)
......
...@@ -278,6 +278,30 @@ ao_reopen(struct audio_output *ao) ...@@ -278,6 +278,30 @@ ao_reopen(struct audio_output *ao)
ao_open(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 * static const char *
ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk, ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk,
struct filter *replay_gain_filter, struct filter *replay_gain_filter,
...@@ -414,6 +438,9 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) ...@@ -414,6 +438,9 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk)
while (size > 0 && ao->command == AO_COMMAND_NONE) { while (size > 0 && ao->command == AO_COMMAND_NONE) {
size_t nbytes; size_t nbytes;
if (!ao_wait(ao))
break;
g_mutex_unlock(ao->mutex); g_mutex_unlock(ao->mutex);
nbytes = ao_plugin_play(ao->plugin, ao->data, data, size, nbytes = ao_plugin_play(ao->plugin, ao->data, data, size,
&error); &error);
...@@ -511,6 +538,9 @@ static void ao_pause(struct audio_output *ao) ...@@ -511,6 +538,9 @@ static void ao_pause(struct audio_output *ao)
ao_command_finished(ao); ao_command_finished(ao);
do { do {
if (!ao_wait(ao))
break;
g_mutex_unlock(ao->mutex); g_mutex_unlock(ao->mutex);
ret = ao_plugin_pause(ao->plugin, ao->data); ret = ao_plugin_pause(ao->plugin, ao->data);
g_mutex_lock(ao->mutex); g_mutex_lock(ao->mutex);
......
...@@ -74,12 +74,12 @@ void timer_add(Timer *timer, int size) ...@@ -74,12 +74,12 @@ void timer_add(Timer *timer, int size)
unsigned unsigned
timer_delay(const Timer *timer) timer_delay(const Timer *timer)
{ {
int64_t delay = timer->time - now(); int64_t delay = (timer->time - now()) / 1000;
if (delay < 0) if (delay < 0)
return 0; return 0;
if (delay > 1000 * 1000 * 1000) if (delay > G_MAXINT)
return 1000 * 1000; delay = G_MAXINT;
return delay / 1000; return delay / 1000;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment