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

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.
parent 6bbea44e
...@@ -213,6 +213,31 @@ int isCurrentAudioFormat(const struct audio_format *audioFormat) ...@@ -213,6 +213,31 @@ int isCurrentAudioFormat(const struct audio_format *audioFormat)
return audio_format_equals(audioFormat, &audio_buffer.format); 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) static void syncAudioDeviceStates(void)
{ {
struct audio_output *audioOutput; struct audio_output *audioOutput;
...@@ -239,6 +264,7 @@ static void syncAudioDeviceStates(void) ...@@ -239,6 +264,7 @@ static void syncAudioDeviceStates(void)
break; break;
case DEVICE_DISABLE: case DEVICE_DISABLE:
audio_output_cancel(audioOutput); audio_output_cancel(audioOutput);
audio_output_wait(audioOutput);
audio_output_close(audioOutput); audio_output_close(audioOutput);
audioDeviceStates[i] = DEVICE_OFF; audioDeviceStates[i] = DEVICE_OFF;
} }
...@@ -255,19 +281,39 @@ static int flushAudioBuffer(void) ...@@ -255,19 +281,39 @@ static int flushAudioBuffer(void)
syncAudioDeviceStates(); syncAudioDeviceStates();
for (i = 0; i < audioOutputArraySize; ++i) { for (i = 0; i < audioOutputArraySize; ++i)
if (audioDeviceStates[i] != DEVICE_ON) if (audioDeviceStates[i] == DEVICE_ON)
continue; audio_output_play(&audioOutputArray[i],
err = audio_output_play(&audioOutputArray[i], audio_buffer.buffer,
audio_buffer.buffer, audio_buffer.position);
audio_buffer.position);
if (!err) while (1) {
ret = 0; int finished = 1;
else if (err < 0)
/* device should already be closed if the play for (i = 0; i < audioOutputArraySize; ++i) {
* func returned an error */ const struct audio_output *ao = &audioOutputArray[i];
audioDeviceStates[i] = DEVICE_ENABLE;
} 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; audio_buffer.position = 0;
...@@ -370,6 +416,8 @@ void dropBufferedAudio(void) ...@@ -370,6 +416,8 @@ void dropBufferedAudio(void)
if (audioDeviceStates[i] == DEVICE_ON) if (audioDeviceStates[i] == DEVICE_ON)
audio_output_cancel(&audioOutputArray[i]); audio_output_cancel(&audioOutputArray[i]);
} }
audio_output_wait_all();
} }
void closeAudioDevice(void) void closeAudioDevice(void)
...@@ -399,6 +447,8 @@ void sendMetadataToAudioDevice(const struct tag *tag) ...@@ -399,6 +447,8 @@ void sendMetadataToAudioDevice(const struct tag *tag)
for (i = 0; i < audioOutputArraySize; ++i) for (i = 0; i < audioOutputArraySize; ++i)
if (audioDeviceStates[i] == DEVICE_ON) if (audioDeviceStates[i] == DEVICE_ON)
audio_output_send_tag(&audioOutputArray[i], tag); audio_output_send_tag(&audioOutputArray[i], tag);
audio_output_wait_all();
} }
int enableAudioDevice(unsigned int device) int enableAudioDevice(unsigned int device)
......
...@@ -41,6 +41,14 @@ static void ao_command(struct audio_output *ao, enum audio_output_command cmd) ...@@ -41,6 +41,14 @@ static void ao_command(struct audio_output *ao, enum audio_output_command cmd)
ao_command_wait(ao); 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, int audio_output_open(struct audio_output *audioOutput,
const struct audio_format *audioFormat) const struct audio_format *audioFormat)
{ {
...@@ -78,22 +86,20 @@ int audio_output_open(struct audio_output *audioOutput, ...@@ -78,22 +86,20 @@ int audio_output_open(struct audio_output *audioOutput,
return ret; return ret;
} }
int audio_output_play(struct audio_output *audioOutput, void audio_output_play(struct audio_output *audioOutput,
const char *playChunk, size_t size) const char *playChunk, size_t size)
{ {
if (!audioOutput->open) if (!audioOutput->open)
return -1; return;
audioOutput->args.play.data = playChunk; audioOutput->args.play.data = playChunk;
audioOutput->args.play.size = size; audioOutput->args.play.size = size;
ao_command(audioOutput, AO_COMMAND_PLAY); ao_command_async(audioOutput, AO_COMMAND_PLAY);
return audioOutput->result;
} }
void audio_output_cancel(struct audio_output *audioOutput) 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) void audio_output_close(struct audio_output *audioOutput)
...@@ -120,5 +126,5 @@ void audio_output_send_tag(struct audio_output *audioOutput, ...@@ -120,5 +126,5 @@ void audio_output_send_tag(struct audio_output *audioOutput,
return; return;
audioOutput->args.tag = tag; audioOutput->args.tag = tag;
ao_command(audioOutput, AO_COMMAND_SEND_TAG); ao_command_async(audioOutput, AO_COMMAND_SEND_TAG);
} }
...@@ -30,8 +30,8 @@ struct tag; ...@@ -30,8 +30,8 @@ struct tag;
int audio_output_init(struct audio_output *, ConfigParam * param); int audio_output_init(struct audio_output *, ConfigParam * param);
int audio_output_open(struct audio_output *audioOutput, int audio_output_open(struct audio_output *audioOutput,
const struct audio_format *audioFormat); const struct audio_format *audioFormat);
int audio_output_play(struct audio_output *audioOutput, void audio_output_play(struct audio_output *audioOutput,
const char *playChunk, size_t size); const char *playChunk, size_t size);
void audio_output_cancel(struct audio_output *audioOutput); void audio_output_cancel(struct audio_output *audioOutput);
void audio_output_close(struct audio_output *audioOutput); void audio_output_close(struct audio_output *audioOutput);
void audio_output_finish(struct audio_output *audioOutput); void audio_output_finish(struct audio_output *audioOutput);
......
...@@ -109,4 +109,16 @@ struct audio_output { ...@@ -109,4 +109,16 @@ struct audio_output {
*/ */
extern struct notify audio_output_client_notify; 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 #endif
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