aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2008-09-24 07:23:19 +0200
committerMax Kellermann <max@duempel.org>2008-09-24 07:23:19 +0200
commit2b782b82eaadeff36fa230ce3ac30893eb6581e3 (patch)
tree6d53007dd37083bc93647e0c68da705506edf412
parent6bbea44e91dd954a32915f824eaa28dfbf4d97d7 (diff)
downloadmpd-2b782b82eaadeff36fa230ce3ac30893eb6581e3.tar.gz
mpd-2b782b82eaadeff36fa230ce3ac30893eb6581e3.tar.xz
mpd-2b782b82eaadeff36fa230ce3ac30893eb6581e3.zip
output: semi-asynchronous playback
Send an output buffer to all output plugins at the same time, instead of waiting for each of them separately. Make several functions non-blocking, and introduce the new function audio_output_wait_all() to synchronize with all audio output threads.
-rw-r--r--src/audio.c76
-rw-r--r--src/output_control.c22
-rw-r--r--src/output_control.h4
-rw-r--r--src/output_internal.h12
4 files changed, 91 insertions, 23 deletions
diff --git a/src/audio.c b/src/audio.c
index f3de2285e..f027be588 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -213,6 +213,31 @@ int isCurrentAudioFormat(const struct audio_format *audioFormat)
return audio_format_equals(audioFormat, &audio_buffer.format);
}
+static void audio_output_wait(struct audio_output *ao)
+{
+ while (!audio_output_command_is_finished(ao))
+ notify_wait(&audio_output_client_notify);
+}
+
+static void audio_output_wait_all(void)
+{
+ unsigned i;
+
+ while (1) {
+ int finished = 1;
+
+ for (i = 0; i < audioOutputArraySize; ++i)
+ if (audioDeviceStates[i] == DEVICE_ON &&
+ !audio_output_command_is_finished(&audioOutputArray[i]))
+ finished = 0;
+
+ if (finished)
+ break;
+
+ notify_wait(&audio_output_client_notify);
+ };
+}
+
static void syncAudioDeviceStates(void)
{
struct audio_output *audioOutput;
@@ -239,6 +264,7 @@ static void syncAudioDeviceStates(void)
break;
case DEVICE_DISABLE:
audio_output_cancel(audioOutput);
+ audio_output_wait(audioOutput);
audio_output_close(audioOutput);
audioDeviceStates[i] = DEVICE_OFF;
}
@@ -255,19 +281,39 @@ static int flushAudioBuffer(void)
syncAudioDeviceStates();
- for (i = 0; i < audioOutputArraySize; ++i) {
- if (audioDeviceStates[i] != DEVICE_ON)
- continue;
- err = audio_output_play(&audioOutputArray[i],
- audio_buffer.buffer,
- audio_buffer.position);
- if (!err)
- ret = 0;
- else if (err < 0)
- /* device should already be closed if the play
- * func returned an error */
- audioDeviceStates[i] = DEVICE_ENABLE;
- }
+ for (i = 0; i < audioOutputArraySize; ++i)
+ if (audioDeviceStates[i] == DEVICE_ON)
+ audio_output_play(&audioOutputArray[i],
+ audio_buffer.buffer,
+ audio_buffer.position);
+
+ while (1) {
+ int finished = 1;
+
+ for (i = 0; i < audioOutputArraySize; ++i) {
+ const struct audio_output *ao = &audioOutputArray[i];
+
+ if (audioDeviceStates[i] != DEVICE_ON)
+ continue;
+
+ if (audio_output_command_is_finished(ao)) {
+ err = audio_output_get_result(ao);
+ if (!err)
+ ret = 0;
+ else if (err < 0)
+ /* device should already be
+ closed if the play func
+ returned an error */
+ audioDeviceStates[i] = DEVICE_ENABLE;
+ } else
+ finished = 0;
+ }
+
+ if (finished)
+ break;
+
+ notify_wait(&audio_output_client_notify);
+ };
audio_buffer.position = 0;
@@ -370,6 +416,8 @@ void dropBufferedAudio(void)
if (audioDeviceStates[i] == DEVICE_ON)
audio_output_cancel(&audioOutputArray[i]);
}
+
+ audio_output_wait_all();
}
void closeAudioDevice(void)
@@ -399,6 +447,8 @@ void sendMetadataToAudioDevice(const struct tag *tag)
for (i = 0; i < audioOutputArraySize; ++i)
if (audioDeviceStates[i] == DEVICE_ON)
audio_output_send_tag(&audioOutputArray[i], tag);
+
+ audio_output_wait_all();
}
int enableAudioDevice(unsigned int device)
diff --git a/src/output_control.c b/src/output_control.c
index 34e51aa41..3be1f6cd6 100644
--- a/src/output_control.c
+++ b/src/output_control.c
@@ -41,6 +41,14 @@ static void ao_command(struct audio_output *ao, enum audio_output_command cmd)
ao_command_wait(ao);
}
+static void ao_command_async(struct audio_output *ao,
+ enum audio_output_command cmd)
+{
+ assert(ao->command == AO_COMMAND_NONE);
+ ao->command = cmd;
+ notify_signal(&ao->notify);
+}
+
int audio_output_open(struct audio_output *audioOutput,
const struct audio_format *audioFormat)
{
@@ -78,22 +86,20 @@ int audio_output_open(struct audio_output *audioOutput,
return ret;
}
-int audio_output_play(struct audio_output *audioOutput,
- const char *playChunk, size_t size)
+void audio_output_play(struct audio_output *audioOutput,
+ const char *playChunk, size_t size)
{
if (!audioOutput->open)
- return -1;
+ return;
audioOutput->args.play.data = playChunk;
audioOutput->args.play.size = size;
- ao_command(audioOutput, AO_COMMAND_PLAY);
-
- return audioOutput->result;
+ ao_command_async(audioOutput, AO_COMMAND_PLAY);
}
void audio_output_cancel(struct audio_output *audioOutput)
{
- ao_command(audioOutput, AO_COMMAND_CANCEL);
+ ao_command_async(audioOutput, AO_COMMAND_CANCEL);
}
void audio_output_close(struct audio_output *audioOutput)
@@ -120,5 +126,5 @@ void audio_output_send_tag(struct audio_output *audioOutput,
return;
audioOutput->args.tag = tag;
- ao_command(audioOutput, AO_COMMAND_SEND_TAG);
+ ao_command_async(audioOutput, AO_COMMAND_SEND_TAG);
}
diff --git a/src/output_control.h b/src/output_control.h
index e16229e21..92973f6c1 100644
--- a/src/output_control.h
+++ b/src/output_control.h
@@ -30,8 +30,8 @@ struct tag;
int audio_output_init(struct audio_output *, ConfigParam * param);
int audio_output_open(struct audio_output *audioOutput,
const struct audio_format *audioFormat);
-int audio_output_play(struct audio_output *audioOutput,
- const char *playChunk, size_t size);
+void audio_output_play(struct audio_output *audioOutput,
+ const char *playChunk, size_t size);
void audio_output_cancel(struct audio_output *audioOutput);
void audio_output_close(struct audio_output *audioOutput);
void audio_output_finish(struct audio_output *audioOutput);
diff --git a/src/output_internal.h b/src/output_internal.h
index 5c11a9521..2455a549a 100644
--- a/src/output_internal.h
+++ b/src/output_internal.h
@@ -109,4 +109,16 @@ struct audio_output {
*/
extern struct notify audio_output_client_notify;
+static inline int
+audio_output_command_is_finished(const struct audio_output *ao)
+{
+ return ao->command == AO_COMMAND_NONE;
+}
+
+static inline int
+audio_output_get_result(const struct audio_output *ao)
+{
+ return ao->result;
+}
+
#endif