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.
This commit is contained in:
76
src/audio.c
76
src/audio.c
@ -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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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;
|
|||||||
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 {
|
|||||||
*/
|
*/
|
||||||
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
|
||||||
|
Reference in New Issue
Block a user