diff options
author | jmcneill <jmcneill> | 2008-12-20 00:43:47 +0000 |
---|---|---|
committer | jmcneill <jmcneill> | 2008-12-20 00:43:47 +0000 |
commit | 756b6c0c136f1be143bd0e9ac1b8bfbcc7bb18a6 (patch) | |
tree | ed8499426b667c7cde5b0a7d3cf6523eeb6e06ac /multimedia | |
parent | 323cbf0d38f61d2fc65f711be2a7ae3f0c184986 (diff) | |
download | pkgsrc-756b6c0c136f1be143bd0e9ac1b8bfbcc7bb18a6.tar.gz |
Backport PulseAudio driver from MPlayer SVN.
Diffstat (limited to 'multimedia')
-rw-r--r-- | multimedia/mplayer-share/Makefile.common | 6 | ||||
-rw-r--r-- | multimedia/mplayer-share/distinfo | 5 | ||||
-rw-r--r-- | multimedia/mplayer-share/files/ao_pulse.c | 386 | ||||
-rw-r--r-- | multimedia/mplayer-share/options.mk | 13 | ||||
-rw-r--r-- | multimedia/mplayer-share/patches/patch-aa | 36 | ||||
-rw-r--r-- | multimedia/mplayer-share/patches/patch-be | 22 |
6 files changed, 460 insertions, 8 deletions
diff --git a/multimedia/mplayer-share/Makefile.common b/multimedia/mplayer-share/Makefile.common index ebd8401214e..531411a17c9 100644 --- a/multimedia/mplayer-share/Makefile.common +++ b/multimedia/mplayer-share/Makefile.common @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.common,v 1.38 2008/09/08 14:32:42 joerg Exp $ +# $NetBSD: Makefile.common,v 1.39 2008/12/20 00:43:47 jmcneill Exp $ MPLAYER_DIST_VERSION= 1.0rc2 @@ -27,6 +27,7 @@ HOMEPAGE?= http://www.mplayerhq.hu/ # PATCHDIR= ${.CURDIR}/../../multimedia/mplayer-share/patches +FILESDIR= ${.CURDIR}/../../multimedia/mplayer-share/files DISTINFO_FILE= ${.CURDIR}/../../multimedia/mplayer-share/distinfo RESTRICTED= Prohibited by USAs DMCA and patent law @@ -51,6 +52,9 @@ ONLY_FOR_COMPILER= gcc # TMPDIR to ${WRKDIR} CONFIGURE_ENV+= TMPDIR=${WRKDIR:Q} +post-extract: + ${CP} ${FILESDIR}/ao_pulse.c ${WRKSRC}/libao2/ao_polyp.c + .include "../../mk/bsd.prefs.mk" .include "../../multimedia/mplayer-share/options.mk" diff --git a/multimedia/mplayer-share/distinfo b/multimedia/mplayer-share/distinfo index c6052a5a21b..67647e0ceb7 100644 --- a/multimedia/mplayer-share/distinfo +++ b/multimedia/mplayer-share/distinfo @@ -1,9 +1,9 @@ -$NetBSD: distinfo,v 1.57 2008/12/18 16:40:58 bjs Exp $ +$NetBSD: distinfo,v 1.58 2008/12/20 00:43:47 jmcneill Exp $ SHA1 (mplayer-1.0rc10/MPlayer-1.0rc2.tar.bz2) = e9b496f3527c552004ec6d01d6b43f196b43ce2d RMD160 (mplayer-1.0rc10/MPlayer-1.0rc2.tar.bz2) = 3b5cba1529856a177a5191e22f8dcc00b5a83c52 Size (mplayer-1.0rc10/MPlayer-1.0rc2.tar.bz2) = 9338201 bytes -SHA1 (patch-aa) = cd6735a7fd2db3eeccc2f1417cb187648775bff6 +SHA1 (patch-aa) = 66237776593acde3de025d485285978e63b4996a SHA1 (patch-ab) = 29bf59ecb3d283708ae1c5002d1fa71cac627cc9 SHA1 (patch-ac) = 6d0de4bd41d9842ea1bf46e9fbe60bf6a943b913 SHA1 (patch-ad) = d0b72eaa5e63d2cfd7828ea1a9973f1728c607b5 @@ -22,6 +22,7 @@ SHA1 (patch-ba) = 2683c414fed3a4a6d3b4d47287f43d822339bd4e SHA1 (patch-bb) = 26d000bcbc94b9139e6dbc79237fdb3a109c6057 SHA1 (patch-bc) = fd46ce3cd6d5f7525e210cf6d475b89573ca988d SHA1 (patch-bd) = 9132118a143758b6c9e9dffb713f7dadd29ce3c3 +SHA1 (patch-be) = d9b0573c9ea9767bed7d9b3f29cd07cc31c37519 SHA1 (patch-ca) = 68603a92b3dd8c7a33e6bc982f8ced1219fa419d SHA1 (patch-tc) = 89f802ff0ebfc14d6f2a4b17177915f66c9f9038 SHA1 (patch-va) = db69c373e78048924c536055c68c7de0feabc623 diff --git a/multimedia/mplayer-share/files/ao_pulse.c b/multimedia/mplayer-share/files/ao_pulse.c new file mode 100644 index 00000000000..827dab92db6 --- /dev/null +++ b/multimedia/mplayer-share/files/ao_pulse.c @@ -0,0 +1,386 @@ +/* + * PulseAudio audio output driver. + * Copyright (C) 2006 Lennart Poettering + * Copyright (C) 2007 Reimar Doeffinger + * + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <string.h> + +#include <pulse/pulseaudio.h> + +#include "config.h" +#include "libaf/af_format.h" +#include "mp_msg.h" +#include "audio_out.h" +#include "audio_out_internal.h" + +#define PULSE_CLIENT_NAME "MPlayer" + +/** General driver info */ +static ao_info_t info = { + "PulseAudio audio output", + "pulse", + "Lennart Poettering", + "" +}; + +/** PulseAudio playback stream object */ +static struct pa_stream *stream; + +/** PulseAudio connection context */ +static struct pa_context *context; + +/** Main event loop object */ +static struct pa_threaded_mainloop *mainloop; + +/** A temporary variable to store the current volume */ +static pa_cvolume volume; + +LIBAO_EXTERN(pulse) + +#define GENERIC_ERR_MSG(ctx, str) \ + mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] "str": %s\n", \ + pa_strerror(pa_context_errno(ctx))) + +static void context_state_cb(pa_context *c, void *userdata) { + switch (pa_context_get_state(c)) { + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(mainloop, 0); + break; + } +} + +static void stream_state_cb(pa_stream *s, void *userdata) { + switch (pa_stream_get_state(s)) { + case PA_STREAM_READY: + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: + pa_threaded_mainloop_signal(mainloop, 0); + break; + } +} + +static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { + pa_threaded_mainloop_signal(mainloop, 0); +} + +static void stream_latency_update_cb(pa_stream *s, void *userdata) { + pa_threaded_mainloop_signal(mainloop, 0); +} + +static void success_cb(pa_stream *s, int success, void *userdata) { + if (userdata) + *(int *)userdata = success; + pa_threaded_mainloop_signal(mainloop, 0); +} + +/** + * \brief waits for a pulseaudio operation to finish, frees it and + * unlocks the mainloop + * \param op operation to wait for + * \return 1 if operation has finished normally (DONE state), 0 otherwise + */ +static int waitop(pa_operation *op) { + pa_operation_state_t state; + if (!op) return 0; + state = pa_operation_get_state(op); + while (state == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mainloop); + state = pa_operation_get_state(op); + } + pa_operation_unref(op); + pa_threaded_mainloop_unlock(mainloop); + return state == PA_OPERATION_DONE; +} + +static const struct format_map_s { + int mp_format; + pa_sample_format_t pa_format; +} format_maps[] = { + {AF_FORMAT_S16_LE, PA_SAMPLE_S16LE}, + {AF_FORMAT_S16_BE, PA_SAMPLE_S16BE}, +#ifdef PA_SAMPLE_S32NE + {AF_FORMAT_S32_LE, PA_SAMPLE_S32LE}, + {AF_FORMAT_S32_BE, PA_SAMPLE_S32BE}, +#endif +#ifdef PA_SAMPLE_FLOAT32NE + {AF_FORMAT_FLOAT_LE, PA_SAMPLE_FLOAT32LE}, + {AF_FORMAT_FLOAT_BE, PA_SAMPLE_FLOAT32BE}, +#endif + {AF_FORMAT_U8, PA_SAMPLE_U8}, + {AF_FORMAT_MU_LAW, PA_SAMPLE_ULAW}, + {AF_FORMAT_A_LAW, PA_SAMPLE_ALAW}, + {AF_FORMAT_UNKNOWN, 0} +}; + +static int init(int rate_hz, int channels, int format, int flags) { + struct pa_sample_spec ss; + struct pa_channel_map map; + const struct format_map_s *fmt_map; + char *devarg = NULL; + char *host = NULL; + char *sink = NULL; + + if (ao_subdevice) { + devarg = strdup(ao_subdevice); + sink = strchr(devarg, ':'); + if (sink) *sink++ = 0; + if (devarg[0]) host = devarg; + } + + ss.channels = channels; + ss.rate = rate_hz; + + ao_data.samplerate = rate_hz; + ao_data.channels = channels; + + fmt_map = format_maps; + while (fmt_map->mp_format != format) { + if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) { + mp_msg(MSGT_AO, MSGL_V, "AO: [pulse] Unsupported format, using default\n"); + fmt_map = format_maps; + break; + } + fmt_map++; + } + ao_data.format = fmt_map->mp_format; + ss.format = fmt_map->pa_format; + + if (!pa_sample_spec_valid(&ss)) { + mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n"); + goto fail; + } + + pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); + ao_data.bps = pa_bytes_per_second(&ss); + + pa_cvolume_reset(&volume, ss.channels); + + if (!(mainloop = pa_threaded_mainloop_new())) { + mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n"); + goto fail; + } + + if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), PULSE_CLIENT_NAME))) { + mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate context\n"); + goto fail; + } + + pa_context_set_state_callback(context, context_state_cb, NULL); + + if (pa_context_connect(context, host, 0, NULL) < 0) + goto fail; + + pa_threaded_mainloop_lock(mainloop); + + if (pa_threaded_mainloop_start(mainloop) < 0) + goto unlock_and_fail; + + /* Wait until the context is ready */ + pa_threaded_mainloop_wait(mainloop); + + if (pa_context_get_state(context) != PA_CONTEXT_READY) + goto unlock_and_fail; + + if (!(stream = pa_stream_new(context, "audio stream", &ss, &map))) + goto unlock_and_fail; + + pa_stream_set_state_callback(stream, stream_state_cb, NULL); + pa_stream_set_write_callback(stream, stream_request_cb, NULL); + pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL); + + if (pa_stream_connect_playback(stream, sink, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, &volume, NULL) < 0) + goto unlock_and_fail; + + /* Wait until the stream is ready */ + pa_threaded_mainloop_wait(mainloop); + + if (pa_stream_get_state(stream) != PA_STREAM_READY) + goto unlock_and_fail; + + pa_threaded_mainloop_unlock(mainloop); + + free(devarg); + return 1; + +unlock_and_fail: + + if (mainloop) + pa_threaded_mainloop_unlock(mainloop); + +fail: + if (context) + GENERIC_ERR_MSG(context, "Init failed"); + free(devarg); + uninit(1); + return 0; +} + +/** Destroy libao driver */ +static void uninit(int immed) { + if (stream && !immed) { + pa_threaded_mainloop_lock(mainloop); + waitop(pa_stream_drain(stream, success_cb, NULL)); + } + + if (mainloop) + pa_threaded_mainloop_stop(mainloop); + + if (stream) { + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = NULL; + } + + if (context) { + pa_context_disconnect(context); + pa_context_unref(context); + context = NULL; + } + + if (mainloop) { + pa_threaded_mainloop_free(mainloop); + mainloop = NULL; + } +} + +/** Play the specified data to the pulseaudio server */ +static int play(void* data, int len, int flags) { + pa_threaded_mainloop_lock(mainloop); + if (pa_stream_write(stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) { + GENERIC_ERR_MSG(context, "pa_stream_write() failed"); + len = -1; + } + pa_threaded_mainloop_unlock(mainloop); + return len; +} + +static void cork(int b) { + int success = 0; + pa_threaded_mainloop_lock(mainloop); + if (!waitop(pa_stream_cork(stream, b, success_cb, &success)) || + !success) + GENERIC_ERR_MSG(context, "pa_stream_cork() failed"); +} + +/** Pause the audio stream by corking it on the server */ +static void audio_pause(void) { + cork(1); +} + +/** Resume the audio stream by uncorking it on the server */ +static void audio_resume(void) { + cork(0); +} + +/** Reset the audio stream, i.e. flush the playback buffer on the server side */ +static void reset(void) { + int success = 0; + pa_threaded_mainloop_lock(mainloop); + if (!waitop(pa_stream_flush(stream, success_cb, &success)) || + !success) + GENERIC_ERR_MSG(context, "pa_stream_flush() failed"); +} + +/** Return number of bytes that may be written to the server without blocking */ +static int get_space(void) { + size_t l; + pa_threaded_mainloop_lock(mainloop); + l = pa_stream_writable_size(stream); + pa_threaded_mainloop_unlock(mainloop); + return l; +} + +/** Return the current latency in seconds */ +static float get_delay(void) { + pa_usec_t latency = (pa_usec_t) -1; + pa_threaded_mainloop_lock(mainloop); + while (pa_stream_get_latency(stream, &latency, NULL) < 0) { + if (pa_context_errno(context) != PA_ERR_NODATA) { + GENERIC_ERR_MSG(context, "pa_stream_get_latency() failed"); + break; + } + /* Wait until latency data is available again */ + pa_threaded_mainloop_wait(mainloop); + } + pa_threaded_mainloop_unlock(mainloop); + return latency == (pa_usec_t) -1 ? 0 : latency / 1000000.0; +} + +/** A callback function that is called when the + * pa_context_get_sink_input_info() operation completes. Saves the + * volume field of the specified structure to the global variable volume. */ +static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) { + if (is_last < 0) { + GENERIC_ERR_MSG(context, "Failed to get sink input info"); + return; + } + if (!i) + return; + volume = i->volume; + pa_threaded_mainloop_signal(mainloop, 0); +} + +static int control(int cmd, void *arg) { + switch (cmd) { + case AOCONTROL_GET_VOLUME: { + ao_control_vol_t *vol = arg; + uint32_t devidx = pa_stream_get_index(stream); + pa_threaded_mainloop_lock(mainloop); + if (!waitop(pa_context_get_sink_input_info(context, devidx, info_func, NULL))) { + GENERIC_ERR_MSG(context, "pa_stream_get_sink_input_info() failed"); + return CONTROL_ERROR; + } + + if (volume.channels != 2) + vol->left = vol->right = pa_cvolume_avg(&volume)*100/PA_VOLUME_NORM; + else { + vol->left = volume.values[0]*100/PA_VOLUME_NORM; + vol->right = volume.values[1]*100/PA_VOLUME_NORM; + } + + return CONTROL_OK; + } + + case AOCONTROL_SET_VOLUME: { + const ao_control_vol_t *vol = arg; + pa_operation *o; + + if (volume.channels != 2) + pa_cvolume_set(&volume, volume.channels, (pa_volume_t)vol->left*PA_VOLUME_NORM/100); + else { + volume.values[0] = (pa_volume_t)vol->left*PA_VOLUME_NORM/100; + volume.values[1] = (pa_volume_t)vol->right*PA_VOLUME_NORM/100; + } + + if (!(o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL))) { + GENERIC_ERR_MSG(context, "pa_context_set_sink_input_volume() failed"); + return CONTROL_ERROR; + } + /* We don't wait for completion here */ + pa_operation_unref(o); + return CONTROL_OK; + } + + default: + return CONTROL_UNKNOWN; + } +} diff --git a/multimedia/mplayer-share/options.mk b/multimedia/mplayer-share/options.mk index 3c7ec2f9daa..11586b84e3e 100644 --- a/multimedia/mplayer-share/options.mk +++ b/multimedia/mplayer-share/options.mk @@ -1,4 +1,4 @@ -# $NetBSD: options.mk,v 1.33 2008/09/09 01:11:53 jmcneill Exp $ +# $NetBSD: options.mk,v 1.34 2008/12/20 00:43:47 jmcneill Exp $ .if defined(PKGNAME) && empty(PKGNAME:Mmplayer-share*) @@ -25,7 +25,7 @@ PKG_OPTIONS_OPTIONAL_GROUPS= faadgroup PKG_OPTIONS_GROUP.faadgroup= faad mplayer-internal-faad PKG_SUGGESTED_OPTIONS+= mplayer-internal-faad -PKG_SUPPORTED_OPTIONS+= aalib esound ggi mplayer-menu nas sdl +PKG_SUPPORTED_OPTIONS+= aalib esound ggi mplayer-menu nas pulseaudio sdl . if ${OPSYS} != "SunOS" PKG_SUPPORTED_OPTIONS+= arts @@ -76,7 +76,7 @@ PKG_SUPPORTED_OPTIONS+= xvid .for _o_ in aalib arts cdparanoia dv dvdread esound gif jpeg \ lame mad mplayer-menu mplayer-real \ mplayer-default-cflags mplayer-runtime-cpudetection mplayer-win32 \ - nas oss png sdl theora vorbis x264 xvid + nas oss pulseaudio png sdl theora vorbis x264 xvid . if !empty(PKG_SUPPORTED_OPTIONS:M${_o_}) PKG_SUGGESTED_OPTIONS+= ${_o_} . endif @@ -256,6 +256,13 @@ CONFIGURE_ARGS+= --enable-png CONFIGURE_ARGS+= --disable-png .endif +.if !empty(PKG_OPTIONS:Mpulseaudio) +CONFIGURE_ARGS+= --enable-polyp +. include "../../audio/pulseaudio/buildlink3.mk" +.else +CONFIGURE_ARGS+= --disable-polyp +.endif + .if !empty(PKG_OPTIONS:Msdl) CONFIGURE_ARGS+= --enable-sdl . include "../../devel/SDL/buildlink3.mk" diff --git a/multimedia/mplayer-share/patches/patch-aa b/multimedia/mplayer-share/patches/patch-aa index 263301417b6..856051b062b 100644 --- a/multimedia/mplayer-share/patches/patch-aa +++ b/multimedia/mplayer-share/patches/patch-aa @@ -1,7 +1,7 @@ -$NetBSD: patch-aa,v 1.21 2008/09/09 12:07:45 jmcneill Exp $ +$NetBSD: patch-aa,v 1.22 2008/12/20 00:43:47 jmcneill Exp $ --- configure.orig 2007-10-07 15:49:33.000000000 -0400 -+++ configure 2008-09-08 20:58:52.000000000 -0400 ++++ configure 2008-12-19 19:29:30.000000000 -0500 @@ -718,7 +718,7 @@ _inc_extra=-I`echo $ac_option | cut -d '=' -f 2 | sed 's,:, -I,g'` ;; @@ -64,6 +64,38 @@ $NetBSD: patch-aa,v 1.21 2008/09/09 12:07:45 jmcneill Exp $ fi _vosrc="$_vosrc vo_aa.c" _vomodules="aa $_vomodules" +@@ -5100,15 +5103,15 @@ + echocheck "Polyp" + if test "$_polyp" = auto ; then + _polyp=no +- if $_pkg_config --exists 'polyplib >= 0.6 polyplib-error >= 0.6 polyplib-mainloop >= 0.6' ; then ++ if $_pkg_config --exists 'libpulse >= 0.9 libpulse-simple >= 0.9 libpulse-mainloop-glib >= 0.9' ; then + + cat > $TMPC << EOF +-#include <polyp/polyplib.h> +-#include <polyp/mainloop.h> +-#include <polyp/polyplib-error.h> ++#include <pulse/pulseaudio.h> ++#include <pulse/mainloop.h> ++#include <pulse/error.h> + int main(void) { return 0; } + EOF +-cc_check `$_pkg_config --libs --cflags polyplib polyplib-error polyplib-mainloop` && tmp_run && _polyp=yes ++cc_check `$_pkg_config --libs --cflags libpulse libpulse-simple libpulse-mainloop-glib` && tmp_run && _polyp=yes + + fi + fi +@@ -5118,8 +5121,8 @@ + _def_polyp='#define USE_POLYP 1' + _aosrc="$_aosrc ao_polyp.c" + _aomodules="polyp $_aomodules" +- _libs_mplayer="$_libs_mplayer `$_pkg_config --libs polyplib polyplib-error polyplib-mainloop`" +- _inc_extra="$_inc_extra `$_pkg_config --cflags polyplib polyplib-error polyplib-mainloop`" ++ _libs_mplayer="$_libs_mplayer `$_pkg_config --libs libpulse libpulse-simple libpulse-mainloop-glib`" ++ _inc_extra="$_inc_extra `$_pkg_config --cflags libpulse libpulse-simple libpulse-mainloop-glib`" + else + _def_polyp='#undef USE_POLYP' + _noaomodules="polyp $_noaomodules" @@ -6837,11 +6840,16 @@ echocheck "Video 4 Linux 2 TV interface" if test "$_tv_v4l2" = auto ; then diff --git a/multimedia/mplayer-share/patches/patch-be b/multimedia/mplayer-share/patches/patch-be new file mode 100644 index 00000000000..ef2b1fd4faa --- /dev/null +++ b/multimedia/mplayer-share/patches/patch-be @@ -0,0 +1,22 @@ +$NetBSD: patch-be,v 1.3 2008/12/20 00:43:47 jmcneill Exp $ + +--- libao2/audio_out.c.orig 2008-12-19 19:39:23.000000000 -0500 ++++ libao2/audio_out.c 2008-12-19 19:39:37.000000000 -0500 +@@ -26,7 +26,7 @@ extern ao_functions_t audio_out_arts; + extern ao_functions_t audio_out_esd; + #endif + #ifdef USE_POLYP +-extern ao_functions_t audio_out_polyp; ++extern ao_functions_t audio_out_pulse; + #endif + #ifdef USE_JACK + extern ao_functions_t audio_out_jack; +@@ -113,7 +113,7 @@ ao_functions_t* audio_out_drivers[] = + &audio_out_esd, + #endif + #ifdef USE_POLYP +- &audio_out_polyp, ++ &audio_out_pulse, + #endif + #ifdef USE_JACK + &audio_out_jack, |