From 6e21e24caed1a9497e876e4b89b12687aa73d6ad Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 29 Sep 2008 16:43:55 +0200 Subject: [PATCH] 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. --- src/audio.c | 13 +++++++++++++ src/audio.h | 2 ++ src/audioOutputs/audioOutput_shout.c | 19 ++++++++++++++++++- src/audioOutputs/audioOutput_shout.h | 2 ++ src/output_api.h | 11 +++++++++++ src/output_control.c | 5 +++++ src/output_control.h | 3 +++ src/output_thread.c | 18 ++++++++++++++++++ src/player_thread.c | 2 +- 9 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/audio.c b/src/audio.c index bbc7fd0eb..b38c47d72 100644 --- a/src/audio.c +++ b/src/audio.c @@ -397,6 +397,19 @@ int playAudio(const char *playChunk, size_t size) 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) { unsigned int i; diff --git a/src/audio.h b/src/audio.h index 4e34b0f61..3ffa2dc55 100644 --- a/src/audio.h +++ b/src/audio.h @@ -45,6 +45,8 @@ int openAudioDevice(const struct audio_format *audioFormat); int playAudio(const char *playChunk, size_t size); +void audio_output_pause_all(void); + void dropBufferedAudio(void); void closeAudioDevice(void); diff --git a/src/audioOutputs/audioOutput_shout.c b/src/audioOutputs/audioOutput_shout.c index b55c06cc9..6b59044d8 100644 --- a/src/audioOutputs/audioOutput_shout.c +++ b/src/audioOutputs/audioOutput_shout.c @@ -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, ConfigParam *param) { @@ -104,6 +104,7 @@ static void *my_shout_init_driver(mpd_unused struct audio_output *audio_output, int public; sd = new_shout_data(); + sd->audio_output = audio_output; if (shout_init_count == 0) shout_init(); @@ -516,6 +517,21 @@ static int my_shout_play(void *data, 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, const struct tag *tag) { @@ -539,6 +555,7 @@ const struct audio_output_plugin shoutPlugin = { .finish = my_shout_finish_driver, .open = my_shout_open_device, .play = my_shout_play, + .pause = my_shout_pause, .cancel = my_shout_drop_buffered_audio, .close = my_shout_close_device, .send_tag = my_shout_set_tag, diff --git a/src/audioOutputs/audioOutput_shout.h b/src/audioOutputs/audioOutput_shout.h index ddab852df..bd525fd6d 100644 --- a/src/audioOutputs/audioOutput_shout.h +++ b/src/audioOutputs/audioOutput_shout.h @@ -59,6 +59,8 @@ struct shout_buffer { }; struct shout_data { + struct audio_output *audio_output; + shout_t *shout_conn; shout_metadata_t *shout_meta; int shout_error; diff --git a/src/output_api.h b/src/output_api.h index 96acff775..1cad66e60 100644 --- a/src/output_api.h +++ b/src/output_api.h @@ -81,6 +81,16 @@ struct audio_output_plugin { */ 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 * buffers. @@ -104,6 +114,7 @@ enum audio_output_command { AO_COMMAND_OPEN, AO_COMMAND_CLOSE, AO_COMMAND_PLAY, + AO_COMMAND_PAUSE, AO_COMMAND_CANCEL, AO_COMMAND_SEND_TAG, AO_COMMAND_KILL diff --git a/src/output_control.c b/src/output_control.c index ac9394bd7..4724aeeea 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -103,6 +103,11 @@ void audio_output_play(struct audio_output *audioOutput, 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) { ao_command_async(audioOutput, AO_COMMAND_CANCEL); diff --git a/src/output_control.h b/src/output_control.h index b83a67b2f..7a31bb68f 100644 --- a/src/output_control.h +++ b/src/output_control.h @@ -41,6 +41,9 @@ audio_output_signal(struct audio_output *ao); void audio_output_play(struct audio_output *audioOutput, 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_close(struct audio_output *audioOutput); void audio_output_finish(struct audio_output *audioOutput); diff --git a/src/output_thread.c b/src/output_thread.c index 4bc5d8fcb..c2f4f6d3c 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -63,6 +63,20 @@ static void ao_play(struct audio_output *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) { struct audio_output *ao = arg; @@ -95,6 +109,10 @@ static void *audio_output_task(void *arg) ao_play(ao); break; + case AO_COMMAND_PAUSE: + ao_pause(ao); + break; + case AO_COMMAND_CANCEL: ao->plugin->cancel(ao->data); ao_command_finished(ao); diff --git a/src/player_thread.c b/src/player_thread.c index 171bd71c4..48715dd20 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -143,7 +143,7 @@ static void processDecodeInput(int *pause_r, unsigned int *bbp_r, *pause_r = 1; } else if (*pause_r) { dropBufferedAudio(); - closeAudioDevice(); + audio_output_pause_all(); } break;