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:
parent
c13e8b5146
commit
6e21e24cae
13
src/audio.c
13
src/audio.c
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user