diff options
32 files changed, 830 insertions, 552 deletions
diff --git a/Makefile.am b/Makefile.am index c85422ada..e85a2967f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,7 +45,6 @@ mpd_headers = \ src/audio_parser.h \ src/output_internal.h \ src/output_api.h \ - src/output_plugin.h \ src/output_list.h \ src/output_all.h \ src/output_thread.h \ @@ -716,6 +715,7 @@ OUTPUT_API_SRC = \ src/output_state.c \ src/output_print.c \ src/output_command.c \ + src/output_plugin.c src/output_plugin.h \ src/output_finish.c \ src/output_init.c @@ -1144,6 +1144,7 @@ test_run_output_SOURCES = test/run_output.c \ src/page.c \ src/socket_util.c \ src/output_init.c src/output_finish.c src/output_list.c \ + src/output_plugin.c \ $(ENCODER_SRC) \ src/mixer_api.c \ src/mixer_control.c \ diff --git a/src/output/alsa_output_plugin.c b/src/output/alsa_output_plugin.c index fb0498e96..41293272d 100644 --- a/src/output/alsa_output_plugin.c +++ b/src/output/alsa_output_plugin.c @@ -43,6 +43,8 @@ typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t * pcm, const void *buffer, snd_pcm_uframes_t size); struct alsa_data { + struct audio_output base; + /** the configured name of the ALSA device; NULL for the default device */ char *device; @@ -143,23 +145,27 @@ alsa_configure(struct alsa_data *ad, const struct config_param *param) #endif } -static void * -alsa_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, - G_GNUC_UNUSED GError **error) +static struct audio_output * +alsa_init(const struct config_param *param, GError **error_r) { struct alsa_data *ad = alsa_data_new(); + if (!ao_base_init(&ad->base, &alsa_output_plugin, param, error_r)) { + g_free(ad); + return NULL; + } + alsa_configure(ad, param); - return ad; + return &ad->base; } static void -alsa_finish(void *data) +alsa_finish(struct audio_output *ao) { - struct alsa_data *ad = data; + struct alsa_data *ad = (struct alsa_data *)ao; + ao_base_finish(&ad->base); alsa_data_free(ad); /* free libasound's config cache */ @@ -530,9 +536,9 @@ error: } static bool -alsa_open(void *data, struct audio_format *audio_format, GError **error) +alsa_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) { - struct alsa_data *ad = data; + struct alsa_data *ad = (struct alsa_data *)ao; int err; bool success; @@ -594,9 +600,9 @@ alsa_recover(struct alsa_data *ad, int err) } static void -alsa_drain(void *data) +alsa_drain(struct audio_output *ao) { - struct alsa_data *ad = data; + struct alsa_data *ad = (struct alsa_data *)ao; if (snd_pcm_state(ad->pcm) != SND_PCM_STATE_RUNNING) return; @@ -628,9 +634,9 @@ alsa_drain(void *data) } static void -alsa_cancel(void *data) +alsa_cancel(struct audio_output *ao) { - struct alsa_data *ad = data; + struct alsa_data *ad = (struct alsa_data *)ao; ad->period_position = 0; @@ -638,17 +644,18 @@ alsa_cancel(void *data) } static void -alsa_close(void *data) +alsa_close(struct audio_output *ao) { - struct alsa_data *ad = data; + struct alsa_data *ad = (struct alsa_data *)ao; snd_pcm_close(ad->pcm); } static size_t -alsa_play(void *data, const void *chunk, size_t size, GError **error) +alsa_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error) { - struct alsa_data *ad = data; + struct alsa_data *ad = (struct alsa_data *)ao; size /= ad->frame_size; diff --git a/src/output/ao_output_plugin.c b/src/output/ao_output_plugin.c index e85d97d6e..c0790681e 100644 --- a/src/output/ao_output_plugin.c +++ b/src/output/ao_output_plugin.c @@ -33,6 +33,8 @@ static const ao_sample_format OUR_AO_FORMAT_INITIALIZER; static unsigned ao_output_ref; struct ao_data { + struct audio_output base; + size_t write_size; int driver; ao_option *options; @@ -79,12 +81,17 @@ ao_output_error(GError **error_r) "%s", error); } -static void * -ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, +static struct audio_output * +ao_output_init(const struct config_param *param, GError **error) { struct ao_data *ad = g_new(struct ao_data, 1); + + if (!ao_base_init(&ad->base, &ao_output_plugin, param, error)) { + g_free(ad); + return NULL; + } + ao_info *ai; const char *value; @@ -107,6 +114,7 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, g_set_error(error, ao_output_quark(), 0, "\"%s\" is not a valid ao driver", value); + ao_base_finish(&ad->base); g_free(ad); return NULL; } @@ -114,6 +122,7 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, if ((ai = ao_driver_info(ad->driver)) == NULL) { g_set_error(error, ao_output_quark(), 0, "problems getting driver info"); + ao_base_finish(&ad->base); g_free(ad); return NULL; } @@ -132,6 +141,7 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, g_set_error(error, ao_output_quark(), 0, "problems parsing options \"%s\"", options[i]); + ao_base_finish(&ad->base); g_free(ad); return NULL; } @@ -145,15 +155,16 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, g_strfreev(options); } - return ad; + return &ad->base; } static void -ao_output_finish(void *data) +ao_output_finish(struct audio_output *ao) { - struct ao_data *ad = (struct ao_data *)data; + struct ao_data *ad = (struct ao_data *)ao; ao_free_options(ad->options); + ao_base_finish(&ad->base); g_free(ad); ao_output_ref--; @@ -163,19 +174,19 @@ ao_output_finish(void *data) } static void -ao_output_close(void *data) +ao_output_close(struct audio_output *ao) { - struct ao_data *ad = (struct ao_data *)data; + struct ao_data *ad = (struct ao_data *)ao; ao_close(ad->device); } static bool -ao_output_open(void *data, struct audio_format *audio_format, +ao_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) { ao_sample_format format = OUR_AO_FORMAT_INITIALIZER; - struct ao_data *ad = (struct ao_data *)data; + struct ao_data *ad = (struct ao_data *)ao; switch (audio_format->format) { case SAMPLE_FORMAT_S8: @@ -227,10 +238,10 @@ static int ao_play_deconst(ao_device *device, const void *output_samples, } static size_t -ao_output_play(void *data, const void *chunk, size_t size, +ao_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error) { - struct ao_data *ad = (struct ao_data *)data; + struct ao_data *ad = (struct ao_data *)ao; if (size > ad->write_size) size = ad->write_size; diff --git a/src/output/ffado_output_plugin.c b/src/output/ffado_output_plugin.c index af74419a9..ba239a4ad 100644 --- a/src/output/ffado_output_plugin.c +++ b/src/output/ffado_output_plugin.c @@ -54,6 +54,8 @@ struct mpd_ffado_stream { }; struct mpd_ffado_device { + struct audio_output base; + char *device_name; int verbose; unsigned period_size, nb_buffers; @@ -83,21 +85,26 @@ ffado_output_quark(void) return g_quark_from_static_string("ffado_output"); } -static void * -ffado_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, +static struct audio_output * +ffado_init(const struct config_param *param, GError **error_r) { g_debug("using libffado version %s, API=%d", ffado_get_version(), ffado_get_api_version()); struct mpd_ffado_device *fd = g_new(struct mpd_ffado_device, 1); + if (!ao_base_init(&fd->base, &ffado_output_plugin, param, error_r)) { + g_free(fd); + return NULL; + } + fd->device_name = config_dup_block_string(param, "device", NULL); fd->verbose = config_get_block_unsigned(param, "verbose", 0); fd->period_size = config_get_block_unsigned(param, "period_size", 1024); if (fd->period_size == 0 || fd->period_size > 1024 * 1024) { + ao_base_finish(&fd->base); g_set_error(error_r, ffado_output_quark(), 0, "invalid period_size setting"); return false; @@ -105,20 +112,22 @@ ffado_init(G_GNUC_UNUSED const struct audio_format *audio_format, fd->nb_buffers = config_get_block_unsigned(param, "nb_buffers", 3); if (fd->nb_buffers == 0 || fd->nb_buffers > 1024) { + ao_base_finish(&fd->base); g_set_error(error_r, ffado_output_quark(), 0, "invalid nb_buffers setting"); return false; } - return fd; + return &fd->base; } static void -ffado_finish(void *data) +ffado_finish(struct audio_output *ao) { - struct mpd_ffado_device *fd = data; + struct mpd_ffado_device *fd = (struct mpd_ffado_device *)ao; g_free(fd->device_name); + ao_base_finish(&fd->base); g_free(fd); } @@ -228,9 +237,10 @@ ffado_configure(struct mpd_ffado_device *fd, struct audio_format *audio_format, } static bool -ffado_open(void *data, struct audio_format *audio_format, GError **error_r) +ffado_open(struct audio_output *ao, struct audio_format *audio_format, + GError **error_r) { - struct mpd_ffado_device *fd = data; + struct mpd_ffado_device *fd = (struct mpd_ffado_device *)ao; /* will be converted to floating point, choose best input format */ @@ -274,9 +284,9 @@ ffado_open(void *data, struct audio_format *audio_format, GError **error_r) } static void -ffado_close(void *data) +ffado_close(struct audio_output *ao) { - struct mpd_ffado_device *fd = data; + struct mpd_ffado_device *fd = (struct mpd_ffado_device *)ao; ffado_streaming_stop(fd->dev); ffado_streaming_finish(fd->dev); @@ -288,9 +298,10 @@ ffado_close(void *data) } static size_t -ffado_play(void *data, const void *chunk, size_t size, GError **error_r) +ffado_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error_r) { - struct mpd_ffado_device *fd = data; + struct mpd_ffado_device *fd = (struct mpd_ffado_device *)ao; /* wait for prefious buffer to finish (if it was full) */ diff --git a/src/output/fifo_output_plugin.c b/src/output/fifo_output_plugin.c index db250e81c..f7c88cdc8 100644 --- a/src/output/fifo_output_plugin.c +++ b/src/output/fifo_output_plugin.c @@ -39,6 +39,8 @@ #define FIFO_BUFFER_SIZE 65536 /* pipe capacity on Linux >= 2.6.11 */ struct fifo_data { + struct audio_output base; + char *path; int input; int output; @@ -176,9 +178,8 @@ fifo_open(struct fifo_data *fd, GError **error) return true; } -static void * -fifo_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, +static struct audio_output * +fifo_output_init(const struct config_param *param, GError **error_r) { struct fifo_data *fd; @@ -197,28 +198,35 @@ fifo_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, fd = fifo_data_new(); fd->path = path; + if (!ao_base_init(&fd->base, &fifo_output_plugin, param, error_r)) { + fifo_data_free(fd); + return NULL; + } + if (!fifo_open(fd, error_r)) { + ao_base_finish(&fd->base); fifo_data_free(fd); return NULL; } - return fd; + return &fd->base; } static void -fifo_output_finish(void *data) +fifo_output_finish(struct audio_output *ao) { - struct fifo_data *fd = (struct fifo_data *)data; + struct fifo_data *fd = (struct fifo_data *)ao; fifo_close(fd); + ao_base_finish(&fd->base); fifo_data_free(fd); } static bool -fifo_output_open(void *data, struct audio_format *audio_format, +fifo_output_open(struct audio_output *ao, struct audio_format *audio_format, G_GNUC_UNUSED GError **error) { - struct fifo_data *fd = (struct fifo_data *)data; + struct fifo_data *fd = (struct fifo_data *)ao; fd->timer = timer_new(audio_format); @@ -226,17 +234,17 @@ fifo_output_open(void *data, struct audio_format *audio_format, } static void -fifo_output_close(void *data) +fifo_output_close(struct audio_output *ao) { - struct fifo_data *fd = (struct fifo_data *)data; + struct fifo_data *fd = (struct fifo_data *)ao; timer_free(fd->timer); } static void -fifo_output_cancel(void *data) +fifo_output_cancel(struct audio_output *ao) { - struct fifo_data *fd = (struct fifo_data *)data; + struct fifo_data *fd = (struct fifo_data *)ao; char buf[FIFO_BUFFER_SIZE]; int bytes = 1; @@ -252,10 +260,10 @@ fifo_output_cancel(void *data) } static size_t -fifo_output_play(void *data, const void *chunk, size_t size, +fifo_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error) { - struct fifo_data *fd = (struct fifo_data *)data; + struct fifo_data *fd = (struct fifo_data *)ao; ssize_t bytes; if (!fd->timer->started) @@ -274,7 +282,7 @@ fifo_output_play(void *data, const void *chunk, size_t size, switch (errno) { case EAGAIN: /* The pipe is full, so empty it */ - fifo_output_cancel(fd); + fifo_output_cancel(&fd->base); continue; case EINTR: continue; diff --git a/src/output/httpd_internal.h b/src/output/httpd_internal.h index 3e6e9768d..5dcb8ab9b 100644 --- a/src/output/httpd_internal.h +++ b/src/output/httpd_internal.h @@ -25,6 +25,7 @@ #ifndef MPD_OUTPUT_HTTPD_INTERNAL_H #define MPD_OUTPUT_HTTPD_INTERNAL_H +#include "output_internal.h" #include "timer.h" #include <glib.h> @@ -34,6 +35,8 @@ struct httpd_client; struct httpd_output { + struct audio_output base; + /** * True if the audio output is open and accepts client * connections. diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c index abbd78ad2..ab663badf 100644 --- a/src/output/httpd_output_plugin.c +++ b/src/output/httpd_output_plugin.c @@ -79,12 +79,16 @@ httpd_output_unbind(struct httpd_output *httpd) g_mutex_unlock(httpd->mutex); } -static void * -httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, +static struct audio_output * +httpd_output_init(const struct config_param *param, GError **error) { struct httpd_output *httpd = g_new(struct httpd_output, 1); + if (!ao_base_init(&httpd->base, &httpd_output_plugin, param, error)) { + g_free(httpd); + return NULL; + } + const char *encoder_name, *bind_to_address; const struct encoder_plugin *encoder_plugin; guint port; @@ -104,6 +108,7 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, if (encoder_plugin == NULL) { g_set_error(error, httpd_output_quark(), 0, "No such encoder: %s", encoder_name); + ao_base_finish(&httpd->base); g_free(httpd); return NULL; } @@ -121,8 +126,11 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, ? server_socket_add_host(httpd->server_socket, bind_to_address, port, error) : server_socket_add_port(httpd->server_socket, port, error); - if (!success) + if (!success) { + ao_base_finish(&httpd->base); + g_free(httpd); return NULL; + } /* initialize metadata */ httpd->metadata = NULL; @@ -131,8 +139,11 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, /* initialize encoder */ httpd->encoder = encoder_init(encoder_plugin, param, error); - if (httpd->encoder == NULL) + if (httpd->encoder == NULL) { + ao_base_finish(&httpd->base); + g_free(httpd); return NULL; + } /* determine content type */ httpd->content_type = encoder_get_mime_type(httpd->encoder); @@ -142,13 +153,13 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, httpd->mutex = g_mutex_new(); - return httpd; + return &httpd->base; } static void -httpd_output_finish(void *data) +httpd_output_finish(struct audio_output *ao) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; if (httpd->metadata) page_unref(httpd->metadata); @@ -156,6 +167,7 @@ httpd_output_finish(void *data) encoder_finish(httpd->encoder); server_socket_free(httpd->server_socket); g_mutex_free(httpd->mutex); + ao_base_finish(&httpd->base); g_free(httpd); } @@ -287,26 +299,26 @@ httpd_output_encoder_open(struct httpd_output *httpd, } static bool -httpd_output_enable(void *data, GError **error_r) +httpd_output_enable(struct audio_output *ao, GError **error_r) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; return httpd_output_bind(httpd, error_r); } static void -httpd_output_disable(void *data) +httpd_output_disable(struct audio_output *ao) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; httpd_output_unbind(httpd); } static bool -httpd_output_open(void *data, struct audio_format *audio_format, +httpd_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; bool success; g_mutex_lock(httpd->mutex); @@ -339,9 +351,10 @@ httpd_client_delete(gpointer data, G_GNUC_UNUSED gpointer user_data) httpd_client_free(client); } -static void httpd_output_close(void *data) +static void +httpd_output_close(struct audio_output *ao) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; g_mutex_lock(httpd->mutex); @@ -380,9 +393,9 @@ httpd_output_send_header(struct httpd_output *httpd, } static unsigned -httpd_output_delay(void *data) +httpd_output_delay(struct audio_output *ao) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; return httpd->timer->started ? timer_delay(httpd->timer) @@ -458,9 +471,10 @@ httpd_output_encode_and_play(struct httpd_output *httpd, } static size_t -httpd_output_play(void *data, const void *chunk, size_t size, GError **error) +httpd_output_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; bool has_clients; g_mutex_lock(httpd->mutex); @@ -484,9 +498,9 @@ httpd_output_play(void *data, const void *chunk, size_t size, GError **error) } static bool -httpd_output_pause(void *data) +httpd_output_pause(struct audio_output *ao) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; g_mutex_lock(httpd->mutex); bool has_clients = httpd->clients != NULL; @@ -494,7 +508,7 @@ httpd_output_pause(void *data) if (has_clients) { static const char silence[1020]; - return httpd_output_play(data, silence, sizeof(silence), + return httpd_output_play(ao, silence, sizeof(silence), NULL) > 0; } else { g_usleep(100000); @@ -512,9 +526,9 @@ httpd_send_metadata(gpointer data, gpointer user_data) } static void -httpd_output_tag(void *data, const struct tag *tag) +httpd_output_tag(struct audio_output *ao, const struct tag *tag) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; assert(tag != NULL); @@ -571,9 +585,9 @@ httpd_client_cancel_callback(gpointer data, G_GNUC_UNUSED gpointer user_data) } static void -httpd_output_cancel(void *data) +httpd_output_cancel(struct audio_output *ao) { - struct httpd_output *httpd = data; + struct httpd_output *httpd = (struct httpd_output *)ao; g_mutex_lock(httpd->mutex); g_list_foreach(httpd->clients, httpd_client_cancel_callback, NULL); diff --git a/src/output/jack_output_plugin.c b/src/output/jack_output_plugin.c index 189b52a6f..cd769088b 100644 --- a/src/output/jack_output_plugin.c +++ b/src/output/jack_output_plugin.c @@ -44,6 +44,8 @@ enum { static const size_t jack_sample_size = sizeof(jack_default_audio_sample_t); struct jack_data { + struct audio_output base; + /** * libjack options passed to jack_client_open(). */ @@ -292,14 +294,18 @@ parse_port_list(int line, const char *source, char **dest, GError **error_r) return n; } -static void * -mpd_jack_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, GError **error_r) +static struct audio_output * +mpd_jack_init(const struct config_param *param, GError **error_r) { - struct jack_data *jd; + struct jack_data *jd = g_new(struct jack_data, 1); + + if (!ao_base_init(&jd->base, &jack_output_plugin, param, error_r)) { + g_free(jd); + return NULL; + } + const char *value; - jd = g_new(struct jack_data, 1); jd->options = JackNullOption; jd->name = config_get_block_string(param, "client_name", NULL); @@ -362,13 +368,13 @@ mpd_jack_init(G_GNUC_UNUSED const struct audio_format *audio_format, jack_set_info_function(mpd_jack_info); #endif - return jd; + return &jd->base; } static void -mpd_jack_finish(void *data) +mpd_jack_finish(struct audio_output *ao) { - struct jack_data *jd = data; + struct jack_data *jd = (struct jack_data *)ao; for (unsigned i = 0; i < jd->num_source_ports; ++i) g_free(jd->source_ports[i]); @@ -376,13 +382,14 @@ mpd_jack_finish(void *data) for (unsigned i = 0; i < jd->num_destination_ports; ++i) g_free(jd->destination_ports[i]); + ao_base_finish(&jd->base); g_free(jd); } static bool -mpd_jack_enable(void *data, GError **error_r) +mpd_jack_enable(struct audio_output *ao, GError **error_r) { - struct jack_data *jd = (struct jack_data *)data; + struct jack_data *jd = (struct jack_data *)ao; for (unsigned i = 0; i < jd->num_source_ports; ++i) jd->ringbuffer[i] = NULL; @@ -391,9 +398,9 @@ mpd_jack_enable(void *data, GError **error_r) } static void -mpd_jack_disable(void *data) +mpd_jack_disable(struct audio_output *ao) { - struct jack_data *jd = (struct jack_data *)data; + struct jack_data *jd = (struct jack_data *)ao; if (jd->client != NULL) mpd_jack_disconnect(jd); @@ -556,9 +563,10 @@ mpd_jack_start(struct jack_data *jd, GError **error_r) } static bool -mpd_jack_open(void *data, struct audio_format *audio_format, GError **error_r) +mpd_jack_open(struct audio_output *ao, struct audio_format *audio_format, + GError **error_r) { - struct jack_data *jd = data; + struct jack_data *jd = (struct jack_data *)ao; assert(jd != NULL); @@ -577,9 +585,9 @@ mpd_jack_open(void *data, struct audio_format *audio_format, GError **error_r) } static void -mpd_jack_close(G_GNUC_UNUSED void *data) +mpd_jack_close(G_GNUC_UNUSED struct audio_output *ao) { - struct jack_data *jd = data; + struct jack_data *jd = (struct jack_data *)ao; mpd_jack_stop(jd); } @@ -649,9 +657,10 @@ mpd_jack_write_samples(struct jack_data *jd, const void *src, } static size_t -mpd_jack_play(void *data, const void *chunk, size_t size, GError **error_r) +mpd_jack_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error_r) { - struct jack_data *jd = data; + struct jack_data *jd = (struct jack_data *)ao; const size_t frame_size = audio_format_frame_size(&jd->audio_format); size_t space = 0, space1; @@ -693,9 +702,9 @@ mpd_jack_play(void *data, const void *chunk, size_t size, GError **error_r) } static bool -mpd_jack_pause(void *data) +mpd_jack_pause(struct audio_output *ao) { - struct jack_data *jd = data; + struct jack_data *jd = (struct jack_data *)ao; if (jd->shutdown) return false; diff --git a/src/output/mvp_output_plugin.c b/src/output/mvp_output_plugin.c index 6f058b53e..aec09248f 100644 --- a/src/output/mvp_output_plugin.c +++ b/src/output/mvp_output_plugin.c @@ -70,6 +70,8 @@ typedef struct { #define MVP_GET_AUD_REGS _IOW('a',28,aud_ctl_regs_t*) struct mvp_data { + struct audio_output base; + struct audio_format audio_format; int fd; }; @@ -131,21 +133,26 @@ mvp_output_test_default_device(void) return false; } -static void * -mvp_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - G_GNUC_UNUSED const struct config_param *param, - G_GNUC_UNUSED GError **error) +static struct audio_output * +mvp_output_init(G_GNUC_UNUSED const struct config_param *param, GError **error) { struct mvp_data *md = g_new(struct mvp_data, 1); + + if (!ao_base_init(&md->base, &mvp_output_plugin, param, error)) { + g_free(md); + return NULL; + } + md->fd = -1; - return md; + return &md->base; } static void -mvp_output_finish(void *data) +mvp_output_finish(struct audio_output *ao) { - struct mvp_data *md = data; + struct mvp_data *md = (struct mvp_data *)ao; + ao_base_finish(&md->base); g_free(md); } @@ -226,9 +233,10 @@ mvp_set_pcm_params(struct mvp_data *md, struct audio_format *audio_format, } static bool -mvp_output_open(void *data, struct audio_format *audio_format, GError **error) +mvp_output_open(struct audio_output *ao, struct audio_format *audio_format, + GError **error) { - struct mvp_data *md = data; + struct mvp_data *md = (struct mvp_data *)ao; long long int stc = 0; int mix[5] = { 0, 2, 7, 1, 0 }; bool success; @@ -274,17 +282,17 @@ mvp_output_open(void *data, struct audio_format *audio_format, GError **error) return true; } -static void mvp_output_close(void *data) +static void mvp_output_close(struct audio_output *ao) { - struct mvp_data *md = data; + struct mvp_data *md = (struct mvp_data *)ao; if (md->fd >= 0) close(md->fd); md->fd = -1; } -static void mvp_output_cancel(void *data) +static void mvp_output_cancel(struct audio_output *ao) { - struct mvp_data *md = data; + struct mvp_data *md = (struct mvp_data *)ao; if (md->fd >= 0) { ioctl(md->fd, MVP_SET_AUD_RESET, 0x11); close(md->fd); @@ -293,16 +301,17 @@ static void mvp_output_cancel(void *data) } static size_t -mvp_output_play(void *data, const void *chunk, size_t size, GError **error) +mvp_output_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error) { - struct mvp_data *md = data; + struct mvp_data *md = (struct mvp_data *)ao; ssize_t ret; /* reopen the device since it was closed by dropBufferedAudio */ if (md->fd < 0) { bool success; - success = mvp_output_open(md, &md->audio_format, error); + success = mvp_output_open(ao, &md->audio_format, error); if (!success) return 0; } diff --git a/src/output/null_output_plugin.c b/src/output/null_output_plugin.c index 94c0c5321..e680e617c 100644 --- a/src/output/null_output_plugin.c +++ b/src/output/null_output_plugin.c @@ -27,39 +27,45 @@ #include <assert.h> struct null_data { + struct audio_output base; + bool sync; struct timer *timer; }; -static void * -null_init(G_GNUC_UNUSED const struct audio_format *audio_format, - G_GNUC_UNUSED const struct config_param *param, - G_GNUC_UNUSED GError **error) +static struct audio_output * +null_init(const struct config_param *param, GError **error_r) { struct null_data *nd = g_new(struct null_data, 1); + if (!ao_base_init(&nd->base, &null_output_plugin, param, error_r)) { + g_free(nd); + return NULL; + } + nd->sync = config_get_block_bool(param, "sync", true); nd->timer = NULL; - return nd; + return &nd->base; } static void -null_finish(void *data) +null_finish(struct audio_output *ao) { - struct null_data *nd = data; + struct null_data *nd = (struct null_data *)ao; assert(nd->timer == NULL); + ao_base_finish(&nd->base); g_free(nd); } static bool -null_open(void *data, struct audio_format *audio_format, +null_open(struct audio_output *ao, struct audio_format *audio_format, G_GNUC_UNUSED GError **error) { - struct null_data *nd = data; + struct null_data *nd = (struct null_data *)ao; if (nd->sync) nd->timer = timer_new(audio_format); @@ -68,9 +74,9 @@ null_open(void *data, struct audio_format *audio_format, } static void -null_close(void *data) +null_close(struct audio_output *ao) { - struct null_data *nd = data; + struct null_data *nd = (struct null_data *)ao; if (nd->timer != NULL) { timer_free(nd->timer); @@ -79,10 +85,10 @@ null_close(void *data) } static size_t -null_play(void *data, G_GNUC_UNUSED const void *chunk, size_t size, +null_play(struct audio_output *ao, G_GNUC_UNUSED const void *chunk, size_t size, G_GNUC_UNUSED GError **error) { - struct null_data *nd = data; + struct null_data *nd = (struct null_data *)ao; struct timer *timer = nd->timer; if (!nd->sync) @@ -99,9 +105,9 @@ null_play(void *data, G_GNUC_UNUSED const void *chunk, size_t size, } static void -null_cancel(void *data) +null_cancel(struct audio_output *ao) { - struct null_data *nd = data; + struct null_data *nd = (struct null_data *)ao; if (!nd->sync) return; diff --git a/src/output/openal_output_plugin.c b/src/output/openal_output_plugin.c index 56afc4463..1473659f0 100644 --- a/src/output/openal_output_plugin.c +++ b/src/output/openal_output_plugin.c @@ -39,6 +39,8 @@ #define NUM_BUFFERS 16 struct openal_data { + struct audio_output base; + const char *device_name; ALCdevice *device; ALCcontext *context; @@ -126,10 +128,8 @@ openal_unqueue_buffers(struct openal_data *od) } } -static void * -openal_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, - G_GNUC_UNUSED GError **error) +static struct audio_output * +openal_init(const struct config_param *param, GError **error_r) { const char *device_name = config_get_block_string(param, "device", NULL); struct openal_data *od; @@ -139,24 +139,30 @@ openal_init(G_GNUC_UNUSED const struct audio_format *audio_format, } od = g_new(struct openal_data, 1); + if (!ao_base_init(&od->base, &openal_output_plugin, param, error_r)) { + g_free(od); + return NULL; + } + od->device_name = device_name; - return od; + return &od->base; } static void -openal_finish(void *data) +openal_finish(struct audio_output *ao) { - struct openal_data *od = data; + struct openal_data *od = (struct openal_data *)ao; + ao_base_finish(&od->base); g_free(od); } static bool -openal_open(void *data, struct audio_format *audio_format, +openal_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) { - struct openal_data *od = data; + struct openal_data *od = (struct openal_data *)ao; od->format = openal_audio_format(audio_format); @@ -198,9 +204,9 @@ openal_open(void *data, struct audio_format *audio_format, } static void -openal_close(void *data) +openal_close(struct audio_output *ao) { - struct openal_data *od = data; + struct openal_data *od = (struct openal_data *)ao; timer_free(od->timer); alcMakeContextCurrent(od->context); @@ -211,10 +217,10 @@ openal_close(void *data) } static size_t -openal_play(void *data, const void *chunk, size_t size, +openal_play(struct audio_output *ao, const void *chunk, size_t size, G_GNUC_UNUSED GError **error) { - struct openal_data *od = data; + struct openal_data *od = (struct openal_data *)ao; ALuint buffer; ALint num, state; @@ -257,9 +263,9 @@ openal_play(void *data, const void *chunk, size_t size, } static void -openal_cancel(void *data) +openal_cancel(struct audio_output *ao) { - struct openal_data *od = data; + struct openal_data *od = (struct openal_data *)ao; od->filled = 0; alcMakeContextCurrent(od->context); diff --git a/src/output/oss_output_plugin.c b/src/output/oss_output_plugin.c index c9aef52a6..c8fce84ea 100644 --- a/src/output/oss_output_plugin.c +++ b/src/output/oss_output_plugin.c @@ -52,6 +52,8 @@ #endif struct oss_data { + struct audio_output base; + int fd; const char *device; @@ -143,7 +145,7 @@ oss_output_test_default_device(void) return false; } -static void * +static struct audio_output * oss_open_default(GError **error) { int i; @@ -154,8 +156,14 @@ oss_open_default(GError **error) ret[i] = oss_stat_device(default_devices[i], &err[i]); if (ret[i] == OSS_STAT_NO_ERROR) { struct oss_data *od = oss_data_new(); + if (!ao_base_init(&od->base, &oss_output_plugin, NULL, + error)) { + g_free(od); + return NULL; + } + od->device = default_devices[i]; - return od; + return &od->base; } } @@ -185,26 +193,31 @@ oss_open_default(GError **error) return NULL; } -static void * -oss_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, - GError **error) +static struct audio_output * +oss_output_init(const struct config_param *param, GError **error) { const char *device = config_get_block_string(param, "device", NULL); if (device != NULL) { struct oss_data *od = oss_data_new(); + if (!ao_base_init(&od->base, &oss_output_plugin, param, + error)) { + g_free(od); + return NULL; + } + od->device = device; - return od; + return &od->base; } return oss_open_default(error); } static void -oss_output_finish(void *data) +oss_output_finish(struct audio_output *ao) { - struct oss_data *od = data; + struct oss_data *od = (struct oss_data *)ao; + ao_base_finish(&od->base); oss_data_free(od); } @@ -607,9 +620,10 @@ oss_reopen(struct oss_data *od, GError **error_r) } static bool -oss_output_open(void *data, struct audio_format *audio_format, GError **error) +oss_output_open(struct audio_output *ao, struct audio_format *audio_format, + GError **error) { - struct oss_data *od = data; + struct oss_data *od = (struct oss_data *)ao; od->fd = open_cloexec(od->device, O_WRONLY, 0); if (od->fd < 0) { @@ -629,17 +643,17 @@ oss_output_open(void *data, struct audio_format *audio_format, GError **error) } static void -oss_output_close(void *data) +oss_output_close(struct audio_output *ao) { - struct oss_data *od = data; + struct oss_data *od = (struct oss_data *)ao; oss_close(od); } static void -oss_output_cancel(void *data) +oss_output_cancel(struct audio_output *ao) { - struct oss_data *od = data; + struct oss_data *od = (struct oss_data *)ao; if (od->fd >= 0) { ioctl(od->fd, SNDCTL_DSP_RESET, 0); @@ -648,9 +662,10 @@ oss_output_cancel(void *data) } static size_t -oss_output_play(void *data, const void *chunk, size_t size, GError **error) +oss_output_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error) { - struct oss_data *od = data; + struct oss_data *od = (struct oss_data *)ao; ssize_t ret; /* reopen the device since it was closed by dropBufferedAudio */ diff --git a/src/output/osx_output_plugin.c b/src/output/osx_output_plugin.c index f33148c25..f07aedc08 100644 --- a/src/output/osx_output_plugin.c +++ b/src/output/osx_output_plugin.c @@ -29,6 +29,8 @@ #define G_LOG_DOMAIN "osx" struct osx_output { + struct audio_output base; + /* configuration settings */ OSType component_subtype; /* only applicable with kAudioUnitSubType_HALOutput */ @@ -80,12 +82,14 @@ osx_output_configure(struct osx_output *oo, const struct config_param *param) } } -static void * -osx_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - G_GNUC_UNUSED const struct config_param *param, - G_GNUC_UNUSED GError **error) +static struct audio_output * +osx_output_init(const struct config_param *param, GError **error_r) { struct osx_output *oo = g_new(struct osx_output, 1); + if (!ao_base_init(&oo->base, &osx_output_plugin, param, error_r)) { + g_free(oo); + return NULL; + } osx_output_configure(oo, param); oo->mutex = g_mutex_new(); @@ -96,12 +100,13 @@ osx_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, oo->buffer = NULL; oo->buffer_size = 0; - return oo; + return &oo->base; } -static void osx_output_finish(void *data) +static void +osx_output_finish(struct audio_output *ao) { - struct osx_output *od = data; + struct osx_output *od = (struct osx_output *)ao; g_free(od->buffer); g_mutex_free(od->mutex); @@ -109,18 +114,20 @@ static void osx_output_finish(void *data) g_free(od); } -static void osx_output_cancel(void *data) +static void +osx_output_cancel(struct audio_output *ao) { - struct osx_output *od = data; + struct osx_output *od = (struct osx_output *)ao; g_mutex_lock(od->mutex); od->len = 0; g_mutex_unlock(od->mutex); } -static void osx_output_close(void *data) +static void +osx_output_close(struct audio_output *ao) { - struct osx_output *od = data; + struct osx_output *od = (struct osx_output *)ao; AudioOutputUnitStop(od->au); AudioUnitUninitialize(od->au); @@ -266,9 +273,9 @@ done: } static bool -osx_output_open(void *data, struct audio_format *audio_format, GError **error) +osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) { - struct osx_output *od = data; + struct osx_output *od = (struct osx_output *)ao; ComponentDescription desc; Component comp; AURenderCallbackStruct callback; @@ -385,10 +392,10 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error) } static size_t -osx_output_play(void *data, const void *chunk, size_t size, +osx_output_play(struct audio_output *ao, const void *chunk, size_t size, G_GNUC_UNUSED GError **error) { - struct osx_output *od = data; + struct osx_output *od = (struct osx_output *)ao; size_t start, nbytes; g_mutex_lock(od->mutex); diff --git a/src/output/pipe_output_plugin.c b/src/output/pipe_output_plugin.c index 08f195068..90c5a5331 100644 --- a/src/output/pipe_output_plugin.c +++ b/src/output/pipe_output_plugin.c @@ -25,6 +25,8 @@ #include <errno.h> struct pipe_output { + struct audio_output base; + char *cmd; FILE *fh; }; @@ -38,13 +40,17 @@ pipe_output_quark(void) return g_quark_from_static_string("pipe_output"); } -static void * -pipe_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, +static struct audio_output * +pipe_output_init(const struct config_param *param, GError **error) { struct pipe_output *pd = g_new(struct pipe_output, 1); + if (!ao_base_init(&pd->base, &pipe_output_plugin, param, error)) { + g_free(pd); + return NULL; + } + pd->cmd = config_dup_block_string(param, "command", NULL); if (pd->cmd == NULL) { g_set_error(error, pipe_output_quark(), 0, @@ -52,23 +58,25 @@ pipe_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, return NULL; } - return pd; + return &pd->base; } static void -pipe_output_finish(void *data) +pipe_output_finish(struct audio_output *ao) { - struct pipe_output *pd = data; + struct pipe_output *pd = (struct pipe_output *)ao; g_free(pd->cmd); + ao_base_finish(&pd->base); g_free(pd); } static bool -pipe_output_open(void *data, G_GNUC_UNUSED struct audio_format *audio_format, +pipe_output_open(struct audio_output *ao, + G_GNUC_UNUSED struct audio_format *audio_format, G_GNUC_UNUSED GError **error) { - struct pipe_output *pd = data; + struct pipe_output *pd = (struct pipe_output *)ao; pd->fh = popen(pd->cmd, "w"); if (pd->fh == NULL) { @@ -82,17 +90,17 @@ pipe_output_open(void *data, G_GNUC_UNUSED struct audio_format *audio_format, } static void -pipe_output_close(void *data) +pipe_output_close(struct audio_output *ao) { - struct pipe_output *pd = data; + struct pipe_output *pd = (struct pipe_output *)ao; pclose(pd->fh); } static size_t -pipe_output_play(void *data, const void *chunk, size_t size, GError **error) +pipe_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error) { - struct pipe_output *pd = data; + struct pipe_output *pd = (struct pipe_output *)ao; size_t ret; ret = fwrite(chunk, 1, size, pd->fh); diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c index 22e21d729..0dc9be0e4 100644 --- a/src/output/pulse_output_plugin.c +++ b/src/output/pulse_output_plugin.c @@ -46,6 +46,8 @@ #endif struct pulse_output { + struct audio_output base; + const char *name; const char *server; const char *sink; @@ -342,16 +344,19 @@ pulse_output_setup_context(struct pulse_output *po, GError **error_r) return true; } -static void * -pulse_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, - G_GNUC_UNUSED GError **error_r) +static struct audio_output * +pulse_output_init(const struct config_param *param, GError **error_r) { struct pulse_output *po; g_setenv("PULSE_PROP_media.role", "music", true); po = g_new(struct pulse_output, 1); + if (!ao_base_init(&po->base, &pulse_output_plugin, param, error_r)) { + g_free(po); + return NULL; + } + po->name = config_get_block_string(param, "name", "mpd_pulse"); po->server = config_get_block_string(param, "server", NULL); po->sink = config_get_block_string(param, "sink", NULL); @@ -361,21 +366,22 @@ pulse_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, po->context = NULL; po->stream = NULL; - return po; + return &po->base; } static void -pulse_output_finish(void *data) +pulse_output_finish(struct audio_output *ao) { - struct pulse_output *po = data; + struct pulse_output *po = (struct pulse_output *)ao; + ao_base_finish(&po->base); g_free(po); } static bool -pulse_output_enable(void *data, GError **error_r) +pulse_output_enable(struct audio_output *ao, GError **error_r) { - struct pulse_output *po = data; + struct pulse_output *po = (struct pulse_output *)ao; assert(po->mainloop == NULL); assert(po->context == NULL); @@ -419,9 +425,9 @@ pulse_output_enable(void *data, GError **error_r) } static void -pulse_output_disable(void *data) +pulse_output_disable(struct audio_output *ao) { - struct pulse_output *po = data; + struct pulse_output *po = (struct pulse_output *)ao; assert(po->mainloop != NULL); @@ -573,10 +579,10 @@ pulse_output_setup_stream(struct pulse_output *po, const pa_sample_spec *ss, } static bool -pulse_output_open(void *data, struct audio_format *audio_format, +pulse_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error_r) { - struct pulse_output *po = data; + struct pulse_output *po = (struct pulse_output *)ao; pa_sample_spec ss; int error; @@ -647,9 +653,9 @@ pulse_output_open(void *data, struct audio_format *audio_format, } static void -pulse_output_close(void *data) +pulse_output_close(struct audio_output *ao) { - struct pulse_output *po = data; + struct pulse_output *po = (struct pulse_output *)ao; pa_operation *o; assert(po->mainloop != NULL); @@ -796,9 +802,10 @@ pulse_output_stream_pause(struct pulse_output *po, bool pause, } static size_t -pulse_output_play(void *data, const void *chunk, size_t size, GError **error_r) +pulse_output_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error_r) { - struct pulse_output *po = data; + struct pulse_output *po = (struct pulse_output *)ao; int error; assert(po->mainloop != NULL); @@ -866,9 +873,9 @@ pulse_output_play(void *data, const void *chunk, size_t size, GError **error_r) } static void -pulse_output_cancel(void *data) +pulse_output_cancel(struct audio_output *ao) { - struct pulse_output *po = data; + struct pulse_output *po = (struct pulse_output *)ao; pa_operation *o; assert(po->mainloop != NULL); @@ -898,9 +905,9 @@ pulse_output_cancel(void *data) } static bool -pulse_output_pause(void *data) +pulse_output_pause(struct audio_output *ao) { - struct pulse_output *po = data; + struct pulse_output *po = (struct pulse_output *)ao; GError *error = NULL; assert(po->mainloop != NULL); @@ -945,12 +952,12 @@ pulse_output_test_default_device(void) struct pulse_output *po; bool success; - po = pulse_output_init(NULL, NULL, NULL); + po = (struct pulse_output *)pulse_output_init(NULL, NULL); if (po == NULL) return false; success = pulse_output_wait_connection(po, NULL); - pulse_output_finish(po); + pulse_output_finish(&po->base); return success; } diff --git a/src/output/raop_output_plugin.c b/src/output/raop_output_plugin.c index 772112e51..dce7b5beb 100644 --- a/src/output/raop_output_plugin.c +++ b/src/output/raop_output_plugin.c @@ -79,6 +79,8 @@ struct encrypt_data { /*********************************************************************/ struct raop_data { + struct audio_output base; + struct rtspcl_data *rtspcl; const char *addr; // target host address short rtsp_port; @@ -209,9 +211,13 @@ raop_session_new(GError **error_r) } static struct raop_data * -new_raop_data(GError **error_r) +new_raop_data(const struct config_param *param, GError **error_r) { struct raop_data *ret = g_new(struct raop_data, 1); + if (!ao_base_init(&ret->base, &raop_output_plugin, param, error_r)) { + g_free(ret); + return NULL; + } ret->control_mutex = g_mutex_new(); @@ -223,6 +229,7 @@ new_raop_data(GError **error_r) if (raop_session == NULL && (raop_session = raop_session_new(error_r)) == NULL) { g_mutex_free(ret->control_mutex); + ao_base_finish(&ret->base); g_free(ret); return NULL; } @@ -721,10 +728,8 @@ send_audio_data(int fd, GError **error_r) return true; } -static void * -raop_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - G_GNUC_UNUSED const struct config_param *param, - GError **error_r) +static struct audio_output * +raop_output_init(const struct config_param *param, GError **error_r) { const char *host = config_get_block_string(param, "host", NULL); if (host == NULL) { @@ -735,14 +740,14 @@ raop_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, struct raop_data *rd; - rd = new_raop_data(error_r); + rd = new_raop_data(param, error_r); if (rd == NULL) return NULL; rd->addr = host; rd->rtsp_port = config_get_block_unsigned(param, "port", 5000); rd->volume = config_get_block_unsigned(param, "volume", 75); - return rd; + return &rd->base; } static bool @@ -755,14 +760,15 @@ raop_set_volume_local(struct raop_data *rd, int volume, GError **error_r) static void -raop_output_finish(void *data) +raop_output_finish(struct audio_output *ao) { - struct raop_data *rd = data; + struct raop_data *rd = (struct raop_data *)ao; if (rd->rtspcl) rtspcl_close(rd->rtspcl); g_mutex_free(rd->control_mutex); + ao_base_finish(&rd->base); g_free(rd); } @@ -797,11 +803,11 @@ raop_set_volume(struct raop_data *rd, unsigned volume, GError **error_r) } static void -raop_output_cancel(void *data) +raop_output_cancel(struct audio_output *ao) { //flush struct key_data kd; - struct raop_data *rd = (struct raop_data *) data; + struct raop_data *rd = (struct raop_data *)ao; int flush_diff = 1; rd->started = 0; @@ -825,9 +831,9 @@ raop_output_cancel(void *data) } static bool -raop_output_pause(void *data) +raop_output_pause(struct audio_output *ao) { - struct raop_data *rd = (struct raop_data *) data; + struct raop_data *rd = (struct raop_data *)ao; rd->paused = true; return true; @@ -870,10 +876,10 @@ raop_output_remove(struct raop_data *rd) } static void -raop_output_close(void *data) +raop_output_close(struct audio_output *ao) { //teardown - struct raop_data *rd = data; + struct raop_data *rd = (struct raop_data *)ao; raop_output_remove(rd); @@ -887,10 +893,10 @@ raop_output_close(void *data) static bool -raop_output_open(void *data, struct audio_format *audio_format, GError **error_r) +raop_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error_r) { //setup, etc. - struct raop_data *rd = data; + struct raop_data *rd = (struct raop_data *)ao; g_mutex_lock(raop_session->list_mutex); if (raop_session->raop_list == NULL) { @@ -940,11 +946,11 @@ raop_output_open(void *data, struct audio_format *audio_format, GError **error_r } static size_t -raop_output_play(void *data, const void *chunk, size_t size, +raop_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error_r) { //raopcl_send_sample - struct raop_data *rd = data; + struct raop_data *rd = (struct raop_data *)ao; size_t rval = 0, orig_size = size; rd->paused = false; diff --git a/src/output/recorder_output_plugin.c b/src/output/recorder_output_plugin.c index 981f92e44..00adc5d19 100644 --- a/src/output/recorder_output_plugin.c +++ b/src/output/recorder_output_plugin.c @@ -35,6 +35,8 @@ #define G_LOG_DOMAIN "recorder" struct recorder_output { + struct audio_output base; + /** * The configured encoder plugin. */ @@ -65,11 +67,16 @@ recorder_output_quark(void) return g_quark_from_static_string("recorder_output"); } -static void * -recorder_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, GError **error_r) +static struct audio_output * +recorder_output_init(const struct config_param *param, GError **error_r) { struct recorder_output *recorder = g_new(struct recorder_output, 1); + if (!ao_base_init(&recorder->base, &recorder_output_plugin, param, + error_r)) { + g_free(recorder); + return NULL; + } + const char *encoder_name; const struct encoder_plugin *encoder_plugin; @@ -96,19 +103,21 @@ recorder_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, if (recorder->encoder == NULL) goto failure; - return recorder; + return &recorder->base; failure: + ao_base_finish(&recorder->base); g_free(recorder); return NULL; } static void -recorder_output_finish(void *data) +recorder_output_finish(struct audio_output *ao) { - struct recorder_output *recorder = data; + struct recorder_output *recorder = (struct recorder_output *)ao; encoder_finish(recorder->encoder); + ao_base_finish(&recorder->base); g_free(recorder); } @@ -155,10 +164,11 @@ recorder_output_encoder_to_file(struct recorder_output *recorder, } static bool -recorder_output_open(void *data, struct audio_format *audio_format, +recorder_output_open(struct audio_output *ao, + struct audio_format *audio_format, GError **error_r) { - struct recorder_output *recorder = data; + struct recorder_output *recorder = (struct recorder_output *)ao; bool success; /* create the output file */ @@ -186,9 +196,9 @@ recorder_output_open(void *data, struct audio_format *audio_format, } static void -recorder_output_close(void *data) +recorder_output_close(struct audio_output *ao) { - struct recorder_output *recorder = data; + struct recorder_output *recorder = (struct recorder_output *)ao; /* flush the encoder and write the rest to the file */ @@ -203,10 +213,10 @@ recorder_output_close(void *data) } static size_t -recorder_output_play(void *data, const void *chunk, size_t size, +recorder_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error_r) { - struct recorder_output *recorder = data; + struct recorder_output *recorder = (struct recorder_output *)ao; return encoder_write(recorder->encoder, chunk, size, error_r) && recorder_output_encoder_to_file(recorder, error_r) diff --git a/src/output/roar_output_plugin.c b/src/output/roar_output_plugin.c index c6f3e99f5..d15569fd5 100644 --- a/src/output/roar_output_plugin.c +++ b/src/output/roar_output_plugin.c @@ -38,6 +38,8 @@ typedef struct roar { + struct audio_output base; + roar_vs_t * vss; int err; char *host; @@ -114,34 +116,39 @@ roar_configure(struct roar * self, const struct config_param *param) : ROAR_ROLE_MUSIC; } -static void * -roar_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, - G_GNUC_UNUSED GError **error) +static struct audio_output * +roar_init(const struct config_param *param, GError **error_r) { struct roar *self = g_new0(struct roar, 1); + + if (!ao_base_init(&self->base, &roar_output_plugin, param, error_r)) { + g_free(self); + return NULL; + } + self->lock = g_mutex_new(); self->err = ROAR_ERROR_NONE; roar_configure(self, param); - return self; + return &self->base; } static void -roar_finish(void *data) +roar_finish(struct audio_output *ao) { - roar_t * self = data; + struct roar *self = (struct roar *)ao; g_free(self->host); g_free(self->name); g_mutex_free(self->lock); + ao_base_finish(&self->base); g_free(self); } static bool -roar_open(void *data, struct audio_format *audio_format, GError **error) +roar_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) { - roar_t * self = data; + struct roar *self = (struct roar *)ao; g_mutex_lock(self->lock); if (roar_simple_connect(&(self->con), self->host, self->name) < 0) @@ -205,9 +212,9 @@ roar_open(void *data, struct audio_format *audio_format, GError **error) } static void -roar_close(void *data) +roar_close(struct audio_output *ao) { - roar_t * self = data; + struct roar *self = (struct roar *)ao; g_mutex_lock(self->lock); self->alive = false; @@ -246,9 +253,9 @@ roar_cancel_locked(struct roar *self) } static void -roar_cancel(void *data) +roar_cancel(struct audio_output *ao) { - roar_t * self = data; + struct roar *self = (struct roar *)ao; g_mutex_lock(self->lock); roar_cancel_locked(self); @@ -256,9 +263,9 @@ roar_cancel(void *data) } static size_t -roar_play(void *data, const void *chunk, size_t size, GError **error) +roar_play(struct audio_output *ao, const void *chunk, size_t size, GError **error) { - struct roar * self = data; + struct roar *self = (struct roar *)ao; ssize_t rc; if (self->vss == NULL) @@ -323,9 +330,9 @@ roar_tag_convert(enum tag_type type, bool *is_uuid) } static void -roar_send_tag(void *data, const struct tag *meta) +roar_send_tag(struct audio_output *ao, const struct tag *meta) { - struct roar * self = data; + struct roar *self = (struct roar *)ao; if (self->vss == NULL) return; diff --git a/src/output/shout_output_plugin.c b/src/output/shout_output_plugin.c index 299f5b24d..35356d659 100644 --- a/src/output/shout_output_plugin.c +++ b/src/output/shout_output_plugin.c @@ -42,6 +42,8 @@ struct shout_buffer { }; struct shout_data { + struct audio_output base; + shout_t *shout_conn; shout_metadata_t *shout_meta; @@ -108,9 +110,8 @@ static void free_shout_data(struct shout_data *sd) } \ } -static void * -my_shout_init_driver(const struct audio_format *audio_format, - const struct config_param *param, +static struct audio_output * +my_shout_init_driver(const struct config_param *param, GError **error) { struct shout_data *sd; @@ -129,15 +130,23 @@ my_shout_init_driver(const struct audio_format *audio_format, const struct block_param *block_param; int public; - if (audio_format == NULL || - !audio_format_fully_defined(audio_format)) { + sd = new_shout_data(); + + if (!ao_base_init(&sd->base, &shout_output_plugin, param, error)) { + free_shout_data(sd); + return NULL; + } + + const struct audio_format *audio_format = + &sd->base.config_audio_format; + if (!audio_format_fully_defined(audio_format)) { g_set_error(error, shout_output_quark(), 0, "Need full audio format specification"); + ao_base_finish(&sd->base); + free_shout_data(sd); return NULL; } - sd = new_shout_data(); - if (shout_init_count == 0) shout_init(); @@ -307,9 +316,10 @@ my_shout_init_driver(const struct audio_format *audio_format, } } - return sd; + return &sd->base; failure: + ao_base_finish(&sd->base); free_shout_data(sd); return NULL; } @@ -379,12 +389,14 @@ static void close_shout_conn(struct shout_data * sd) } } -static void my_shout_finish_driver(void *data) +static void +my_shout_finish_driver(struct audio_output *ao) { - struct shout_data *sd = (struct shout_data *)data; + struct shout_data *sd = (struct shout_data *)ao; encoder_finish(sd->encoder); + ao_base_finish(&sd->base); free_shout_data(sd); shout_init_count--; @@ -393,17 +405,19 @@ static void my_shout_finish_driver(void *data) shout_shutdown(); } -static void my_shout_drop_buffered_audio(void *data) +static void +my_shout_drop_buffered_audio(struct audio_output *ao) { G_GNUC_UNUSED - struct shout_data *sd = (struct shout_data *)data; + struct shout_data *sd = (struct shout_data *)ao; /* needs to be implemented for shout */ } -static void my_shout_close_device(void *data) +static void +my_shout_close_device(struct audio_output *ao) { - struct shout_data *sd = (struct shout_data *)data; + struct shout_data *sd = (struct shout_data *)ao; close_shout_conn(sd); } @@ -430,10 +444,10 @@ shout_connect(struct shout_data *sd, GError **error) } static bool -my_shout_open_device(void *data, struct audio_format *audio_format, +my_shout_open_device(struct audio_output *ao, struct audio_format *audio_format, GError **error) { - struct shout_data *sd = (struct shout_data *)data; + struct shout_data *sd = (struct shout_data *)ao; bool ret; ret = shout_connect(sd, error); @@ -453,9 +467,9 @@ my_shout_open_device(void *data, struct audio_format *audio_format, } static unsigned -my_shout_delay(void *data) +my_shout_delay(struct audio_output *ao) { - struct shout_data *sd = (struct shout_data *)data; + struct shout_data *sd = (struct shout_data *)ao; int delay = shout_delay(sd->shout_conn); if (delay < 0) @@ -465,9 +479,10 @@ my_shout_delay(void *data) } static size_t -my_shout_play(void *data, const void *chunk, size_t size, GError **error) +my_shout_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error) { - struct shout_data *sd = (struct shout_data *)data; + struct shout_data *sd = (struct shout_data *)ao; return encoder_write(sd->encoder, chunk, size, error) && write_page(sd, error) @@ -476,11 +491,11 @@ my_shout_play(void *data, const void *chunk, size_t size, GError **error) } static bool -my_shout_pause(void *data) +my_shout_pause(struct audio_output *ao) { static const char silence[1020]; - return my_shout_play(data, silence, sizeof(silence), NULL); + return my_shout_play(ao, silence, sizeof(silence), NULL); } static void @@ -509,10 +524,10 @@ shout_tag_to_metadata(const struct tag *tag, char *dest, size_t size) snprintf(dest, size, "%s - %s", artist, title); } -static void my_shout_set_tag(void *data, +static void my_shout_set_tag(struct audio_output *ao, const struct tag *tag) { - struct shout_data *sd = (struct shout_data *)data; + struct shout_data *sd = (struct shout_data *)ao; bool ret; GError *error = NULL; diff --git a/src/output/solaris_output_plugin.c b/src/output/solaris_output_plugin.c index efa7a4e32..796c7806d 100644 --- a/src/output/solaris_output_plugin.c +++ b/src/output/solaris_output_plugin.c @@ -36,6 +36,8 @@ #define G_LOG_DOMAIN "solaris_output" struct solaris_output { + struct audio_output base; + /* configuration */ const char *device; @@ -60,31 +62,35 @@ solaris_output_test_default_device(void) access("/dev/audio", W_OK) == 0; } -static void * -solaris_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - const struct config_param *param, - G_GNUC_UNUSED GError **error) +static struct audio_output * +solaris_output_init(const struct config_param *param, GError **error_r) { struct solaris_output *so = g_new(struct solaris_output, 1); + if (!ao_base_init(&so->base, &solaris_output_plugin, param, error_r)) { + g_free(so); + return NULL; + } + so->device = config_get_block_string(param, "device", "/dev/audio"); - return so; + return &so->base; } static void -solaris_output_finish(void *data) +solaris_output_finish(struct audio_output *ao) { - struct solaris_output *so = data; + struct solaris_output *so = (struct solaris_output *)ao; + ao_base_finish(&so->base); g_free(so); } static bool -solaris_output_open(void *data, struct audio_format *audio_format, +solaris_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) { - struct solaris_output *so = data; + struct solaris_output *so = (struct solaris_output *)ao; struct audio_info info; int ret, flags; @@ -135,17 +141,18 @@ solaris_output_open(void *data, struct audio_format *audio_format, } static void -solaris_output_close(void *data) +solaris_output_close(struct audio_output *ao) { - struct solaris_output *so = data; + struct solaris_output *so = (struct solaris_output *)ao; close(so->fd); } static size_t -solaris_output_play(void *data, const void *chunk, size_t size, GError **error) +solaris_output_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error) { - struct solaris_output *so = data; + struct solaris_output *so = (struct solaris_output *)ao; ssize_t nbytes; nbytes = write(so->fd, chunk, size); @@ -159,9 +166,9 @@ solaris_output_play(void *data, const void *chunk, size_t size, GError **error) } static void -solaris_output_cancel(void *data) +solaris_output_cancel(struct audio_output *ao) { - struct solaris_output *so = data; + struct solaris_output *so = (struct solaris_output *)ao; ioctl(so->fd, I_FLUSH); } diff --git a/src/output/winmm_output_plugin.c b/src/output/winmm_output_plugin.c index d11a23e6d..66e693dd4 100644 --- a/src/output/winmm_output_plugin.c +++ b/src/output/winmm_output_plugin.c @@ -38,6 +38,8 @@ struct winmm_buffer { }; struct winmm_output { + struct audio_output base; + UINT device_id; HWAVEOUT handle; @@ -101,30 +103,34 @@ get_device_id(const char *device_name) return WAVE_MAPPER; } -static void * -winmm_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, - G_GNUC_UNUSED const struct config_param *param, - G_GNUC_UNUSED GError **error) +static struct audio_output * +winmm_output_init(const struct config_param *param, GError **error_r) { struct winmm_output *wo = g_new(struct winmm_output, 1); + if (!ao_base_init(&wo->base, &winmm_output_plugin, param, error_r)) { + g_free(wo); + return NULL; + } + const char *device = config_get_block_string(param, "device", NULL); wo->device_id = get_device_id(device); - return wo; + return &wo->base; } static void -winmm_output_finish(void *data) +winmm_output_finish(struct audio_output *ao) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; + ao_base_finish(&wo->base); g_free(wo); } static bool -winmm_output_open(void *data, struct audio_format *audio_format, +winmm_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error_r) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; wo->event = CreateEvent(NULL, false, false, NULL); if (wo->event == NULL) { @@ -180,9 +186,9 @@ winmm_output_open(void *data, struct audio_format *audio_format, } static void -winmm_output_close(void *data) +winmm_output_close(struct audio_output *ao) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; for (unsigned i = 0; i < G_N_ELEMENTS(wo->buffers); ++i) pcm_buffer_deinit(&wo->buffers[i].buffer); @@ -253,9 +259,9 @@ winmm_drain_buffer(struct winmm_output *wo, struct winmm_buffer *buffer, } static size_t -winmm_output_play(void *data, const void *chunk, size_t size, GError **error_r) +winmm_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error_r) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; /* get the next buffer from the ring and prepare it */ struct winmm_buffer *buffer = &wo->buffers[wo->next_buffer]; @@ -308,18 +314,18 @@ winmm_stop(struct winmm_output *wo) } static void -winmm_output_drain(void *data) +winmm_output_drain(struct audio_output *ao) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; if (!winmm_drain_all_buffers(wo, NULL)) winmm_stop(wo); } static void -winmm_output_cancel(void *data) +winmm_output_cancel(struct audio_output *ao) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; winmm_stop(wo); } diff --git a/src/output_all.c b/src/output_all.c index 7f4694a8b..f56cd04ee 100644 --- a/src/output_all.c +++ b/src/output_all.c @@ -41,7 +41,7 @@ static struct audio_format input_audio_format; -static struct audio_output *audio_outputs; +static struct audio_output **audio_outputs; static unsigned int num_audio_outputs; /** @@ -70,7 +70,9 @@ audio_output_get(unsigned i) { assert(i < num_audio_outputs); - return &audio_outputs[i]; + assert(audio_outputs[i] != NULL); + + return audio_outputs[i]; } struct audio_output * @@ -110,11 +112,10 @@ audio_output_all_init(struct player_control *pc) notify_init(&audio_output_client_notify); num_audio_outputs = audio_output_config_count(); - audio_outputs = g_new(struct audio_output, num_audio_outputs); + audio_outputs = g_new(struct audio_output *, num_audio_outputs); for (i = 0; i < num_audio_outputs; i++) { - struct audio_output *output = &audio_outputs[i]; unsigned int j; param = config_get_next_param(CONF_AUDIO_OUTPUT, param); @@ -122,7 +123,8 @@ audio_output_all_init(struct player_control *pc) /* only allow param to be NULL if there just one audioOutput */ assert(param || (num_audio_outputs == 1)); - if (!audio_output_init(output, param, pc, &error)) { + struct audio_output *output = audio_output_new(param, pc, &error); + if (output == NULL) { if (param != NULL) MPD_ERROR("line %i: %s", param->line, error->message); @@ -130,9 +132,11 @@ audio_output_all_init(struct player_control *pc) MPD_ERROR("%s", error->message); } + audio_outputs[i] = output; + /* require output names to be unique: */ for (j = 0; j < i; j++) { - if (!strcmp(output->name, audio_outputs[j].name)) { + if (!strcmp(output->name, audio_outputs[j]->name)) { MPD_ERROR("output devices with identical " "names: %s\n", output->name); } @@ -146,8 +150,8 @@ audio_output_all_finish(void) unsigned int i; for (i = 0; i < num_audio_outputs; i++) { - audio_output_disable(&audio_outputs[i]); - audio_output_finish(&audio_outputs[i]); + audio_output_disable(audio_outputs[i]); + audio_output_finish(audio_outputs[i]); } g_free(audio_outputs); @@ -161,7 +165,7 @@ void audio_output_all_enable_disable(void) { for (unsigned i = 0; i < num_audio_outputs; i++) { - struct audio_output *ao = &audio_outputs[i]; + struct audio_output *ao = audio_outputs[i]; bool enabled; g_mutex_lock(ao->mutex); @@ -185,7 +189,7 @@ static bool audio_output_all_finished(void) { for (unsigned i = 0; i < num_audio_outputs; ++i) { - struct audio_output *ao = &audio_outputs[i]; + struct audio_output *ao = audio_outputs[i]; bool not_finished; g_mutex_lock(ao->mutex); @@ -213,7 +217,7 @@ static void audio_output_allow_play_all(void) { for (unsigned i = 0; i < num_audio_outputs; ++i) - audio_output_allow_play(&audio_outputs[i]); + audio_output_allow_play(audio_outputs[i]); } static void @@ -238,7 +242,7 @@ static void audio_output_all_reset_reopen(void) { for (unsigned i = 0; i < num_audio_outputs; ++i) { - struct audio_output *ao = &audio_outputs[i]; + struct audio_output *ao = audio_outputs[i]; audio_output_reset_reopen(ao); } @@ -259,7 +263,7 @@ audio_output_all_update(void) return false; for (i = 0; i < num_audio_outputs; ++i) - ret = audio_output_update(&audio_outputs[i], + ret = audio_output_update(audio_outputs[i], &input_audio_format, g_mp) || ret; return ret; @@ -283,7 +287,7 @@ audio_output_all_play(struct music_chunk *chunk) music_pipe_push(g_mp, chunk); for (i = 0; i < num_audio_outputs; ++i) - audio_output_play(&audio_outputs[i]); + audio_output_play(audio_outputs[i]); return true; } @@ -322,10 +326,10 @@ audio_output_all_open(const struct audio_format *audio_format, audio_output_all_update(); for (i = 0; i < num_audio_outputs; ++i) { - if (audio_outputs[i].enabled) + if (audio_outputs[i]->enabled) enabled = true; - if (audio_outputs[i].open) + if (audio_outputs[i]->open) ret = true; } @@ -369,7 +373,7 @@ static bool chunk_is_consumed(const struct music_chunk *chunk) { for (unsigned i = 0; i < num_audio_outputs; ++i) { - const struct audio_output *ao = &audio_outputs[i]; + const struct audio_output *ao = audio_outputs[i]; bool consumed; g_mutex_lock(ao->mutex); @@ -394,7 +398,7 @@ clear_tail_chunk(G_GNUC_UNUSED const struct music_chunk *chunk, bool *locked) assert(music_pipe_contains(g_mp, chunk)); for (unsigned i = 0; i < num_audio_outputs; ++i) { - struct audio_output *ao = &audio_outputs[i]; + struct audio_output *ao = audio_outputs[i]; /* this mutex will be unlocked by the caller when it's ready */ @@ -451,7 +455,7 @@ audio_output_all_check(void) by clear_tail_chunk() */ for (unsigned i = 0; i < num_audio_outputs; ++i) if (locked[i]) - g_mutex_unlock(audio_outputs[i].mutex); + g_mutex_unlock(audio_outputs[i]->mutex); /* return the chunk to the buffer */ music_buffer_return(g_music_buffer, shifted); @@ -484,7 +488,7 @@ audio_output_all_pause(void) audio_output_all_update(); for (i = 0; i < num_audio_outputs; ++i) - audio_output_pause(&audio_outputs[i]); + audio_output_pause(audio_outputs[i]); audio_output_wait_all(); } @@ -493,7 +497,7 @@ void audio_output_all_drain(void) { for (unsigned i = 0; i < num_audio_outputs; ++i) - audio_output_drain_async(&audio_outputs[i]); + audio_output_drain_async(audio_outputs[i]); audio_output_wait_all(); } @@ -506,7 +510,7 @@ audio_output_all_cancel(void) /* send the cancel() command to all audio outputs */ for (i = 0; i < num_audio_outputs; ++i) - audio_output_cancel(&audio_outputs[i]); + audio_output_cancel(audio_outputs[i]); audio_output_wait_all(); @@ -531,7 +535,7 @@ audio_output_all_close(void) unsigned int i; for (i = 0; i < num_audio_outputs; ++i) - audio_output_close(&audio_outputs[i]); + audio_output_close(audio_outputs[i]); if (g_mp != NULL) { assert(g_music_buffer != NULL); @@ -554,7 +558,7 @@ audio_output_all_release(void) unsigned int i; for (i = 0; i < num_audio_outputs; ++i) - audio_output_release(&audio_outputs[i]); + audio_output_release(audio_outputs[i]); if (g_mp != NULL) { assert(g_music_buffer != NULL); diff --git a/src/output_api.h b/src/output_api.h index 302a0cdc9..dfeef3518 100644 --- a/src/output_api.h +++ b/src/output_api.h @@ -21,6 +21,7 @@ #define MPD_OUTPUT_API_H #include "output_plugin.h" +#include "output_internal.h" #include "audio_format.h" #include "tag.h" #include "conf.h" diff --git a/src/output_control.c b/src/output_control.c index 7ddcb8b19..69553145a 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -335,5 +335,5 @@ void audio_output_finish(struct audio_output *ao) ao->thread = NULL; } - audio_output_destruct(ao); + audio_output_free(ao); } diff --git a/src/output_control.h b/src/output_control.h index f58a113e6..874a53518 100644 --- a/src/output_control.h +++ b/src/output_control.h @@ -37,11 +37,6 @@ audio_output_quark(void) return g_quark_from_static_string("audio_output"); } -bool -audio_output_init(struct audio_output *ao, const struct config_param *param, - struct player_control *pc, - GError **error_r); - /** * Enables the device. */ diff --git a/src/output_finish.c b/src/output_finish.c index ac7f7e0c2..e11b43675 100644 --- a/src/output_finish.c +++ b/src/output_finish.c @@ -26,7 +26,7 @@ #include <assert.h> void -audio_output_destruct(struct audio_output *ao) +ao_base_finish(struct audio_output *ao) { assert(!ao->open); assert(ao->fail_timer == NULL); @@ -35,8 +35,6 @@ audio_output_destruct(struct audio_output *ao) if (ao->mixer != NULL) mixer_free(ao->mixer); - ao_plugin_finish(ao->plugin, ao->data); - g_cond_free(ao->cond); g_mutex_free(ao->mutex); @@ -50,3 +48,13 @@ audio_output_destruct(struct audio_output *ao) pcm_buffer_deinit(&ao->cross_fade_buffer); } + +void +audio_output_free(struct audio_output *ao) +{ + assert(!ao->open); + assert(ao->fail_timer == NULL); + assert(ao->thread == NULL); + + ao_plugin_finish(ao); +} diff --git a/src/output_init.c b/src/output_init.c index c52dcc8cd..51fe36c47 100644 --- a/src/output_init.c +++ b/src/output_init.c @@ -94,7 +94,8 @@ audio_output_mixer_type(const struct config_param *param) } static struct mixer * -audio_output_load_mixer(void *ao, const struct config_param *param, +audio_output_load_mixer(struct audio_output *ao, + const struct config_param *param, const struct mixer_plugin *plugin, struct filter *filter_chain, GError **error_r) @@ -126,33 +127,22 @@ audio_output_load_mixer(void *ao, const struct config_param *param, } bool -audio_output_init(struct audio_output *ao, const struct config_param *param, - struct player_control *pc, - GError **error_r) +ao_base_init(struct audio_output *ao, + const struct audio_output_plugin *plugin, + const struct config_param *param, GError **error_r) { assert(ao != NULL); - assert(pc != NULL); + assert(plugin != NULL); + assert(plugin->finish != NULL); + assert(plugin->open != NULL); + assert(plugin->close != NULL); + assert(plugin->play != NULL); - const struct audio_output_plugin *plugin = NULL; GError *error = NULL; if (param) { const char *p; - p = config_get_block_string(param, AUDIO_OUTPUT_TYPE, NULL); - if (p == NULL) { - g_set_error(error_r, audio_output_quark(), 0, - "Missing \"type\" configuration"); - return false; - } - - plugin = audio_output_plugin_get(p); - if (plugin == NULL) { - g_set_error(error_r, audio_output_quark(), 0, - "No such audio output plugin: %s", p); - return false; - } - ao->name = config_get_block_string(param, AUDIO_OUTPUT_NAME, NULL); if (ao->name == NULL) { @@ -172,16 +162,6 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, } else audio_format_clear(&ao->config_audio_format); } else { - g_warning("No \"%s\" defined in config file\n", - CONF_AUDIO_OUTPUT); - - plugin = audio_output_detect(error_r); - if (plugin == NULL) - return false; - - g_message("Successfully detected a %s audio device", - plugin->name); - ao->name = "default detected output"; audio_format_clear(&ao->config_audio_format); @@ -203,29 +183,6 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, ao->filter = filter_chain_new(); assert(ao->filter != NULL); - /* create the replay_gain filter */ - - const char *replay_gain_handler = - config_get_block_string(param, "replay_gain_handler", - "software"); - - if (strcmp(replay_gain_handler, "none") != 0) { - ao->replay_gain_filter = filter_new(&replay_gain_filter_plugin, - param, NULL); - assert(ao->replay_gain_filter != NULL); - - ao->replay_gain_serial = 0; - - ao->other_replay_gain_filter = filter_new(&replay_gain_filter_plugin, - param, NULL); - assert(ao->other_replay_gain_filter != NULL); - - ao->other_replay_gain_serial = 0; - } else { - ao->replay_gain_filter = NULL; - ao->other_replay_gain_filter = NULL; - } - /* create the normalization filter (if configured) */ if (config_get_bool(CONF_VOLUME_NORMALIZATION, false)) { @@ -254,16 +211,54 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, ao->command = AO_COMMAND_NONE; ao->mutex = g_mutex_new(); ao->cond = g_cond_new(); - ao->player_control = pc; - ao->data = ao_plugin_init(plugin, - &ao->config_audio_format, - param, error_r); - if (ao->data == NULL) - return false; + ao->mixer = NULL; + + /* the "convert" filter must be the last one in the chain */ + + ao->convert_filter = filter_new(&convert_filter_plugin, NULL, NULL); + assert(ao->convert_filter != NULL); + + filter_chain_append(ao->filter, ao->convert_filter); + + /* done */ + + return true; +} + +static bool +audio_output_setup(struct audio_output *ao, const struct config_param *param, + GError **error_r) +{ + + /* create the replay_gain filter */ - ao->mixer = audio_output_load_mixer(ao->data, param, - plugin->mixer_plugin, + const char *replay_gain_handler = + config_get_block_string(param, "replay_gain_handler", + "software"); + + if (strcmp(replay_gain_handler, "none") != 0) { + ao->replay_gain_filter = filter_new(&replay_gain_filter_plugin, + param, NULL); + assert(ao->replay_gain_filter != NULL); + + ao->replay_gain_serial = 0; + + ao->other_replay_gain_filter = filter_new(&replay_gain_filter_plugin, + param, NULL); + assert(ao->other_replay_gain_filter != NULL); + + ao->other_replay_gain_serial = 0; + } else { + ao->replay_gain_filter = NULL; + ao->other_replay_gain_filter = NULL; + } + + /* set up the mixer */ + + GError *error = NULL; + ao->mixer = audio_output_load_mixer(ao, param, + ao->plugin->mixer_plugin, ao->filter, &error); if (ao->mixer == NULL && error != NULL) { g_warning("Failed to initialize hardware mixer for '%s': %s", @@ -286,14 +281,53 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, return false; } - /* the "convert" filter must be the last one in the chain */ + return true; +} - ao->convert_filter = filter_new(&convert_filter_plugin, NULL, NULL); - assert(ao->convert_filter != NULL); +struct audio_output * +audio_output_new(const struct config_param *param, + struct player_control *pc, + GError **error_r) +{ + const struct audio_output_plugin *plugin; - filter_chain_append(ao->filter, ao->convert_filter); + if (param) { + const char *p; - /* done */ + p = config_get_block_string(param, AUDIO_OUTPUT_TYPE, NULL); + if (p == NULL) { + g_set_error(error_r, audio_output_quark(), 0, + "Missing \"type\" configuration"); + return false; + } - return true; + plugin = audio_output_plugin_get(p); + if (plugin == NULL) { + g_set_error(error_r, audio_output_quark(), 0, + "No such audio output plugin: %s", p); + return false; + } + } else { + g_warning("No \"%s\" defined in config file\n", + CONF_AUDIO_OUTPUT); + + plugin = audio_output_detect(error_r); + if (plugin == NULL) + return false; + + g_message("Successfully detected a %s audio device", + plugin->name); + } + + struct audio_output *ao = ao_plugin_init(plugin, param, error_r); + if (ao == NULL) + return NULL; + + if (!audio_output_setup(ao, param, error_r)) { + ao_plugin_finish(ao); + return NULL; + } + + ao->player_control = pc; + return ao; } diff --git a/src/output_internal.h b/src/output_internal.h index eba3aed91..9d975d789 100644 --- a/src/output_internal.h +++ b/src/output_internal.h @@ -27,6 +27,8 @@ #include <time.h> +struct config_param; + enum audio_output_command { AO_COMMAND_NONE = 0, AO_COMMAND_ENABLE, @@ -64,12 +66,6 @@ struct audio_output { const struct audio_output_plugin *plugin; /** - * The plugin's internal data. It is passed to every plugin - * method. - */ - void *data; - - /** * The #mixer object associated with this audio output device. * May be NULL if none is available, or if software volume is * configured. @@ -254,7 +250,20 @@ audio_output_command_is_finished(const struct audio_output *ao) return ao->command == AO_COMMAND_NONE; } +struct audio_output * +audio_output_new(const struct config_param *param, + struct player_control *pc, + GError **error_r); + +bool +ao_base_init(struct audio_output *ao, + const struct audio_output_plugin *plugin, + const struct config_param *param, GError **error_r); + +void +ao_base_finish(struct audio_output *ao); + void -audio_output_destruct(struct audio_output *ao); +audio_output_free(struct audio_output *ao); #endif diff --git a/src/output_plugin.c b/src/output_plugin.c new file mode 100644 index 000000000..1e41f25f8 --- /dev/null +++ b/src/output_plugin.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "output_plugin.h" +#include "output_internal.h" + +struct audio_output * +ao_plugin_init(const struct audio_output_plugin *plugin, + const struct config_param *param, + GError **error) +{ + assert(plugin != NULL); + assert(plugin->init != NULL); + + return plugin->init(param, error); +} + +void +ao_plugin_finish(struct audio_output *ao) +{ + ao->plugin->finish(ao); +} + +bool +ao_plugin_enable(struct audio_output *ao, GError **error_r) +{ + return ao->plugin->enable != NULL + ? ao->plugin->enable(ao, error_r) + : true; +} + +void +ao_plugin_disable(struct audio_output *ao) +{ + if (ao->plugin->disable != NULL) + ao->plugin->disable(ao); +} + +bool +ao_plugin_open(struct audio_output *ao, struct audio_format *audio_format, + GError **error) +{ + return ao->plugin->open(ao, audio_format, error); +} + +void +ao_plugin_close(struct audio_output *ao) +{ + ao->plugin->close(ao); +} + +unsigned +ao_plugin_delay(struct audio_output *ao) +{ + return ao->plugin->delay != NULL + ? ao->plugin->delay(ao) + : 0; +} + +void +ao_plugin_send_tag(struct audio_output *ao, const struct tag *tag) +{ + if (ao->plugin->send_tag != NULL) + ao->plugin->send_tag(ao, tag); +} + +size_t +ao_plugin_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error) +{ + return ao->plugin->play(ao, chunk, size, error); +} + +void +ao_plugin_drain(struct audio_output *ao) +{ + if (ao->plugin->drain != NULL) + ao->plugin->drain(ao); +} + +void +ao_plugin_cancel(struct audio_output *ao) +{ + if (ao->plugin->cancel != NULL) + ao->plugin->cancel(ao); +} + +bool +ao_plugin_pause(struct audio_output *ao) +{ + return ao->plugin->pause != NULL && ao->plugin->pause(ao); +} diff --git a/src/output_plugin.h b/src/output_plugin.h index 72b519d13..209ca6221 100644 --- a/src/output_plugin.h +++ b/src/output_plugin.h @@ -48,8 +48,6 @@ struct audio_output_plugin { * Configure and initialize the device, but do not open it * yet. * - * @param audio_format the configured audio format, or NULL if - * none is configured * @param param the configuration section, or NULL if there is * no configuration * @param error location to store the error occurring, or NULL @@ -57,14 +55,13 @@ struct audio_output_plugin { * @return NULL on error, or an opaque pointer to the plugin's * data */ - void *(*init)(const struct audio_format *audio_format, - const struct config_param *param, - GError **error); + struct audio_output *(*init)(const struct config_param *param, + GError **error); /** * Free resources allocated by this device. */ - void (*finish)(void *data); + void (*finish)(struct audio_output *data); /** * Enable the device. This may allocate resources, preparing @@ -76,13 +73,13 @@ struct audio_output_plugin { * NULL to ignore errors * @return true on success, false on error */ - bool (*enable)(void *data, GError **error_r); + bool (*enable)(struct audio_output *data, GError **error_r); /** * Disables the device. It is closed before this method is * called. */ - void (*disable)(void *data); + void (*disable)(struct audio_output *data); /** * Really open the device. @@ -92,13 +89,13 @@ struct audio_output_plugin { * @param error location to store the error occurring, or NULL * to ignore errors */ - bool (*open)(void *data, struct audio_format *audio_format, + bool (*open)(struct audio_output *data, struct audio_format *audio_format, GError **error); /** * Close the device. */ - void (*close)(void *data); + void (*close)(struct audio_output *data); /** * Returns a positive number if the output thread shall delay @@ -108,13 +105,13 @@ struct audio_output_plugin { * * @return the number of milliseconds to wait */ - unsigned (*delay)(void *data); + unsigned (*delay)(struct audio_output *data); /** * Display metadata for the next chunk. Optional method, * because not all devices can display metadata. */ - void (*send_tag)(void *data, const struct tag *tag); + void (*send_tag)(struct audio_output *data, const struct tag *tag); /** * Play a chunk of audio data. @@ -123,19 +120,20 @@ struct audio_output_plugin { * to ignore errors * @return the number of bytes played, or 0 on error */ - size_t (*play)(void *data, const void *chunk, size_t size, + size_t (*play)(struct audio_output *data, + const void *chunk, size_t size, GError **error); /** * Wait until the device has finished playing. */ - void (*drain)(void *data); + void (*drain)(struct audio_output *data); /** * Try to cancel data which may still be in the device's * buffers. */ - void (*cancel)(void *data); + void (*cancel)(struct audio_output *data); /** * Pause the device. If supported, it may perform a special @@ -148,7 +146,7 @@ struct audio_output_plugin { * @return false on error (output will be closed then), true * for continue to pause */ - bool (*pause)(void *data); + bool (*pause)(struct audio_output *data); /** * The mixer plugin associated with this output plugin. This @@ -167,95 +165,46 @@ ao_plugin_test_default_device(const struct audio_output_plugin *plugin) : false; } -static inline void * +G_GNUC_MALLOC +struct audio_output * ao_plugin_init(const struct audio_output_plugin *plugin, - const struct audio_format *audio_format, const struct config_param *param, - GError **error) -{ - return plugin->init(audio_format, param, error); -} + GError **error); -static inline void -ao_plugin_finish(const struct audio_output_plugin *plugin, void *data) -{ - plugin->finish(data); -} +void +ao_plugin_finish(struct audio_output *ao); -static inline bool -ao_plugin_enable(const struct audio_output_plugin *plugin, void *data, - GError **error_r) -{ - return plugin->enable != NULL - ? plugin->enable(data, error_r) - : true; -} +bool +ao_plugin_enable(struct audio_output *ao, GError **error_r); -static inline void -ao_plugin_disable(const struct audio_output_plugin *plugin, void *data) -{ - if (plugin->disable != NULL) - plugin->disable(data); -} +void +ao_plugin_disable(struct audio_output *ao); -static inline bool -ao_plugin_open(const struct audio_output_plugin *plugin, - void *data, struct audio_format *audio_format, - GError **error) -{ - return plugin->open(data, audio_format, error); -} +bool +ao_plugin_open(struct audio_output *ao, struct audio_format *audio_format, + GError **error); -static inline void -ao_plugin_close(const struct audio_output_plugin *plugin, void *data) -{ - plugin->close(data); -} +void +ao_plugin_close(struct audio_output *ao); -static inline unsigned -ao_plugin_delay(const struct audio_output_plugin *plugin, void *data) -{ - return plugin->delay != NULL - ? plugin->delay(data) - : 0; -} +G_GNUC_PURE +unsigned +ao_plugin_delay(struct audio_output *ao); -static inline void -ao_plugin_send_tag(const struct audio_output_plugin *plugin, - void *data, const struct tag *tag) -{ - if (plugin->send_tag != NULL) - plugin->send_tag(data, tag); -} +void +ao_plugin_send_tag(struct audio_output *ao, const struct tag *tag); -static inline size_t -ao_plugin_play(const struct audio_output_plugin *plugin, - void *data, const void *chunk, size_t size, - GError **error) -{ - return plugin->play(data, chunk, size, error); -} +size_t +ao_plugin_play(struct audio_output *ao, const void *chunk, size_t size, + GError **error); -static inline void -ao_plugin_drain(const struct audio_output_plugin *plugin, void *data) -{ - if (plugin->drain != NULL) - plugin->drain(data); -} +void +ao_plugin_drain(struct audio_output *ao); -static inline void -ao_plugin_cancel(const struct audio_output_plugin *plugin, void *data) -{ - if (plugin->cancel != NULL) - plugin->cancel(data); -} +void +ao_plugin_cancel(struct audio_output *ao); -static inline bool -ao_plugin_pause(const struct audio_output_plugin *plugin, void *data) -{ - return plugin->pause != NULL - ? plugin->pause(data) - : false; -} +bool +ao_plugin_pause(struct audio_output *ao); #endif diff --git a/src/output_thread.c b/src/output_thread.c index c36ba5f4f..e194edc92 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -60,7 +60,7 @@ ao_enable(struct audio_output *ao) return true; g_mutex_unlock(ao->mutex); - success = ao_plugin_enable(ao->plugin, ao->data, &error); + success = ao_plugin_enable(ao, &error); g_mutex_lock(ao->mutex); if (!success) { g_warning("Failed to enable \"%s\" [%s]: %s\n", @@ -86,7 +86,7 @@ ao_disable(struct audio_output *ao) ao->really_enabled = false; g_mutex_unlock(ao->mutex); - ao_plugin_disable(ao->plugin, ao->data); + ao_plugin_disable(ao); g_mutex_lock(ao->mutex); } } @@ -175,9 +175,7 @@ ao_open(struct audio_output *ao) &ao->config_audio_format); g_mutex_unlock(ao->mutex); - success = ao_plugin_open(ao->plugin, ao->data, - &ao->out_audio_format, - &error); + success = ao_plugin_open(ao, &ao->out_audio_format, &error); g_mutex_lock(ao->mutex); assert(!ao->open); @@ -221,11 +219,11 @@ ao_close(struct audio_output *ao, bool drain) g_mutex_unlock(ao->mutex); if (drain) - ao_plugin_drain(ao->plugin, ao->data); + ao_plugin_drain(ao); else - ao_plugin_cancel(ao->plugin, ao->data); + ao_plugin_cancel(ao); - ao_plugin_close(ao->plugin, ao->data); + ao_plugin_close(ao); ao_filter_close(ao); g_mutex_lock(ao->mutex); @@ -257,7 +255,7 @@ ao_reopen_filter(struct audio_output *ao) ao->fail_timer = g_timer_new(); g_mutex_unlock(ao->mutex); - ao_plugin_close(ao->plugin, ao->data); + ao_plugin_close(ao); g_mutex_lock(ao->mutex); return; @@ -302,7 +300,7 @@ static bool ao_wait(struct audio_output *ao) { while (true) { - unsigned delay = ao_plugin_delay(ao->plugin, ao->data); + unsigned delay = ao_plugin_delay(ao); if (delay == 0) return true; @@ -434,7 +432,7 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) if (chunk->tag != NULL) { g_mutex_unlock(ao->mutex); - ao_plugin_send_tag(ao->plugin, ao->data, chunk->tag); + ao_plugin_send_tag(ao, chunk->tag); g_mutex_lock(ao->mutex); } @@ -456,8 +454,7 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) break; g_mutex_unlock(ao->mutex); - nbytes = ao_plugin_play(ao->plugin, ao->data, data, size, - &error); + nbytes = ao_plugin_play(ao, data, size, &error); g_mutex_lock(ao->mutex); if (nbytes == 0) { /* play()==0 means failure */ @@ -547,7 +544,7 @@ static void ao_pause(struct audio_output *ao) bool ret; g_mutex_unlock(ao->mutex); - ao_plugin_cancel(ao->plugin, ao->data); + ao_plugin_cancel(ao); g_mutex_lock(ao->mutex); ao->pause = true; @@ -558,7 +555,7 @@ static void ao_pause(struct audio_output *ao) break; g_mutex_unlock(ao->mutex); - ret = ao_plugin_pause(ao->plugin, ao->data); + ret = ao_plugin_pause(ao); g_mutex_lock(ao->mutex); if (!ret) { @@ -632,7 +629,7 @@ static gpointer audio_output_task(gpointer arg) assert(music_pipe_peek(ao->pipe) == NULL); g_mutex_unlock(ao->mutex); - ao_plugin_drain(ao->plugin, ao->data); + ao_plugin_drain(ao); g_mutex_lock(ao->mutex); } @@ -644,7 +641,7 @@ static gpointer audio_output_task(gpointer arg) if (ao->open) { g_mutex_unlock(ao->mutex); - ao_plugin_cancel(ao->plugin, ao->data); + ao_plugin_cancel(ao); g_mutex_lock(ao->mutex); } diff --git a/test/run_output.c b/test/run_output.c index c1d7a8120..5e688f2c7 100644 --- a/test/run_output.c +++ b/test/run_output.c @@ -94,11 +94,10 @@ find_named_config_block(const char *block, const char *name) return NULL; } -static bool -load_audio_output(struct audio_output *ao, const char *name) +static struct audio_output * +load_audio_output(const char *name) { const struct config_param *param; - bool success; GError *error = NULL; param = find_named_config_block(CONF_AUDIO_OUTPUT, name); @@ -109,13 +108,14 @@ load_audio_output(struct audio_output *ao, const char *name) static struct player_control dummy_player_control; - success = audio_output_init(ao, param, &dummy_player_control, &error); - if (!success) { + struct audio_output *ao = + audio_output_new(param, &dummy_player_control, &error); + if (ao == NULL) { g_printerr("%s\n", error->message); g_error_free(error); } - return success; + return ao; } static bool @@ -124,7 +124,7 @@ run_output(struct audio_output *ao, struct audio_format *audio_format) /* open the audio output */ GError *error = NULL; - if (!ao_plugin_open(ao->plugin, ao->data, audio_format, &error)) { + if (!ao_plugin_open(ao, audio_format, &error)) { g_printerr("Failed to open audio output: %s\n", error->message); g_error_free(error); @@ -153,11 +153,11 @@ run_output(struct audio_output *ao, struct audio_format *audio_format) size_t play_length = (length / frame_size) * frame_size; if (play_length > 0) { - size_t consumed = ao_plugin_play(ao->plugin, ao->data, + size_t consumed = ao_plugin_play(ao, buffer, play_length, &error); if (consumed == 0) { - ao_plugin_close(ao->plugin, ao->data); + ao_plugin_close(ao); g_printerr("Failed to play: %s\n", error->message); g_error_free(error); @@ -172,13 +172,12 @@ run_output(struct audio_output *ao, struct audio_format *audio_format) } } - ao_plugin_close(ao->plugin, ao->data); + ao_plugin_close(ao); return true; } int main(int argc, char **argv) { - struct audio_output ao; struct audio_format audio_format; bool success; GError *error = NULL; @@ -211,7 +210,8 @@ int main(int argc, char **argv) /* initialize the audio output */ - if (!load_audio_output(&ao, argv[2])) + struct audio_output *ao = load_audio_output(argv[2]); + if (ao == NULL) return 1; /* parse the audio format */ @@ -229,11 +229,11 @@ int main(int argc, char **argv) /* do it */ - success = run_output(&ao, &audio_format); + success = run_output(ao, &audio_format); /* cleanup and exit */ - audio_output_destruct(&ao); + audio_output_free(ao); io_thread_deinit(); |