aboutsummaryrefslogtreecommitdiffstats
path: root/src/output_all.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/output_all.c')
-rw-r--r--src/output_all.c160
1 files changed, 141 insertions, 19 deletions
diff --git a/src/output_all.c b/src/output_all.c
index 4b5ba3a6f..5b066ba26 100644
--- a/src/output_all.c
+++ b/src/output_all.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2009 The Music Player Daemon Project
+ * Copyright (C) 2003-2010 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,6 +17,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "config.h"
#include "output_all.h"
#include "output_internal.h"
#include "output_control.h"
@@ -25,6 +26,7 @@
#include "pipe.h"
#include "buffer.h"
#include "player_control.h"
+#include "mpd_error.h"
#ifndef NDEBUG
#include "chunk.h"
@@ -52,6 +54,11 @@ static struct music_buffer *g_music_buffer;
*/
static struct music_pipe *g_mp;
+/**
+ * The "elapsed_time" stamp of the most recently finished chunk.
+ */
+static float audio_output_all_elapsed_time = -1.0;
+
unsigned int audio_output_count(void)
{
return num_audio_outputs;
@@ -116,17 +123,17 @@ audio_output_all_init(void)
if (!audio_output_init(output, param, &error)) {
if (param != NULL)
- g_error("line %i: %s",
- param->line, error->message);
+ MPD_ERROR("line %i: %s",
+ param->line, error->message);
else
- g_error("%s", error->message);
+ MPD_ERROR("%s", error->message);
}
/* require output names to be unique: */
for (j = 0; j < i; j++) {
if (!strcmp(output->name, audio_outputs[j].name)) {
- g_error("output devices with identical "
- "names: %s\n", output->name);
+ MPD_ERROR("output devices with identical "
+ "names: %s\n", output->name);
}
}
}
@@ -138,6 +145,7 @@ audio_output_all_finish(void)
unsigned int i;
for (i = 0; i < num_audio_outputs; i++) {
+ audio_output_disable(&audio_outputs[i]);
audio_output_finish(&audio_outputs[i]);
}
@@ -148,6 +156,25 @@ audio_output_all_finish(void)
notify_deinit(&audio_output_client_notify);
}
+void
+audio_output_all_enable_disable(void)
+{
+ for (unsigned i = 0; i < num_audio_outputs; i++) {
+ struct audio_output *ao = &audio_outputs[i];
+ bool enabled;
+
+ g_mutex_lock(ao->mutex);
+ enabled = ao->really_enabled;
+ g_mutex_unlock(ao->mutex);
+
+ if (ao->enabled != enabled) {
+ if (ao->enabled)
+ audio_output_enable(ao);
+ else
+ audio_output_disable(ao);
+ }
+ }
+}
/**
* Determine if all (active) outputs have finished the current
@@ -156,10 +183,18 @@ audio_output_all_finish(void)
static bool
audio_output_all_finished(void)
{
- for (unsigned i = 0; i < num_audio_outputs; ++i)
- if (audio_output_is_open(&audio_outputs[i]) &&
- !audio_output_command_is_finished(&audio_outputs[i]))
+ for (unsigned i = 0; i < num_audio_outputs; ++i) {
+ struct audio_output *ao = &audio_outputs[i];
+ bool not_finished;
+
+ g_mutex_lock(ao->mutex);
+ not_finished = audio_output_is_open(ao) &&
+ !audio_output_command_is_finished(ao);
+ g_mutex_unlock(ao->mutex);
+
+ if (not_finished)
return false;
+ }
return true;
}
@@ -170,6 +205,29 @@ static void audio_output_wait_all(void)
notify_wait(&audio_output_client_notify);
}
+/**
+ * Signals the audio output if it is open. This function locks the
+ * mutex.
+ */
+static void
+audio_output_lock_signal(struct audio_output *ao)
+{
+ g_mutex_lock(ao->mutex);
+ if (audio_output_is_open(ao))
+ g_cond_signal(ao->cond);
+ g_mutex_unlock(ao->mutex);
+}
+
+/**
+ * Signals all audio outputs which are open.
+ */
+static void
+audio_output_signal_all(void)
+{
+ for (unsigned i = 0; i < num_audio_outputs; ++i)
+ audio_output_lock_signal(&audio_outputs[i]);
+}
+
static void
audio_output_reset_reopen(struct audio_output *ao)
{
@@ -237,8 +295,7 @@ audio_output_all_play(struct music_chunk *chunk)
music_pipe_push(g_mp, chunk);
for (i = 0; i < num_audio_outputs; ++i)
- if (audio_output_is_open(&audio_outputs[i]))
- audio_output_play(&audio_outputs[i]);
+ audio_output_play(&audio_outputs[i]);
return true;
}
@@ -273,6 +330,7 @@ audio_output_all_open(const struct audio_format *audio_format,
input_audio_format = *audio_format;
audio_output_all_reset_reopen();
+ audio_output_all_enable_disable();
audio_output_all_update();
for (i = 0; i < num_audio_outputs; ++i) {
@@ -385,6 +443,11 @@ audio_output_all_check(void)
this chunk */
return music_pipe_size(g_mp);
+ if (chunk->length > 0 && chunk->times >= 0.0)
+ /* only update elapsed_time if the chunk
+ provides a defined value */
+ audio_output_all_elapsed_time = chunk->times;
+
is_tail = chunk->next == NULL;
if (is_tail)
/* this is the tail of the pipe - clear the
@@ -412,10 +475,15 @@ audio_output_all_check(void)
bool
audio_output_all_wait(unsigned threshold)
{
- if (audio_output_all_check() < threshold)
+ player_lock();
+
+ if (audio_output_all_check() < threshold) {
+ player_unlock();
return true;
+ }
- notify_wait(&pc.notify);
+ player_wait();
+ player_unlock();
return audio_output_all_check() < threshold;
}
@@ -428,8 +496,16 @@ audio_output_all_pause(void)
audio_output_all_update();
for (i = 0; i < num_audio_outputs; ++i)
- if (audio_output_is_open(&audio_outputs[i]))
- audio_output_pause(&audio_outputs[i]);
+ audio_output_pause(&audio_outputs[i]);
+
+ audio_output_wait_all();
+}
+
+void
+audio_output_all_drain(void)
+{
+ for (unsigned i = 0; i < num_audio_outputs; ++i)
+ audio_output_drain_async(&audio_outputs[i]);
audio_output_wait_all();
}
@@ -441,10 +517,8 @@ audio_output_all_cancel(void)
/* send the cancel() command to all audio outputs */
- for (i = 0; i < num_audio_outputs; ++i) {
- if (audio_output_is_open(&audio_outputs[i]))
- audio_output_cancel(&audio_outputs[i]);
- }
+ for (i = 0; i < num_audio_outputs; ++i)
+ audio_output_cancel(&audio_outputs[i]);
audio_output_wait_all();
@@ -452,6 +526,15 @@ audio_output_all_cancel(void)
if (g_mp != NULL)
music_pipe_clear(g_mp, g_music_buffer);
+
+ /* the audio outputs are now waiting for a signal, to
+ synchronize the cleared music pipe */
+
+ audio_output_signal_all();
+
+ /* invalidate elapsed_time */
+
+ audio_output_all_elapsed_time = -1.0;
}
void
@@ -473,4 +556,43 @@ audio_output_all_close(void)
g_music_buffer = NULL;
audio_format_clear(&input_audio_format);
+
+ audio_output_all_elapsed_time = -1.0;
+}
+
+void
+audio_output_all_release(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_audio_outputs; ++i)
+ audio_output_release(&audio_outputs[i]);
+
+ if (g_mp != NULL) {
+ assert(g_music_buffer != NULL);
+
+ music_pipe_clear(g_mp, g_music_buffer);
+ music_pipe_free(g_mp);
+ g_mp = NULL;
+ }
+
+ g_music_buffer = NULL;
+
+ audio_format_clear(&input_audio_format);
+
+ audio_output_all_elapsed_time = -1.0;
+}
+
+void
+audio_output_all_song_border(void)
+{
+ /* clear the elapsed_time pointer at the beginning of a new
+ song */
+ audio_output_all_elapsed_time = 0.0;
+}
+
+float
+audio_output_all_get_elapsed_time(void)
+{
+ return audio_output_all_elapsed_time;
}