audio_output: added method pause()

pause() puts the audio output into pause mode: if supported, it may
perform a special action, which keeps the device open, but does not
play anything.  Output plugins like "shout" might want to play silence
during pause, so their clients won't be disconnected.  Plugins which
do not support pausing will simply be closed, and have to be reopened
when unpaused.

This pach includes an implementation for the shout plugin, which
sends silence chunks.
This commit is contained in:
Max Kellermann 2008-09-29 16:43:55 +02:00
parent c13e8b5146
commit 6e21e24cae
9 changed files with 73 additions and 2 deletions

View File

@ -397,6 +397,19 @@ int playAudio(const char *playChunk, size_t size)
return 0; return 0;
} }
void audio_output_pause_all(void)
{
unsigned int i;
syncAudioDeviceStates();
for (i = 0; i < audioOutputArraySize; ++i)
if (audio_output_is_open(&audioOutputArray[i]))
audio_output_pause(&audioOutputArray[i]);
audio_output_wait_all();
}
void dropBufferedAudio(void) void dropBufferedAudio(void)
{ {
unsigned int i; unsigned int i;

View File

@ -45,6 +45,8 @@ int openAudioDevice(const struct audio_format *audioFormat);
int playAudio(const char *playChunk, size_t size); int playAudio(const char *playChunk, size_t size);
void audio_output_pause_all(void);
void dropBufferedAudio(void); void dropBufferedAudio(void);
void closeAudioDevice(void); void closeAudioDevice(void);

View File

@ -87,7 +87,7 @@ static void free_shout_data(struct shout_data *sd)
} \ } \
} }
static void *my_shout_init_driver(mpd_unused struct audio_output *audio_output, static void *my_shout_init_driver(struct audio_output *audio_output,
const struct audio_format *audio_format, const struct audio_format *audio_format,
ConfigParam *param) ConfigParam *param)
{ {
@ -104,6 +104,7 @@ static void *my_shout_init_driver(mpd_unused struct audio_output *audio_output,
int public; int public;
sd = new_shout_data(); sd = new_shout_data();
sd->audio_output = audio_output;
if (shout_init_count == 0) if (shout_init_count == 0)
shout_init(); shout_init();
@ -516,6 +517,21 @@ static int my_shout_play(void *data,
return 0; return 0;
} }
static void my_shout_pause(void *data)
{
struct shout_data *sd = (struct shout_data *)data;
static const char silence[1020];
int ret;
/* play silence until the player thread sends us a command */
while (sd->opened && !audio_output_is_pending(sd->audio_output)) {
ret = my_shout_play(data, silence, sizeof(silence));
if (ret != 0)
break;
}
}
static void my_shout_set_tag(void *data, static void my_shout_set_tag(void *data,
const struct tag *tag) const struct tag *tag)
{ {
@ -539,6 +555,7 @@ const struct audio_output_plugin shoutPlugin = {
.finish = my_shout_finish_driver, .finish = my_shout_finish_driver,
.open = my_shout_open_device, .open = my_shout_open_device,
.play = my_shout_play, .play = my_shout_play,
.pause = my_shout_pause,
.cancel = my_shout_drop_buffered_audio, .cancel = my_shout_drop_buffered_audio,
.close = my_shout_close_device, .close = my_shout_close_device,
.send_tag = my_shout_set_tag, .send_tag = my_shout_set_tag,

View File

@ -59,6 +59,8 @@ struct shout_buffer {
}; };
struct shout_data { struct shout_data {
struct audio_output *audio_output;
shout_t *shout_conn; shout_t *shout_conn;
shout_metadata_t *shout_meta; shout_metadata_t *shout_meta;
int shout_error; int shout_error;

View File

@ -81,6 +81,16 @@ struct audio_output_plugin {
*/ */
int (*play)(void *data, const char *playChunk, size_t size); int (*play)(void *data, const char *playChunk, size_t size);
/**
* Pause the device. If supported, it may perform a special
* action, which keeps the device open, but does not play
* anything. Output plugins like "shout" might want to play
* silence during pause, so their clients won't be
* disconnected. Plugins which do not support pausing will
* simply be closed, and have to be reopened when unpaused.
*/
void (*pause)(void *data);
/** /**
* Try to cancel data which may still be in the device's * Try to cancel data which may still be in the device's
* buffers. * buffers.
@ -104,6 +114,7 @@ enum audio_output_command {
AO_COMMAND_OPEN, AO_COMMAND_OPEN,
AO_COMMAND_CLOSE, AO_COMMAND_CLOSE,
AO_COMMAND_PLAY, AO_COMMAND_PLAY,
AO_COMMAND_PAUSE,
AO_COMMAND_CANCEL, AO_COMMAND_CANCEL,
AO_COMMAND_SEND_TAG, AO_COMMAND_SEND_TAG,
AO_COMMAND_KILL AO_COMMAND_KILL

View File

@ -103,6 +103,11 @@ void audio_output_play(struct audio_output *audioOutput,
ao_command_async(audioOutput, AO_COMMAND_PLAY); ao_command_async(audioOutput, AO_COMMAND_PLAY);
} }
void audio_output_pause(struct audio_output *audioOutput)
{
ao_command_async(audioOutput, AO_COMMAND_PAUSE);
}
void audio_output_cancel(struct audio_output *audioOutput) void audio_output_cancel(struct audio_output *audioOutput)
{ {
ao_command_async(audioOutput, AO_COMMAND_CANCEL); ao_command_async(audioOutput, AO_COMMAND_CANCEL);

View File

@ -41,6 +41,9 @@ audio_output_signal(struct audio_output *ao);
void 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_pause(struct audio_output *audioOutput);
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);

View File

@ -63,6 +63,20 @@ static void ao_play(struct audio_output *ao)
ao_command_finished(ao); ao_command_finished(ao);
} }
static void ao_pause(struct audio_output *ao)
{
if (ao->plugin->pause != NULL) {
/* pause is supported */
ao_command_finished(ao);
ao->plugin->pause(ao->data);
} else {
/* pause is not supported - simply close the device */
ao->plugin->close(ao->data);
ao->open = 0;
ao_command_finished(ao);
}
}
static void *audio_output_task(void *arg) static void *audio_output_task(void *arg)
{ {
struct audio_output *ao = arg; struct audio_output *ao = arg;
@ -95,6 +109,10 @@ static void *audio_output_task(void *arg)
ao_play(ao); ao_play(ao);
break; break;
case AO_COMMAND_PAUSE:
ao_pause(ao);
break;
case AO_COMMAND_CANCEL: case AO_COMMAND_CANCEL:
ao->plugin->cancel(ao->data); ao->plugin->cancel(ao->data);
ao_command_finished(ao); ao_command_finished(ao);

View File

@ -143,7 +143,7 @@ static void processDecodeInput(int *pause_r, unsigned int *bbp_r,
*pause_r = 1; *pause_r = 1;
} else if (*pause_r) { } else if (*pause_r) {
dropBufferedAudio(); dropBufferedAudio();
closeAudioDevice(); audio_output_pause_all();
} }
break; break;