Commit acc4a0ba authored by Max Kellermann's avatar Max Kellermann

output: make "struct audio_output" opaque for output plugins

We have eliminated direct accesses to the audio_output struct from the all output plugins. Make it opaque for them, and move its real declaration to output_internal.h, similar to decoder_internal.h. Pass the opaque structure to plugin.init() only, which will return the plugin's data pointer on success, and NULL on failure. This data pointer will be passed to all other methods instead of the audio_output struct.
parent 63fb1efb
......@@ -35,6 +35,7 @@ mpd_headers = \
ack.h \
audio.h \
audioOutput.h \
output_internal.h \
output_api.h \
output_list.h \
output_thread.h \
......
......@@ -20,6 +20,7 @@
#include "audio_format.h"
#include "output_api.h"
#include "output_control.h"
#include "output_internal.h"
#include "log.h"
#include "path.h"
#include "client.h"
......
......@@ -72,9 +72,9 @@ static void freeAlsaData(AlsaData * ad)
free(ad);
}
static int alsa_initDriver(struct audio_output *audioOutput,
mpd_unused const struct audio_format *audio_format,
ConfigParam * param)
static void *alsa_initDriver(mpd_unused struct audio_output *ao,
mpd_unused const struct audio_format *audio_format,
ConfigParam * param)
{
/* no need for pthread_once thread-safety when reading config */
static int free_global_registered;
......@@ -98,14 +98,13 @@ static int alsa_initDriver(struct audio_output *audioOutput,
if ((bp = getBlockParam(param, "period_time")))
ad->period_time = atoi(bp->value);
}
audioOutput->data = ad;
return 0;
return ad;
}
static void alsa_finishDriver(struct audio_output *audioOutput)
static void alsa_finishDriver(void *data)
{
AlsaData *ad = audioOutput->data;
AlsaData *ad = data;
freeAlsaData(ad);
}
......@@ -137,10 +136,9 @@ static snd_pcm_format_t get_bitformat(const struct audio_format *af)
return SND_PCM_FORMAT_UNKNOWN;
}
static int alsa_openDevice(struct audio_output *audioOutput,
struct audio_format *audioFormat)
static int alsa_openDevice(void *data, struct audio_format *audioFormat)
{
AlsaData *ad = audioOutput->data;
AlsaData *ad = data;
snd_pcm_format_t bitformat;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
......@@ -351,16 +349,16 @@ static int alsa_errorRecovery(AlsaData * ad, int err)
return err;
}
static void alsa_dropBufferedAudio(struct audio_output *audioOutput)
static void alsa_dropBufferedAudio(void *data)
{
AlsaData *ad = audioOutput->data;
AlsaData *ad = data;
alsa_errorRecovery(ad, snd_pcm_drop(ad->pcmHandle));
}
static void alsa_closeDevice(struct audio_output *audioOutput)
static void alsa_closeDevice(void *data)
{
AlsaData *ad = audioOutput->data;
AlsaData *ad = data;
if (ad->pcmHandle) {
if (snd_pcm_state(ad->pcmHandle) == SND_PCM_STATE_RUNNING) {
......@@ -371,10 +369,9 @@ static void alsa_closeDevice(struct audio_output *audioOutput)
}
}
static int alsa_playAudio(struct audio_output *audioOutput,
const char *playChunk, size_t size)
static int alsa_playAudio(void *data, const char *playChunk, size_t size)
{
AlsaData *ad = audioOutput->data;
AlsaData *ad = data;
int ret;
size /= ad->sampleSize;
......@@ -395,7 +392,7 @@ static int alsa_playAudio(struct audio_output *audioOutput,
ERROR("closing ALSA device \"%s\" due to write "
"error: %s\n", ad->device,
snd_strerror(-errno));
alsa_closeDevice(audioOutput);
alsa_closeDevice(ad);
return -1;
}
continue;
......
......@@ -54,9 +54,9 @@ static void audioOutputAo_error(void)
}
}
static int audioOutputAo_initDriver(struct audio_output *audioOutput,
mpd_unused const struct audio_format *audio_format,
ConfigParam * param)
static void *audioOutputAo_initDriver(struct audio_output *ao,
mpd_unused const struct audio_format *audio_format,
ConfigParam * param)
{
ao_info *ai;
char *duplicated;
......@@ -69,8 +69,6 @@ static int audioOutputAo_initDriver(struct audio_output *audioOutput,
AoData *ad = newAoData();
BlockParam *blockParam;
audioOutput->data = ad;
if ((blockParam = getBlockParam(param, "write_size"))) {
ad->writeSize = strtol(blockParam->value, &test, 10);
if (*test != '\0') {
......@@ -100,7 +98,7 @@ static int audioOutputAo_initDriver(struct audio_output *audioOutput,
}
DEBUG("using ao driver \"%s\" for \"%s\"\n", ai->short_name,
audio_output_get_name(audioOutput));
audio_output_get_name(ao));
blockParam = getBlockParam(param, "options");
......@@ -138,7 +136,7 @@ static int audioOutputAo_initDriver(struct audio_output *audioOutput,
}
free(duplicated);
return 0;
return ad;
}
static void freeAoData(AoData * ad)
......@@ -147,9 +145,9 @@ static void freeAoData(AoData * ad)
free(ad);
}
static void audioOutputAo_finishDriver(struct audio_output *audioOutput)
static void audioOutputAo_finishDriver(void *data)
{
AoData *ad = (AoData *) audioOutput->data;
AoData *ad = (AoData *)data;
freeAoData(ad);
driverInitCount--;
......@@ -158,14 +156,14 @@ static void audioOutputAo_finishDriver(struct audio_output *audioOutput)
ao_shutdown();
}
static void audioOutputAo_dropBufferedAudio(mpd_unused struct audio_output *audioOutput)
static void audioOutputAo_dropBufferedAudio(mpd_unused void *data)
{
/* not supported by libao */
}
static void audioOutputAo_closeDevice(struct audio_output *audioOutput)
static void audioOutputAo_closeDevice(void *data)
{
AoData *ad = (AoData *) audioOutput->data;
AoData *ad = (AoData *)data;
if (ad->device) {
ao_close(ad->device);
......@@ -173,14 +171,14 @@ static void audioOutputAo_closeDevice(struct audio_output *audioOutput)
}
}
static int audioOutputAo_openDevice(struct audio_output *audioOutput,
static int audioOutputAo_openDevice(void *data,
struct audio_format *audio_format)
{
ao_sample_format format;
AoData *ad = (AoData *) audioOutput->data;
AoData *ad = (AoData *)data;
if (ad->device) {
audioOutputAo_closeDevice(audioOutput);
audioOutputAo_closeDevice(ad);
}
format.bits = audio_format->bits;
......@@ -213,11 +211,10 @@ static int ao_play_deconst(ao_device *device, const void *output_samples,
return ao_play(device, u.out, num_bytes);
}
static int audioOutputAo_play(struct audio_output *audioOutput,
const char *playChunk, size_t size)
static int audioOutputAo_play(void *data, const char *playChunk, size_t size)
{
AoData *ad = (AoData *)data;
size_t chunk_size;
AoData *ad = (AoData *) audioOutput->data;
if (ad->device == NULL)
return -1;
......@@ -229,7 +226,7 @@ static int audioOutputAo_play(struct audio_output *audioOutput,
if (ao_play_deconst(ad->device, playChunk, chunk_size) == 0) {
audioOutputAo_error();
ERROR("closing audio device due to write error\n");
audioOutputAo_closeDevice(audioOutput);
audioOutputAo_closeDevice(ad);
return -1;
}
......
......@@ -151,9 +151,9 @@ static int openFifo(FifoData *fd)
return 0;
}
static int fifo_initDriver(struct audio_output *audioOutput,
mpd_unused const struct audio_format *audio_format,
ConfigParam *param)
static void *fifo_initDriver(mpd_unused struct audio_output *ao,
mpd_unused const struct audio_format *audio_format,
ConfigParam *param)
{
FifoData *fd;
BlockParam *blockParam;
......@@ -173,28 +173,27 @@ static int fifo_initDriver(struct audio_output *audioOutput,
fd = newFifoData();
fd->path = path;
audioOutput->data = fd;
if (openFifo(fd) < 0) {
freeFifoData(fd);
return -1;
return NULL;
}
return 0;
return fd;
}
static void fifo_finishDriver(struct audio_output *audioOutput)
static void fifo_finishDriver(void *data)
{
FifoData *fd = (FifoData *)audioOutput->data;
FifoData *fd = (FifoData *)data;
closeFifo(fd);
freeFifoData(fd);
}
static int fifo_openDevice(struct audio_output *audioOutput,
static int fifo_openDevice(void *data,
struct audio_format *audio_format)
{
FifoData *fd = (FifoData *)audioOutput->data;
FifoData *fd = (FifoData *)data;
if (fd->timer)
timer_free(fd->timer);
......@@ -204,9 +203,9 @@ static int fifo_openDevice(struct audio_output *audioOutput,
return 0;
}
static void fifo_closeDevice(struct audio_output *audioOutput)
static void fifo_closeDevice(void *data)
{
FifoData *fd = (FifoData *)audioOutput->data;
FifoData *fd = (FifoData *)data;
if (fd->timer) {
timer_free(fd->timer);
......@@ -214,9 +213,9 @@ static void fifo_closeDevice(struct audio_output *audioOutput)
}
}
static void fifo_dropBufferedAudio(struct audio_output *audioOutput)
static void fifo_dropBufferedAudio(void *data)
{
FifoData *fd = (FifoData *)audioOutput->data;
FifoData *fd = (FifoData *)data;
char buf[FIFO_BUFFER_SIZE];
int bytes = 1;
......@@ -231,10 +230,10 @@ static void fifo_dropBufferedAudio(struct audio_output *audioOutput)
}
}
static int fifo_playAudio(struct audio_output *audioOutput,
static int fifo_playAudio(void *data,
const char *playChunk, size_t size)
{
FifoData *fd = (FifoData *)audioOutput->data;
FifoData *fd = (FifoData *)data;
size_t offset = 0;
ssize_t bytes;
......@@ -251,7 +250,7 @@ static int fifo_playAudio(struct audio_output *audioOutput,
switch (errno) {
case EAGAIN:
/* The pipe is full, so empty it */
fifo_dropBufferedAudio(audioOutput);
fifo_dropBufferedAudio(fd);
continue;
case EINTR:
continue;
......@@ -259,7 +258,7 @@ static int fifo_playAudio(struct audio_output *audioOutput,
ERROR("Closing FIFO output \"%s\" due to write error: "
"%s\n", fd->path, strerror(errno));
fifo_closeDevice(audioOutput);
fifo_closeDevice(fd);
return -1;
}
......
......@@ -29,6 +29,8 @@
static const size_t sample_size = sizeof(jack_default_audio_sample_t);
typedef struct _JackData {
struct audio_output *ao;
/* configuration */
const char *name;
const char *output_ports[2];
......@@ -90,9 +92,8 @@ static void freeJackClient(JackData *jd)
pthread_cond_destroy(&jd->play_audio);
}
static void freeJackData(struct audio_output *audioOutput)
static void freeJackData(JackData *jd)
{
JackData *jd = audioOutput->data;
int i;
assert(jd != NULL);
......@@ -111,15 +112,16 @@ static void freeJackData(struct audio_output *audioOutput)
free(jd);
}
static void jack_finishDriver(struct audio_output *audioOutput)
static void jack_finishDriver(void *data)
{
freeJackData(audioOutput);
JackData *jd = data;
freeJackData(jd);
DEBUG("disconnect_jack (pid=%d)\n", getpid ());
}
static int srate(mpd_unused jack_nframes_t rate, void *data)
{
JackData *jd = (JackData *) ((struct audio_output *) data)->data;
JackData *jd = (JackData *)data;
struct audio_format *audioFormat = jd->audio_format;
audioFormat->sampleRate = (int)jack_get_sample_rate(jd->client);
......@@ -182,11 +184,8 @@ static void shutdown_callback(void *arg)
jd->shutdown = 1;
}
static void set_audioformat(struct audio_output *audioOutput,
struct audio_format *audioFormat)
static void set_audioformat(JackData *jd, struct audio_format *audioFormat)
{
JackData *jd = audioOutput->data;
audioFormat->sampleRate = (int) jack_get_sample_rate(jd->client);
DEBUG("samplerate = %d\n", audioFormat->sampleRate);
audioFormat->channels = 2;
......@@ -201,9 +200,9 @@ static void error_callback(const char *msg)
ERROR("jack: %s\n", msg);
}
static int jack_initDriver(struct audio_output *audioOutput,
mpd_unused const struct audio_format *audio_format,
ConfigParam *param)
static void *jack_initDriver(struct audio_output *ao,
mpd_unused const struct audio_format *audio_format,
ConfigParam *param)
{
JackData *jd;
BlockParam *bp;
......@@ -211,11 +210,12 @@ static int jack_initDriver(struct audio_output *audioOutput,
int val;
char *cp = NULL;
audioOutput->data = newJackData();
jd = audioOutput->data;
jd = newJackData();
jd->ao = ao;
DEBUG("jack_initDriver (pid=%d)\n", getpid());
if ( ! param ) return 0;
if (param == NULL)
return jd;
if ( (bp = getBlockParam(param, "ports")) ) {
DEBUG("output_ports=%s\n", bp->value);
......@@ -261,7 +261,7 @@ static int jack_initDriver(struct audio_output *audioOutput,
DEBUG("name=%s\n", jd->name);
}
return 0;
return jd;
}
static int jack_testDefault(void)
......@@ -269,10 +269,8 @@ static int jack_testDefault(void)
return 0;
}
static int connect_jack(struct audio_output *audioOutput,
struct audio_format *audio_format)
static int connect_jack(JackData *jd, struct audio_format *audio_format)
{
JackData *jd = audioOutput->data;
const char **jports;
char *port_name;
......@@ -286,7 +284,7 @@ static int connect_jack(struct audio_output *audioOutput,
jack_set_error_function(error_callback);
jack_set_process_callback(jd->client, process, (void *)jd);
jack_set_sample_rate_callback(jd->client, (JackProcessCallback)srate,
(void *)audioOutput);
(void *)jd);
jack_on_shutdown(jd->client, shutdown_callback, (void *)jd);
if ( jack_activate(jd->client) ) {
......@@ -353,40 +351,39 @@ static int connect_jack(struct audio_output *audioOutput,
return 1;
}
static int jack_openDevice(struct audio_output *audioOutput,
static int jack_openDevice(void *data,
struct audio_format *audio_format)
{
JackData *jd = audioOutput->data;
JackData *jd = data;
assert(jd != NULL);
if (jd->client == NULL && connect_jack(audioOutput,
audio_format) < 0) {
if (jd->client == NULL && connect_jack(jd, audio_format) < 0) {
freeJackClient(jd);
return -1;
}
set_audioformat(audioOutput, audio_format);
set_audioformat(jd, audio_format);
DEBUG("jack_openDevice (pid=%d)!\n", getpid ());
return 0;
}
static void jack_closeDevice(mpd_unused struct audio_output *audioOutput)
static void jack_closeDevice(mpd_unused void *data)
{
/*jack_finishDriver(audioOutput);*/
DEBUG("jack_closeDevice (pid=%d)\n", getpid());
}
static void jack_dropBufferedAudio (mpd_unused struct audio_output *audioOutput)
static void jack_dropBufferedAudio (mpd_unused void *data)
{
}
static int jack_playAudio(struct audio_output *audioOutput,
static int jack_playAudio(void *data,
const char *buff, size_t size)
{
JackData *jd = audioOutput->data;
JackData *jd = data;
size_t space;
size_t i;
const short *buffer = (const short *) buff;
......@@ -398,7 +395,7 @@ static int jack_playAudio(struct audio_output *audioOutput,
if ( jd->shutdown ) {
ERROR("Refusing to play, because there is no client thread.\n");
freeJackClient(jd);
audio_output_closed(audioOutput);
audio_output_closed(jd->ao);
return 0;
}
......
......@@ -18,34 +18,45 @@
#include "../output_api.h"
#include "../timer.h"
#include "../utils.h"
static int null_initDriver(struct audio_output *audioOutput,
mpd_unused const struct audio_format *audio_format,
mpd_unused ConfigParam *param)
struct null_data {
Timer *timer;
};
static void *null_initDriver(mpd_unused struct audio_output *audioOutput,
mpd_unused const struct audio_format *audio_format,
mpd_unused ConfigParam *param)
{
audioOutput->data = NULL;
return 0;
struct null_data *nd = xmalloc(sizeof(*nd));
nd->timer = NULL;
return nd;
}
static int null_openDevice(struct audio_output *audioOutput,
static int null_openDevice(void *data,
struct audio_format *audio_format)
{
audioOutput->data = timer_new(audio_format);
struct null_data *nd = data;
nd->timer = timer_new(audio_format);
return 0;
}
static void null_closeDevice(struct audio_output *audioOutput)
static void null_closeDevice(void *data)
{
if (audioOutput->data) {
timer_free(audioOutput->data);
audioOutput->data = NULL;
struct null_data *nd = data;
if (nd->timer != NULL) {
timer_free(nd->timer);
nd->timer = NULL;
}
}
static int null_playAudio(struct audio_output *audioOutput,
static int null_playAudio(void *data,
mpd_unused const char *playChunk, size_t size)
{
Timer *timer = audioOutput->data;
struct null_data *nd = data;
Timer *timer = nd->timer;
if (!timer->started)
timer_start(timer);
......@@ -57,9 +68,11 @@ static int null_playAudio(struct audio_output *audioOutput,
return 0;
}
static void null_dropBufferedAudio(struct audio_output *audioOutput)
static void null_dropBufferedAudio(void *data)
{
timer_reset(audioOutput->data);
struct null_data *nd = data;
timer_reset(nd->timer);
}
const struct audio_output_plugin nullPlugin = {
......
......@@ -333,8 +333,7 @@ static int oss_testDefault(void)
return -1;
}
static int oss_open_default(mpd_unused struct audio_output *ao,
ConfigParam *param, OssData *od)
static void *oss_open_default(ConfigParam *param)
{
int i;
int err[ARRAY_SIZE(default_devices)];
......@@ -343,6 +342,7 @@ static int oss_open_default(mpd_unused struct audio_output *ao,
for (i = ARRAY_SIZE(default_devices); --i >= 0; ) {
ret[i] = oss_statDevice(default_devices[i], &err[i]);
if (ret[i] == 0) {
OssData *od = newOssData();
od->device = default_devices[i];
return 0;
}
......@@ -371,28 +371,27 @@ static int oss_open_default(mpd_unused struct audio_output *ao,
}
}
exit(EXIT_FAILURE);
return 0; /* some compilers can be dumb... */
return NULL; /* some compilers can be dumb... */
}
static int oss_initDriver(struct audio_output *audioOutput,
mpd_unused const struct audio_format *audio_format,
ConfigParam * param)
static void *oss_initDriver(mpd_unused struct audio_output *audioOutput,
mpd_unused const struct audio_format *audio_format,
ConfigParam * param)
{
OssData *od = newOssData();
audioOutput->data = od;
if (param) {
BlockParam *bp = getBlockParam(param, "device");
if (bp) {
OssData *od = newOssData();
od->device = bp->value;
return 0;
return od;
}
}
return oss_open_default(audioOutput, param, od);
return oss_open_default(param);
}
static void oss_finishDriver(struct audio_output *audioOutput)
static void oss_finishDriver(void *data)
{
OssData *od = audioOutput->data;
OssData *od = data;
freeOssData(od);
}
......@@ -434,10 +433,9 @@ static void oss_close(OssData * od)
od->fd = -1;
}
static int oss_open(struct audio_output *audioOutput)
static int oss_open(OssData *od)
{
int tmp;
OssData *od = audioOutput->data;
if ((od->fd = open(od->device, O_WRONLY)) < 0) {
ERROR("Error opening OSS device \"%s\": %s\n", od->device,
......@@ -478,17 +476,17 @@ fail:
return -1;
}
static int oss_openDevice(struct audio_output *audioOutput,
static int oss_openDevice(void *data,
struct audio_format *audioFormat)
{
int ret;
OssData *od = audioOutput->data;
OssData *od = data;
od->channels = (mpd_sint8)audioFormat->channels;
od->sampleRate = audioFormat->sampleRate;
od->bits = (mpd_sint8)audioFormat->bits;
if ((ret = oss_open(audioOutput)) < 0)
if ((ret = oss_open(od)) < 0)
return ret;
audioFormat->channels = od->channels;
......@@ -501,16 +499,16 @@ static int oss_openDevice(struct audio_output *audioOutput,
return ret;
}
static void oss_closeDevice(struct audio_output *audioOutput)
static void oss_closeDevice(void *data)
{
OssData *od = audioOutput->data;
OssData *od = data;
oss_close(od);
}
static void oss_dropBufferedAudio(struct audio_output *audioOutput)
static void oss_dropBufferedAudio(void *data)
{
OssData *od = audioOutput->data;
OssData *od = data;
if (od->fd >= 0) {
ioctl(od->fd, SNDCTL_DSP_RESET, 0);
......@@ -518,14 +516,14 @@ static void oss_dropBufferedAudio(struct audio_output *audioOutput)
}
}
static int oss_playAudio(struct audio_output *audioOutput,
static int oss_playAudio(void *data,
const char *playChunk, size_t size)
{
OssData *od = audioOutput->data;
OssData *od = data;
ssize_t ret;
/* reopen the device since it was closed by dropBufferedAudio */
if (od->fd < 0 && oss_open(audioOutput) < 0)
if (od->fd < 0 && oss_open(od) < 0)
return -1;
while (size > 0) {
......@@ -535,7 +533,7 @@ static int oss_playAudio(struct audio_output *audioOutput,
continue;
ERROR("closing oss device \"%s\" due to write error: "
"%s\n", od->device, strerror(errno));
oss_closeDevice(audioOutput);
oss_closeDevice(od);
return -1;
}
playChunk += ret;
......
......@@ -30,6 +30,8 @@
#define CONN_ATTEMPT_INTERVAL 60
typedef struct _PulseData {
struct audio_output *ao;
pa_simple *s;
char *server;
char *sink;
......@@ -61,9 +63,9 @@ static void freePulseData(PulseData * pd)
free(pd);
}
static int pulse_initDriver(struct audio_output *audioOutput,
mpd_unused const struct audio_format *audio_format,
ConfigParam * param)
static void *pulse_initDriver(struct audio_output *ao,
mpd_unused const struct audio_format *audio_format,
ConfigParam * param)
{
BlockParam *server = NULL;
BlockParam *sink = NULL;
......@@ -75,16 +77,18 @@ static int pulse_initDriver(struct audio_output *audioOutput,
}
pd = newPulseData();
pd->ao = ao;
pd->server = server ? xstrdup(server->value) : NULL;
pd->sink = sink ? xstrdup(sink->value) : NULL;
audioOutput->data = pd;
return 0;
return pd;
}
static void pulse_finishDriver(struct audio_output *audioOutput)
static void pulse_finishDriver(void *data)
{
freePulseData((PulseData *) audioOutput->data);
PulseData *pd = data;
freePulseData(pd);
}
static int pulse_testDefault(void)
......@@ -110,16 +114,15 @@ static int pulse_testDefault(void)
return 0;
}
static int pulse_openDevice(struct audio_output *audioOutput,
static int pulse_openDevice(void *data,
struct audio_format *audioFormat)
{
PulseData *pd;
PulseData *pd = data;
pa_sample_spec ss;
time_t t;
int error;
t = time(NULL);
pd = audioOutput->data;
if (pd->connAttempts != 0 &&
(t - pd->lastAttempt) < CONN_ATTEMPT_INTERVAL)
......@@ -139,11 +142,13 @@ static int pulse_openDevice(struct audio_output *audioOutput,
ss.channels = audioFormat->channels;
pd->s = pa_simple_new(pd->server, MPD_PULSE_NAME, PA_STREAM_PLAYBACK,
pd->sink, audioOutput->name, &ss, NULL, NULL,
pd->sink, audio_output_get_name(pd->ao),
&ss, NULL, NULL,
&error);
if (!pd->s) {
ERROR("Cannot connect to server in PulseAudio output "
"\"%s\" (attempt %i): %s\n", audioOutput->name,
"\"%s\" (attempt %i): %s\n",
audio_output_get_name(pd->ao),
pd->connAttempts, pa_strerror(error));
return -1;
}
......@@ -151,46 +156,47 @@ static int pulse_openDevice(struct audio_output *audioOutput,
pd->connAttempts = 0;
DEBUG("PulseAudio output \"%s\" connected and playing %i bit, %i "
"channel audio at %i Hz\n", audioOutput->name, audioFormat->bits,
"channel audio at %i Hz\n",
audio_output_get_name(pd->ao),
audioFormat->bits,
audioFormat->channels, audioFormat->sampleRate);
return 0;
}
static void pulse_dropBufferedAudio(struct audio_output *audioOutput)
static void pulse_dropBufferedAudio(void *data)
{
PulseData *pd;
PulseData *pd = data;
int error;
pd = audioOutput->data;
if (pa_simple_flush(pd->s, &error) < 0)
WARNING("Flush failed in PulseAudio output \"%s\": %s\n",
audioOutput->name, pa_strerror(error));
audio_output_get_name(pd->ao),
pa_strerror(error));
}
static void pulse_closeDevice(struct audio_output *audioOutput)
static void pulse_closeDevice(void *data)
{
PulseData *pd;
PulseData *pd = data;
pd = audioOutput->data;
if (pd->s) {
pa_simple_drain(pd->s, NULL);
pa_simple_free(pd->s);
}
}
static int pulse_playAudio(struct audio_output *audioOutput,
static int pulse_playAudio(void *data,
const char *playChunk, size_t size)
{
PulseData *pd;
PulseData *pd = data;
int error;
pd = audioOutput->data;
if (pa_simple_write(pd->s, playChunk, size, &error) < 0) {
ERROR("PulseAudio output \"%s\" disconnecting due to write "
"error: %s\n", audioOutput->name, pa_strerror(error));
pulse_closeDevice(audioOutput);
"error: %s\n",
audio_output_get_name(pd->ao),
pa_strerror(error));
pulse_closeDevice(pd);
return -1;
}
......
......@@ -87,9 +87,9 @@ static void free_shout_data(struct shout_data *sd)
} \
}
static int my_shout_init_driver(struct audio_output *audio_output,
const struct audio_format *audio_format,
ConfigParam * param)
static void *my_shout_init_driver(mpd_unused struct audio_output *audio_output,
const struct audio_format *audio_format,
ConfigParam *param)
{
struct shout_data *sd;
char *test;
......@@ -263,9 +263,11 @@ static int my_shout_init_driver(struct audio_output *audio_output,
}
}
audio_output->data = sd;
if (sd->encoder->init_func(sd) != 0)
FATAL("shout: encoder plugin '%s' failed to initialize\n",
sd->encoder->name);
return sd->encoder->init_func(sd);
return sd;
}
static int handle_shout_error(struct shout_data *sd, int err)
......@@ -325,9 +327,9 @@ static void close_shout_conn(struct shout_data * sd)
sd->opened = 0;
}
static void my_shout_finish_driver(struct audio_output *audio_output)
static void my_shout_finish_driver(void *data)
{
struct shout_data *sd = (struct shout_data *) audio_output->data;
struct shout_data *sd = (struct shout_data *)data;
close_shout_conn(sd);
......@@ -340,17 +342,17 @@ static void my_shout_finish_driver(struct audio_output *audio_output)
shout_shutdown();
}
static void my_shout_drop_buffered_audio(struct audio_output *audio_output)
static void my_shout_drop_buffered_audio(void *data)
{
struct shout_data *sd = (struct shout_data *)audio_output->data;
struct shout_data *sd = (struct shout_data *)data;
timer_reset(sd->timer);
/* needs to be implemented for shout */
}
static void my_shout_close_device(struct audio_output *audio_output)
static void my_shout_close_device(void *data)
{
struct shout_data *sd = (struct shout_data *) audio_output->data;
struct shout_data *sd = (struct shout_data *)data;
close_shout_conn(sd);
......@@ -416,9 +418,9 @@ static int shout_connect(struct shout_data *sd)
}
}
static int open_shout_conn(struct audio_output *audio_output)
static int open_shout_conn(void *data)
{
struct shout_data *sd = (struct shout_data *) audio_output->data;
struct shout_data *sd = (struct shout_data *)data;
int status;
status = shout_connect(sd);
......@@ -440,12 +442,12 @@ static int open_shout_conn(struct audio_output *audio_output)
return 0;
}
static int my_shout_open_device(struct audio_output *audio_output,
static int my_shout_open_device(void *data,
struct audio_format *audio_format)
{
struct shout_data *sd = (struct shout_data *) audio_output->data;
struct shout_data *sd = (struct shout_data *)data;
if (!sd->opened && open_shout_conn(audio_output) < 0)
if (!sd->opened && open_shout_conn(sd) < 0)
return -1;
if (sd->timer)
......@@ -476,10 +478,10 @@ static void send_metadata(struct shout_data * sd)
sd->tag_to_send = 0;
}
static int my_shout_play(struct audio_output *audio_output,
static int my_shout_play(void *data,
const char *chunk, size_t size)
{
struct shout_data *sd = (struct shout_data *) audio_output->data;
struct shout_data *sd = (struct shout_data *)data;
int status;
if (!sd->timer->started)
......@@ -491,9 +493,9 @@ static int my_shout_play(struct audio_output *audio_output,
send_metadata(sd);
if (!sd->opened) {
status = open_shout_conn(audio_output);
status = open_shout_conn(sd);
if (status < 0) {
my_shout_close_device(audio_output);
my_shout_close_device(sd);
return -1;
} else if (status > 0) {
timer_sync(sd->timer);
......@@ -502,22 +504,22 @@ static int my_shout_play(struct audio_output *audio_output,
}
if (sd->encoder->encode_func(sd, chunk, size)) {
my_shout_close_device(audio_output);
my_shout_close_device(sd);
return -1;
}
if (write_page(sd) < 0) {
my_shout_close_device(audio_output);
my_shout_close_device(sd);
return -1;
}
return 0;
}
static void my_shout_set_tag(struct audio_output *audio_output,
static void my_shout_set_tag(void *data,
const struct tag *tag)
{
struct shout_data *sd = (struct shout_data *) audio_output->data;
struct shout_data *sd = (struct shout_data *)data;
if (sd->tag)
tag_free(sd->tag);
......
......@@ -17,6 +17,7 @@
*/
#include "output_api.h"
#include "output_internal.h"
const char *audio_output_get_name(const struct audio_output *ao)
{
......
......@@ -21,12 +21,10 @@
#define OUTPUT_API_H
#include "../config.h"
#include "pcm_utils.h"
#include "audio_format.h"
#include "tag.h"
#include "conf.h"
#include "log.h"
#include "notify.h"
#include "os_compat.h"
#define DISABLED_AUDIO_OUTPUT_PLUGIN(plugin) const struct audio_output_plugin plugin;
......@@ -38,24 +36,21 @@ struct audio_output_plugin {
int (*test_default_device)(void);
int (*init)(struct audio_output *ao,
const struct audio_format *audio_format,
ConfigParam *param);
void *(*init)(struct audio_output *ao,
const struct audio_format *audio_format,
ConfigParam *param);
void (*finish)(struct audio_output *ao);
void (*finish)(void *data);
int (*open)(struct audio_output *ao,
struct audio_format *audio_format);
int (*open)(void *data, struct audio_format *audio_format);
int (*play)(struct audio_output *ao,
const char *playChunk, size_t size);
int (*play)(void *data, const char *playChunk, size_t size);
void (*cancel)(struct audio_output *ao);
void (*cancel)(void *data);
void (*close)(struct audio_output *ao);
void (*close)(void *data);
void (*send_tag)(struct audio_output *audioOutput,
const struct tag *tag);
void (*send_tag)(void *data, const struct tag *tag);
};
enum audio_output_command {
......@@ -68,36 +63,7 @@ enum audio_output_command {
AO_COMMAND_KILL
};
struct audio_output {
int open;
const char *name;
const struct audio_output_plugin *plugin;
struct audio_format inAudioFormat;
struct audio_format outAudioFormat;
struct audio_format reqAudioFormat;
ConvState convState;
char *convBuffer;
size_t convBufferLen;
pthread_t thread;
struct notify notify;
enum audio_output_command command;
union {
struct {
const char *data;
size_t size;
} play;
const struct tag *tag;
} args;
int result;
void *data;
};
extern struct notify audio_output_client_notify;
struct audio_output;
const char *audio_output_get_name(const struct audio_output *ao);
......
......@@ -18,6 +18,7 @@
#include "output_control.h"
#include "output_api.h"
#include "output_internal.h"
#include "output_thread.h"
#include "pcm_utils.h"
......@@ -107,7 +108,7 @@ void audio_output_finish(struct audio_output *audioOutput)
if (audioOutput->thread != 0)
ao_command(audioOutput, AO_COMMAND_KILL);
if (audioOutput->plugin->finish)
audioOutput->plugin->finish(audioOutput);
audioOutput->plugin->finish(audioOutput->data);
if (audioOutput->convBuffer)
free(audioOutput->convBuffer);
}
......
......@@ -18,6 +18,7 @@
#include "output_control.h"
#include "output_api.h"
#include "output_internal.h"
#include "output_list.h"
#include "log.h"
#include "audio.h"
......@@ -102,7 +103,8 @@ int audio_output_init(struct audio_output *ao, ConfigParam * param)
notify_init(&ao->notify);
ao->command = AO_COMMAND_NONE;
if (plugin->init(ao, format ? &ao->reqAudioFormat : NULL, param) != 0)
ao->data = plugin->init(ao, format ? &ao->reqAudioFormat : NULL, param);
if (ao->data == NULL)
return 0;
return 1;
......
/* the Music Player Daemon (MPD)
* Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* Copyright (C) 2008 Max Kellermann <max@duempel.org>
* This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef OUTPUT_INTERNAL_H
#define OUTPUT_INTERNAL_H
#include "pcm_utils.h"
#include "notify.h"
struct audio_output {
int open;
const char *name;
const struct audio_output_plugin *plugin;
int convertAudioFormat;
struct audio_format inAudioFormat;
struct audio_format outAudioFormat;
struct audio_format reqAudioFormat;
ConvState convState;
char *convBuffer;
size_t convBufferLen;
pthread_t thread;
struct notify notify;
enum audio_output_command command;
union {
struct {
const char *data;
size_t size;
} play;
const struct tag *tag;
} args;
int result;
void *data;
};
extern struct notify audio_output_client_notify;
#endif
......@@ -18,6 +18,7 @@
#include "output_thread.h"
#include "output_api.h"
#include "output_internal.h"
#include "utils.h"
static void ao_command_finished(struct audio_output *ao)
......@@ -58,7 +59,7 @@ static void ao_play(struct audio_output *ao)
if (!audio_format_equals(&ao->inAudioFormat, &ao->outAudioFormat))
convertAudioFormat(ao, &data, &size);
ao->result = ao->plugin->play(ao, data, size);
ao->result = ao->plugin->play(ao->data, data, size);
ao_command_finished(ao);
}
......@@ -75,7 +76,8 @@ static void *audio_output_task(void *arg)
case AO_COMMAND_OPEN:
assert(!ao->open);
ao->result = ao->plugin->open(ao, &ao->outAudioFormat);
ao->result = ao->plugin->open(ao->data,
&ao->outAudioFormat);
assert(!ao->open);
if (ao->result == 0)
......@@ -86,7 +88,7 @@ static void *audio_output_task(void *arg)
case AO_COMMAND_CLOSE:
assert(ao->open);
ao->plugin->close(ao);
ao->plugin->close(ao->data);
ao->open = 0;
ao_command_finished(ao);
break;
......@@ -96,12 +98,12 @@ static void *audio_output_task(void *arg)
break;
case AO_COMMAND_CANCEL:
ao->plugin->cancel(ao);
ao->plugin->cancel(ao->data);
ao_command_finished(ao);
break;
case AO_COMMAND_SEND_TAG:
ao->plugin->send_tag(ao, ao->args.tag);
ao->plugin->send_tag(ao->data, ao->args.tag);
ao_command_finished(ao);
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment