From 48e85562982aee72f055b5ca523ff73bfe34cc43 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Fri, 24 Jun 2011 15:56:43 +0200 Subject: ao_rsound: add new RSound audio output driver --- libao2/ao_rsound.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++ libao2/audio_out.c | 4 + 2 files changed, 218 insertions(+) create mode 100644 libao2/ao_rsound.c (limited to 'libao2') diff --git a/libao2/ao_rsound.c b/libao2/ao_rsound.c new file mode 100644 index 0000000000..9a8b8cb4fc --- /dev/null +++ b/libao2/ao_rsound.c @@ -0,0 +1,214 @@ +/* + * RSound audio output driver + * + * Copyright (C) 2011 Hans-Kristian Arntzen + * + * This file is part of mplayer2. + * + * mplayer2 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. + * + * mplayer2 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 mplayer2; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "talloc.h" + +#include "subopt-helper.h" +#include "osdep/timer.h" +#include "libaf/af_format.h" +#include "audio_out.h" + +struct priv { + rsound_t *rd; +}; + +static int set_format(struct ao *ao) +{ + int rsd_format; + + switch (ao->format) { + case AF_FORMAT_U8: + rsd_format = RSD_U8; + break; + case AF_FORMAT_S8: + rsd_format = RSD_S8; + break; + case AF_FORMAT_S16_LE: + rsd_format = RSD_S16_LE; + break; + case AF_FORMAT_S16_BE: + rsd_format = RSD_S16_BE; + break; + case AF_FORMAT_U16_LE: + rsd_format = RSD_U16_LE; + break; + case AF_FORMAT_U16_BE: + rsd_format = RSD_U16_BE; + break; + case AF_FORMAT_S24_LE: + case AF_FORMAT_S24_BE: + case AF_FORMAT_U24_LE: + case AF_FORMAT_U24_BE: + rsd_format = RSD_S32_LE; + ao->format = AF_FORMAT_S32_LE; + break; + case AF_FORMAT_S32_LE: + rsd_format = RSD_S32_LE; + break; + case AF_FORMAT_S32_BE: + rsd_format = RSD_S32_BE; + break; + case AF_FORMAT_U32_LE: + rsd_format = RSD_U32_LE; + break; + case AF_FORMAT_U32_BE: + rsd_format = RSD_U32_BE; + break; + case AF_FORMAT_A_LAW: + rsd_format = RSD_ALAW; + break; + case AF_FORMAT_MU_LAW: + rsd_format = RSD_MULAW; + break; + default: + rsd_format = RSD_S16_LE; + ao->format = AF_FORMAT_S16_LE; + } + + return rsd_format; +} + +static int init(struct ao *ao, char *params) +{ + struct priv *priv = talloc_zero(ao, struct priv); + ao->priv = priv; + + char *host = NULL; + char *port = NULL; + + const opt_t subopts[] = { + {"host", OPT_ARG_MSTRZ, &host, NULL}, + {"port", OPT_ARG_MSTRZ, &port, NULL}, + {NULL} + }; + + if (subopt_parse(params, subopts) != 0) + return -1; + + if (rsd_init(&priv->rd) < 0) { + free(host); + free(port); + return -1; + } + + if (host) { + rsd_set_param(priv->rd, RSD_HOST, host); + free(host); + } + + if (port) { + rsd_set_param(priv->rd, RSD_PORT, port); + free(port); + } + + rsd_set_param(priv->rd, RSD_SAMPLERATE, &ao->samplerate); + rsd_set_param(priv->rd, RSD_CHANNELS, &ao->channels); + + int rsd_format = set_format(ao); + rsd_set_param(priv->rd, RSD_FORMAT, &rsd_format); + + if (rsd_start(priv->rd) < 0) { + rsd_free(priv->rd); + return -1; + } + + ao->bps = ao->channels * ao->samplerate * af_fmt2bits(ao->format) / 8; + + return 0; +} + +static void uninit(struct ao *ao, bool cut_audio) +{ + struct priv *priv = ao->priv; + /* The API does not provide a direct way to explicitly wait until + * the last byte has been played server-side as this cannot be + * guaranteed by backend drivers, so we approximate this behavior. + */ + if (!cut_audio) + usec_sleep(rsd_delay_ms(priv->rd) * 1000); + + rsd_stop(priv->rd); + rsd_free(priv->rd); +} + +static void reset(struct ao *ao) +{ + struct priv *priv = ao->priv; + rsd_stop(priv->rd); + rsd_start(priv->rd); +} + +static void audio_pause(struct ao *ao) +{ + struct priv *priv = ao->priv; + rsd_pause(priv->rd, 1); +} + +static void audio_resume(struct ao *ao) +{ + struct priv *priv = ao->priv; + rsd_pause(priv->rd, 0); +} + +static int get_space(struct ao *ao) +{ + struct priv *priv = ao->priv; + return rsd_get_avail(priv->rd); +} + +static int play(struct ao *ao, void *data, int len, int flags) +{ + struct priv *priv = ao->priv; + return rsd_write(priv->rd, data, len); +} + +static float get_delay(struct ao *ao) +{ + struct priv *priv = ao->priv; + return rsd_delay_ms(priv->rd) / 1000.0; +} + +const struct ao_driver audio_out_rsound = { + .is_new = true, + .info = &(const struct ao_info) { + .name = "RSound output driver", + .short_name = "rsound", + .author = "Hans-Kristian Arntzen", + .comment = "", + }, + .init = init, + .uninit = uninit, + .reset = reset, + .get_space = get_space, + .play = play, + .get_delay = get_delay, + .pause = audio_pause, + .resume = audio_resume, +}; + diff --git a/libao2/audio_out.c b/libao2/audio_out.c index 2ad147d8a5..14cab9b285 100644 --- a/libao2/audio_out.c +++ b/libao2/audio_out.c @@ -35,6 +35,7 @@ char *ao_subdevice = NULL; extern const struct ao_driver audio_out_oss; extern const struct ao_driver audio_out_coreaudio; extern const struct ao_driver audio_out_arts; +extern const struct ao_driver audio_out_rsound; extern const struct ao_driver audio_out_esd; extern const struct ao_driver audio_out_pulse; extern const struct ao_driver audio_out_jack; @@ -120,6 +121,9 @@ static const struct ao_driver * const audio_out_drivers[] = { &audio_out_null, // should not be auto-selected: &audio_out_pcm, +#ifdef CONFIG_RSOUND + &audio_out_rsound, +#endif NULL }; -- cgit v1.2.3