vlc | branch: master | Rémi Denis-Courmont <[email protected]> | Sat Oct 8 20:53:26 2011 +0300| [bd55fe88464e224a0931a4d82ff2c91f73d4e9a9] | committer: Rémi Denis-Courmont
Add service discovery for PulseAudio input > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=bd55fe88464e224a0931a4d82ff2c91f73d4e9a9 --- modules/LIST | 1 + modules/services_discovery/Modules.am | 10 ++ modules/services_discovery/pulse.c | 250 +++++++++++++++++++++++++++++++++ po/POTFILES.in | 1 + 4 files changed, 262 insertions(+), 0 deletions(-) diff --git a/modules/LIST b/modules/LIST index d3d23f3..ec2509e 100644 --- a/modules/LIST +++ b/modules/LIST @@ -257,6 +257,7 @@ $Id$ * ps: input module for MPEG PS decapsulation * psychedelic: Psychedelic video filter * pulse: PulseAudio audio output + * pulselist: PulseAudio audio input services discovery * pulsesrc: PulseAudio audio input * puzzle: puzzle video filter * pva: PVA demuxer diff --git a/modules/services_discovery/Modules.am b/modules/services_discovery/Modules.am index 4798d49..c3868e5 100644 --- a/modules/services_discovery/Modules.am +++ b/modules/services_discovery/Modules.am @@ -5,6 +5,16 @@ SOURCES_podcast = podcast.c SOURCES_mtp = mtp.c SOURCES_mediadirs = mediadirs.c +libpulselist_plugin_la_SOURCES = \ + ../audio_output/vlcpulse.c ../audio_output/vlcpulse.h \ + pulse.c +libpulselist_plugin_la_CFLAGS = $(AM_CFLAGS) $(PULSE_CFLAGS) +libpulselist_plugin_la_LIBADD = $(AM_LIBADD) $(PULSE_LIBS) +lubpulselist_plugin_la_DEPENDENCIES = +if HAVE_PULSE +libvlc_LTLIBRARIES += libpulselist_plugin.la +endif + libudev_plugin_la_SOURCES = udev.c libudev_plugin_la_CFLAGS = $(AM_CFLAGS) $(UDEV_CFLAGS) libudev_plugin_la_LIBADD = $(AM_LIBADD) $(UDEV_LIBS) diff --git a/modules/services_discovery/pulse.c b/modules/services_discovery/pulse.c new file mode 100644 index 0000000..02e6802 --- /dev/null +++ b/modules/services_discovery/pulse.c @@ -0,0 +1,250 @@ +/** + * @file pulse.c + * @brief List of PulseAudio sources for VLC media player + */ +/***************************************************************************** + * Copyright © 2011 Rémi Denis-Courmont + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <search.h> +#include <assert.h> + +#include <vlc_common.h> +#include <vlc_plugin.h> +#include <vlc_services_discovery.h> +#include <pulse/pulseaudio.h> +#include "../audio_output/vlcpulse.h" + +static int Open (vlc_object_t *); +static void Close (vlc_object_t *); + +VLC_SD_PROBE_HELPER("pulse", "Audio capture", SD_CAT_DEVICES); + +vlc_module_begin () + set_shortname (N_("Video capture")) + set_description (N_("Video capture (Video4Linux)")) + set_category (CAT_PLAYLIST) + set_subcategory (SUBCAT_PLAYLIST_SD) + set_capability ("services_discovery", 0) + set_callbacks (Open, Close) + add_shortcut ("pulse", "pa", "pulseaudio", "audio") + + VLC_SD_PROBE_SUBMODULE +vlc_module_end () + +struct services_discovery_sys_t +{ + void *root; + pa_context *context; + pa_threaded_mainloop *mainloop; +}; + +static void SourceCallback(pa_context *, const pa_source_info *, int, void *); +static void ContextCallback(pa_context *, pa_subscription_event_type_t, + uint32_t, void *); + +static int Open (vlc_object_t *obj) +{ + services_discovery_t *sd = (services_discovery_t *)obj; + pa_operation *op; + pa_context *ctx; + + services_discovery_sys_t *sys = malloc (sizeof (*sys)); + if (unlikely(sys == NULL)) + return VLC_ENOMEM; + + ctx = vlc_pa_connect (obj, &sys->mainloop); + if (ctx == NULL) + { + free (sys); + return VLC_EGENERIC; + } + + sd->p_sys = sys; + sys->context = ctx; + sys->root = NULL; + + /* Subscribe for source events */ + const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SOURCE; + pa_threaded_mainloop_lock (sys->mainloop); + pa_context_set_subscribe_callback (ctx, ContextCallback, sd); + op = pa_context_subscribe (ctx, mask, NULL, NULL); + if (likely(op != NULL)) + pa_operation_unref (op); + + /* Enumerate existing sources */ + op = pa_context_get_source_info_list (ctx, SourceCallback, sd); + if (likely(op != NULL)) + { + //while (pa_operation_get_state (op) == PA_OPERATION_RUNNING) + // pa_threaded_mainloop_wait (sys->mainloop); + pa_operation_unref (op); + } + pa_threaded_mainloop_unlock (sys->mainloop); + return VLC_SUCCESS; +/* +error: + pa_threaded_mainloop_unlock (sys->mainloop); + vlc_pa_disconnect (obj, ctx, sys->mainloop); + free (sys); + return VLC_EGENERIC;*/ +} + +struct device +{ + uint32_t index; + input_item_t *item; + services_discovery_t *sd; +}; + +static void DestroySource (void *data) +{ + struct device *d = data; + + if (d->sd) + services_discovery_RemoveItem (d->sd, d->item); + vlc_gc_decref (d->item); + free (d); +} + +/** + * Compares two devices (to support binary search). + */ +static int cmpsrc (const void *a, const void *b) +{ + const uint32_t *pa = a, *pb = b; + uint32_t idxa = *pa, idxb = *pb; + + return (idxa != idxb) ? ((idxa < idxb) ? -1 : +1) : 0; +} + +/** + * Adds a source. + */ +static int AddSource (services_discovery_t *sd, const pa_source_info *info) +{ + services_discovery_sys_t *sys = sd->p_sys; + + msg_Dbg (sd, "adding %s (%s)", info->name, info->description); + + char *mrl; + if (unlikely(asprintf (&mrl, "pulse://%s", info->name) == -1)) + return -1; + + input_item_t *item = input_item_NewWithType (mrl, info->description, + 0, NULL, 0, -1, + ITEM_TYPE_CARD); + free (mrl); + if (unlikely(item == NULL)) + return -1; + + struct device *d = malloc (sizeof (*d)); + if (unlikely(d == NULL)) + { + vlc_gc_decref (item); + return -1; + } + d->index = info->index; + d->item = item; + d->sd = NULL; + + struct device **dp = tsearch (d, &sys->root, cmpsrc); + if (dp == NULL) /* Out-of-memory */ + { + DestroySource (d); + return -1; + } + if (*dp != d) /* Replace existing source */ + { + DestroySource (*dp); + *dp = d; + } + + char *card; + if (info->card == PA_INVALID_INDEX + || unlikely(asprintf (&card, N_("Card %"PRIu32), info->card) == -1)) + card = NULL; + services_discovery_AddItem (sd, item, + (card != NULL) ? card : N_("Generic")); + d->sd = sd; + free (card); + return 0; +} + +static void SourceCallback(pa_context *ctx, const pa_source_info *i, int eol, + void *userdata) +{ + services_discovery_t *sd = userdata; + + if (eol) + return; + AddSource (sd, i); + (void) ctx; +} + +/** + * Removes a source (if present) by index. + */ +static void RemoveSource (services_discovery_t *sd, uint32_t idx) +{ + services_discovery_sys_t *sys = sd->p_sys; + + struct device **dp = tfind (&idx, &sys->root, cmpsrc); + if (dp == NULL) + return; + + struct device *d = *dp; + tdelete (d, &sys->root, cmpsrc); + DestroySource (d); +} + +static void ContextCallback(pa_context *ctx, pa_subscription_event_type_t type, + uint32_t idx, void *userdata) +{ + services_discovery_t *sd = userdata; + pa_operation *op; + + assert ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) + == PA_SUBSCRIPTION_EVENT_SOURCE); + switch (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) + { + case PA_SUBSCRIPTION_EVENT_NEW: + case PA_SUBSCRIPTION_EVENT_CHANGE: + op = pa_context_get_source_info_by_index(ctx, idx, SourceCallback, sd); + if (likely(op != NULL)) + pa_operation_unref(op); + break; + + case PA_SUBSCRIPTION_EVENT_REMOVE: + RemoveSource (sd, idx); + break; + } +} + +static void Close (vlc_object_t *obj) +{ + services_discovery_t *sd = (services_discovery_t *)obj; + services_discovery_sys_t *sys = sd->p_sys; + + vlc_pa_disconnect (obj, sys->context, sys->mainloop); + tdestroy (sys->root, DestroySource); + free (sys); +} diff --git a/po/POTFILES.in b/po/POTFILES.in index 3a92cad..38a0773 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -971,6 +971,7 @@ modules/services_discovery/bonjour.c modules/services_discovery/mediadirs.c modules/services_discovery/mtp.c modules/services_discovery/podcast.c +modules/services_discovery/pulse.c modules/services_discovery/sap.c modules/services_discovery/udev.c modules/services_discovery/upnp.cpp _______________________________________________ vlc-commits mailing list [email protected] http://mailman.videolan.org/listinfo/vlc-commits
